Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

After upgrading from Debian Lenny to Squeeze, I got my application exiting with this error:

Bad arg length for Socket::inet_ntoa, length is 16, should be 4 at /app/lib/HTTP/Daemon.pm line 48

The offending line is from HTTP/Daemon.pm is:

$url .= gethostbyaddr($addr, AF_INET) || inet_ntoa($addr);

$addr is returned by $self->sockaddr, and since HTTP::Daemon does not override this method, sockaddr() comes from its parent, IO::Socket::INET. From the number of bytes I'm guessing this is a IPv6/IPv4 thingy? If I print unpack("h*", $addr), it's just a bunch of \x00 though...

Anyway, I'm placing a workaround like this before line 48:

        if (length($addr) == 16) { $addr = substr($addr, 12) }

My app now runs as usual, but I'm sure this is not proper. Any insights on why this is happening and how to properly solve this? Thanks.

  • Comment on IO::Socket::INET's sockaddr() returns 16 byte instead of 4, Socket::inet_ntoa() complains
  • Select or Download Code

Replies are listed 'Best First'.
Re: IO::Socket::INET's sockaddr() returns 16 byte instead of 4, Socket::inet_ntoa() complains
by ikegami (Patriarch) on Jan 20, 2012 at 22:42 UTC

    The socket uses IPv6. I'm guessing you're using localhost and that Squeeze defines localhost as ::1. The dumb thing is that sockaddr doesn't tell you if what kind of address it's returning. The module, was written with only IPv4 in mind.

    Here's how you can address this in a portable manner:

    use Socket qw( sockaddr_family sockaddr_in sockaddr_in6 inet_ntop AF_I +NET ); my $sockaddr = getsockaddr($sock); # Or: $sock->sockname() my $fam = sockaddr_family($sockaddr); my $addr_n = $fam == AF_INET ? (sockaddr_in($sockaddr))[1] : (sockaddr_in6($sockaddr))[1]; my $addr_a = inet_ntop($fam, $addr_n); say $addr_a;

      Hm, that's very verbose.

      What I'm not getting is: IO::Socket::INET's doc says, "IO::Socket::INET provides an object interface to creating and using sockets in the AF_INET domain" but why is it still receiving AF_INET6 stuff?

      There's also IO::Socket::INET6 maintained by Shlomi Fish.

      So where should be the appropriate fix/patch placed? In HTTP::Daemon (e.g. creating a separate HTTP::Daemon6)? In IO::Socket::INET (always converts things to IPv4, so sockaddr() never returns 16 bytes)? In still-lower library? This IPv4/IPv6 dichotomy is quite confusing to me.

        You probably have installed package: ii libio-socket-inet6-perl 2.65-1.1 Object interface for AF_INET6 domain sockets uninstall "libio-socket-inet6-perl" package from system and it will work ! :-D
Re: IO::Socket::INET's sockaddr() returns 16 byte instead of 4, Socket::inet_ntoa() complains
by VinsWorldcom (Prior) on Jan 20, 2012 at 21:12 UTC

    Depending on the version of Perl you're using, I believe Socket6 isn't required for IPv6 lookups, Socket itself handles both IPv4 and IPv6. You're correct in the comment that this is (most likely) an IPv6/IPv4 thing as IPv6 addresses are 16 bytes and I've seen this before myself.

    In most operating systems, IPv6 is preferred over IPv4, so if you don't want that behavior, turn off IPv6 on the interface(s) that $addr returns values for.

    Alternatively, use calls that can deal with IPv4/IPv6 address families:

    gethostbyname -> getaddrinfo gethostbyaddr -> getnameinfo inet_aton -> inet_pton inet_ntoa -> inet_ntop

    Your grabbing a substring is certainly *not* a way to get around this as you'll just be pulling the last 4 bytes of an IPv6 address - this is *not* equivalent to the IPv4 address (in most all cases unless specifically configured or using IPv4 compatible addressing).