#ipv6 #ipv4 #proxy #xinetd

IPv6 to IPv4 proxy with xinetd

If you have to deal with legacy applications that do not have native IPv6 support and you need to access via IPv6 there is a way to (ab-)use xinetd to listen for the incoming IPv6 traffic and forward it to the IPv4 port.

In this example we are going to use the Web interface of Transmision, which currently can’t be configured to be accessible via IPv6, but other things, like the Spice proxy of Proxmox suffer the same issue.

The tutorial is for Debian, but other distros should work as well. We further assume, that transmission is already installed and the webinterface works via IPv4. It should look something like this:

# netstat -tlpn | grep 9091
tcp   0   0 0.0.0.0:9091     0.0.0.0:*        LISTEN   1492/transmission-d

First we need to install xinetd if it’s not already installed:

# apt install xinetd

Next we need to create configuration file /etc/xinet.d/transmission6 for our service:

service transmission6
{
    flags           = IPv6
    disable         = no
    type            = UNLISTED
    socket_type     = stream
    protocol        = tcp
    user            = nobody
    wait            = no
    redirect        = 127.0.0.1 9091
    port            = 9092
}

And then reload xinetd:

# systemctl reload xinetd

The result will be:

# netstat -tlpn | grep 9092
tcp6  0   0 :::9092          :::*             LISTEN   7663/xinetd

You will notice, that for IPv6 we are using a different port number. That is because otherwise xinetd will complain with something like this:

xinetd: bind failed (Address already in use (errno = 98)). service = transmission6
xinetd: Service transmission6 failed to start and is deactivated.

This is because xinetd sees that something is already listening on the (IPv4) port 9091. The flags = IPv6 doesn’t seem to have much of an effect. Adding:

bind            = ::

to the service definition (the equivalent of 0.0.0.0 in IPv4) does not work either.

If you absolutely need to use the same port for IPv4 and IPv6 its necessary to specify the exact IPv6 address xinetd should bind the service to like this:

    bind            = 2001:DB8:DEAD::BEEF
    ...
    port            = 9091

If your IPv6 address additionally changes over time (changing network prefix etc.) you have to regulary update the service definition and reload xinetd:

#!/bin/sh

address=$(ip -6 addr list scope global dev eth0 | grep -v " fd" | sed -n 's/.*inet6 \([0-9a-f:]\+\).*/\1/p' | head -n 1)
sed "s/%BIND%/$address/" $HOME/transmission6 > /etc/xinetd.d/transmission6
systemctl reload xinetd

The $HOME/transmission6 file in that case is your template for the service definition, in which %BIND% will be replaced with you current IPv6 address.