Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 4 Jan 2018 10:53:51 -0600
From:      Lewis Donzis <lew@perftech.com>
To:        Karl Denninger <karl@denninger.net>
Cc:        freebsd-net@freebsd.org
Subject:   Re: IP networking single socket, both IPv4 and V6?
Message-ID:  <64BFEA30-EF91-4AAB-9E4F-5937CCAEB92B@perftech.com>
In-Reply-To: <C18C948A-CCF6-4E55-AF34-F6EE05A042EA@perftech.com>
References:  <2b3944fc-df1a-9998-876e-ad74f8cc073d@denninger.net> <C18C948A-CCF6-4E55-AF34-F6EE05A042EA@perftech.com>

next in thread | previous in thread | raw e-mail | index | archive | help


> On Jan 4, 2018, at 10:32 AM, Lewis Donzis <lew@perftech.com> wrote:
>=20
> On Jan 4, 2018, at 10:17 AM, Karl Denninger <karl@denninger.net> =
wrote:
>>=20
>> I've written a fair bit of code that binds to both Ipv4 and v6 for
>> incoming connections, using two sockets (one for each.)
>>=20
>> Perusing around the 'net I see an implementation note written by IBM
>> that implies that on their Unix implementation you can set up an =
INET6
>> listener and it will open listeners on *both* IPv4 and v6; you code =
it
>> as an Ipv6 socket/bind/listen/accept, and if an Ipv4 connection comes =
in
>> you get a prefix'd IPv4 address back when you call getpeername().
>>=20
>> This would obviously shorten up code and remove the need to open the
>> second listener socket, but playing with this on FreeBSD it doesn't
>> appear to work -- I only get the IPv6 listener in "netstat -a -n"
>> showing up and as expected a connection to a v4 address on that port
>> fails (refused, since there's no listener.)
>>=20
>> Is this something that *should* work on FreeBSD?
>=20
> It works.  We do it all the time.  You either have to set the sysctl:
>=20
>   net.inet6.ip6.v6only=3D0
>=20
> which you can do in /etc/sysctl.conf or with the sysctl utility, or, =
in your program, use setsockopt to turn off the V6ONLY option, e.g.:
>=20
>   setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof (int)); =
// Turn off v6-only
>=20
> We use the first method, which is broken in FreeBSD 11.1 prior to =
patch level 5 or 6, I can=E2=80=99t remember which, but works in all =
others.  The second method is considered to be more portable.
>=20
> FWIW, Linux, by default, sets v6only off, so it doesn't require =
anything special.

I forgot about one other option, which we used to get around the =
regression in 11.1 until the kernel gets fixed.  Because libc functions =
are generally published with a weak reference, you can overload the =
socket() function in your own code, like this:

int socket (int domain, int type, int protocol)
{
   extern int _socket(int domain, int type, int protocol);
   int s =3D _socket(domain, type, protocol);
   if (s >=3D 0 && domain =3D=3D PF_INET6)
      setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof (int)); =
// Turn off v6-only
   return s;
   }

We put that in one of our own shared libraries that we bind all of our =
programs to, and that solves it without having to change a lot of code.=



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?64BFEA30-EF91-4AAB-9E4F-5937CCAEB92B>