Discussion:
[stunnel-users] IPv4 and IPv6
(too old to reply)
Konstantin Belousov
2016-05-30 22:42:59 UTC
Permalink
Hi.

I have a following configuration for the outgoing connection
[XXX-1]
client = yes
accept = 127.0.0.1:1564
connect = some-server:9999
local = some-other-address

Sometimes, or rather, quite regular, the connection to localhost port
1564 results in immediate connection close and logging the following:
May 30 23:06:58 tom stunnel: LOG5[4]: Service [XXX-1] accepted connection from 127.0.0.1:12848
May 30 23:06:58 tom stunnel: LOG3[4]: local_bind (ephemeral port): Invalid argument (22)

I traced the syscalls and see the following:
28196 stunnel CALL socket(PF_INET6,SOCK_STREAM,IPPROTO_IP)
28196 stunnel RET socket 10/0xa
28196 stunnel CALL fcntl(0xa,F_GETFL,0)
28196 stunnel RET fcntl 2
28196 stunnel CALL fcntl(0xa,F_SETFL,0x6<O_RDWR|O_NONBLOCK>)
28196 stunnel RET fcntl 0
28196 stunnel CALL fcntl(0xa,F_SETFD,FD_CLOEXEC)
28196 stunnel RET fcntl 0
28196 stunnel CALL bind(0xa,0x802808a6c,0x10)
28196 stunnel STRU struct sockaddr { AF_INET, 176.36.249.139:0 }
28196 stunnel RET bind -1 errno 22 Invalid argument

The socket was created with INET6 address family, but bind was done for
INET AF. Indeed, both some-server and some-other-address have both A and
AAAA records, corresponding addresses are configured and functional. OS
is FreeBSD, I was ensured that this combination (INET6 socket and INET
bind) is not correct.

It probably works sometime when first resolved addresses for names
happen to come from the same address family, but when resolvers return
different order, the situation above occurs. Disabling ipv6 support
makes the connection work reliably, which confirms my observations.

I am using stunnel 5.31.

Would be nice to have this fixed. Thanks.
Michał Trojnara
2016-05-31 06:04:24 UTC
Permalink
Post by Konstantin Belousov
I have a following configuration for the outgoing connection
[XXX-1]
client = yes
accept = 127.0.0.1:1564
connect = some-server:9999
local = some-other-address
[cut]
Post by Konstantin Belousov
The socket was created with INET6 address family, but bind was done for
INET AF.
This is pretty much expected if "some-server:9999" is an IPv6 address
and "some-other-address" is an IPv4 address. The "local" option indeed
cannot handle a mix of IPv4 and IPv6 "connect" addresses.

What do you think might be a proper solution?

Best regards,
Mike
Konstantin Belousov
2016-05-31 10:50:54 UTC
Permalink
Post by Michał Trojnara
Post by Konstantin Belousov
I have a following configuration for the outgoing connection
[XXX-1]
client = yes
accept = 127.0.0.1:1564
connect = some-server:9999
local = some-other-address
[cut]
Post by Konstantin Belousov
The socket was created with INET6 address family, but bind was done for
INET AF.
This is pretty much expected if "some-server:9999" is an IPv6 address
and "some-other-address" is an IPv4 address. The "local" option indeed
cannot handle a mix of IPv4 and IPv6 "connect" addresses.
Usually some-server is the list of addresses, one of them is IPv4, and
another is IPv6. This is the only reasonable way to name dual-stack
host.
Post by Michał Trojnara
What do you think might be a proper solution?
I would expect that the code which binds the socket for connect(2),
matched the address types before binding. A good implementation needs
to iterate over the results of getaddrinfo(3) for remote host to try to
connect to each returned address. In the same manner, when one outgoing
address is attempted to connect to, the getaddrinfo(3) list for the
local address would be iterated over, and first matched compatible
address selected for binding.

It seems that it is enough to match addrinfo pairs by
ai_family/ai_socktype/ai_protocol, but you might also need to e.g. pay
some attention to filter out IPv4 mapped to IPv6 entries.

I am not sure how much additional plumbing is required to have local
getaddrinfo(3) result in the local_bind().

Loading...