On Thu, Oct 27, 2022 at 1:51 PM Klaus Ebbe Grue <g...@di.ku.dk> wrote:
> Hi systemd-devel, > > Sorry to bug you with another user question. > > I have a socket activated daemon, call it mydaemon, and I have trouble > finding out who connects to it. > > > mydaemon.socket contains: > > > [Socket] > ListenStream=9999 > > When I connect using IPv4 using > > nc -4 localhost 9999 > > then mydaemon does > > sockaddr_in6 peer; > socklen_t peer_size=sizeof(peer); > accept(3,(struct sockaddr *)&peer,sizeof(peer)) > > Afterwards, peer.sin6_family is AF_INET6 and peer.sin6_addr contains some > gibberish like a00:e5ae:: > If you specify nothing for the listen address, systemd will assume the IPv6 address [::] as the default, and will create an AF_INET6 socket bound to [::]:9999. Due to Linux's default "bind both families" magic, it will actually be bound to both [::]:9999 *and* 0.0.0.0:9999, so it will accept IPv4 connections – but you'll receive them in the form of AF_INET6 sockets, so the peer address of your v4 client indeed has family AF_INET6 but contains a "v6-mapped" IPv4 address such as [::ffff:10.0.229.174] aka [::ffff:a00:e5ae]. The alternative would be to specify both ListenStream=[::]:9999 and ListenStream=0.0.0.0:9999 (as well as BindIPv6Only=ipv6-only), which would cause you to receive *two* socket FDs – one purely for IPv6 clients, the other for IPv4 – that you'd have to put into poll() or some other loop for accepting clients. You can extract the IPv4 address by detecting the [::ffff:0:0/96] prefix and stripping away the first 12 bytes. (There's also a magic option for getsockopt() listed in ipv6(7) that can convert such a "v6-mapped" socket to a "real" AF_INET socket, but it's rarely needed.) > > If I connect more than once, the gibberish changes from connection to > connection. > I have a feeling it "changes" because you're trying to give the whole struct sockaddr to inet_pton() instead of giving just the .sin6_addr field, so your program is trying to interpret the *port number* (i.e. the .sin6_port which precedes .sin_addr) as part of the address... But please show your entire code, otherwise this is all just guessing. Here's a working example that I've just tested with `systemd-socket-activate --listen=9999`: https://gist.github.com/grawity/63369273742f23b596d764cb6d45feb7 > > If mydaemon creates the listening socket, I can easily get the peer > address. > > I suspect that when systemd creates the listening socket then > accept(3,...) returns a socket which is connected to a local socket created > by systemd. > > QUESTION: Is that suspicion correct? > No, it isn't. > -- Mantas Mikulėnas