5

Switched providers the other day, they only assign DSlite-connections. I'm fine, I thought. Thing is - I want to access some of my stuff from outside of my network, which should be of much less a hassle now I got native IPv6.

My new main problem was that I can't assume to have that everywhere I roam, so most of the time I'll try to access from an IPv4-only entry point. Found $ socat was my friend, as I can access one box with true dualstack connection - so accessing my IPv6 from an IPv4-only connection is as easy as running $ socat UDP4-LISTEN:sourceport,fork,su=nobody UDP6:my-ipv6-hostname-behind.cgn:targetport on the dualstacked machine and afterwards connecting to my-dualstack-hostna.me:sourceport from outside.

Now, $ netstat -tulpen | grep sourceport on the dualstacked machine only reveals an UDP4-listener - so my current problem is:

  • Access from IPv6-only connection requires me to connect to my-ipv6-hostname-behind.cgn:targetport
  • Access from IPv4-only connection requires me to connect to my-dualstack-hostna.me:sourceport
  • Access from DS(-lite) connection enables me to use both, but preferably use the direct IPv6-route

So it would be great to be able to use my-dualstack-hostna.me:sourceport for both IPv4 and IPv6 connections and not to root-update the configuration every time I move my laptop or phone! How to make socat listen on both? There has to be a way! $ netstat -tulpen | grep ":22" on the DS-machine shows these:

tcp        0      0 0.0.0.0:22 […]
tcp6       0      0 :::22      […]
LDericher
  • 161

2 Answers2

5

You can configure socat to listen on both IPv4 and IPv6 by, counter-intuitively, always use the "TCP6-LISTENER" or "UDP6-LISTENER" address forms. This causes socat to listen in a dual-stack manner. This is because by default Linux (and I suspect the BSDs) also accept IPv4 when the socket has been bound for ::.

$ socat -v tcp6-listen:8000,fork,max-children=500,reuseaddr exec:"$(which cat)"

We can see socat now support dual stack.

$ ss -ntpl | rg socat
LISTEN 0      5                  *:8000             *:*    users:(("socat",pid=1568208,fd=5))

$ echo "test" | nc 127.0.0.1 8000 test ^C

$ echo "test" | nc ::1 8000 test ^C


If you're using socat in an environment where you actually want just IPv6, you can pass the ipv6only option. This sets the IPV6_V6ONLY socket option, which is described in ipv6(7):

IPV6_V6ONLY (since Linux 2.4.21 and 2.6)  
        If this flag is set to true (nonzero), then the  socket  is  re‐  
        stricted  to  sending  and receiving IPv6 packets only.  In this  
        case, an IPv4 and an IPv6 application can bind to a single  port  
        at the same time.
    If this flag is set to false (zero), then the socket can be used
    to send and receive packets to and from an IPv6  address  or  an
    IPv4-mapped IPv6 address.

$ socat -v tcp6-listen:8000,fork,max-children=500,reuseaddr,ipv6only exec:"$(which cat)

We can then observable this change:

$ ss -ntpl | rg socat
LISTEN 0      5               [::]:8000          [::]:*    users:(("socat",pid=1573995,fd=5))

$ echo "test" | nc 127.0.0.1 8000

$ echo "test" | nc ::1 8000 test ^C

4

I had the same issue - you can solve it by running two instances of socat, one listening on ipv4 and one listening on the same ipv6 port by binding each to its respective address, like this:

socat UDP4-LISTEN:sourceport,bind=<ipv4-addr>,fork,su=nobody UDP6:my-ipv6-hostname-behind.cgn:targetport

socat UDP6-LISTEN:sourceport,bind=<ipv6-addr>,fork,su=nobody UDP6:my-ipv6-hostname-behind.cgn:targetport
nosyjoe
  • 141