Skip Menu |

This queue is for tickets about the IO-Socket-IP CPAN distribution.

Report information
The Basics
Id: 89608
Status: open
Priority: 0/
Queue: IO-Socket-IP

People
Owner: Nobody in particular
Requestors: Mark.Martinec [...] ijs.si
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 0.24
Fixed in: (no value)



Subject: Handle scoped IP addresses
RFC 4291 (IP Version 6 Addressing Architecture) defines a scope an IP address can have, e.g. a link-local scope. Multiple interfaces can have the same link-local address assigned, and a field sin6_scope_id in the sockaddr_in6 structure of a socket associates it with a particular interface. RFC 4007 defines a textual representation of a scope (zone_id) in an address specification. Basically, textual representation of an IP address can be followed by a '%' and an integer (interface index, defaults to 0), of by an interface name, in which case a if_nametoindex() may be used to translate an interface name to its index. Currently IP::Socket::IP does not allow specifying a scope when creating a socket. This means that one cannot use link-local addresses - which are invalid without also specifying an interface to which they are associated. To illustrate the point, here are equivalent requests for socket creation & listen, using a program netcat (nc), and IP::Socket::IP : The first example is fine, the IO::Socket::IP works correctly, missing scope results in "Can't assign requested address": $ nc -l fe80::1 4567 nc: Can't assign requested address $ nc -l fe80::21c:c0ff:feb1:8c91 4567 nc: Can't assign requested address $ perl -e 'use IO::Socket::IP; $s=IO::Socket::IP->new(LocalHost=>"[fe80::1]:4567", Listen=>1) or die $@' Can't assign requested address at -e line 1. The next example illustrates the correct behavior by netcat, but IO::Socket::IP does not recognize the zone-id in the syntax of an IP address: $ nc -l fe80::1%lo0 4567 ^C (binds correctly and listens) $ nc -l fe80::21c:c0ff:feb1:8c91%em0 4567 ^C (binds correctly and listens) $ perl -e 'use IO::Socket::IP; $s=IO::Socket::IP->new(LocalHost=>"[fe80::1%lo0]:4567", Listen=>1) or die $@' hostname nor servname provided, or not known at -e line 1. $ perl -e 'use IO::Socket::IP; $s=IO::Socket::IP->new(LocalHost=>"[fe80::21c:c0ff:feb1:8c91%em0]:4567", Listen=>1) or die $@' hostname nor servname provided, or not known at -e line 1. Please enhance the IO::Socket::IP module to recognize a zone_id (i.e. scope, either numeric i/f id, or its name) in an IP address, and to pass this id to socket structure when creating a socket. This would allow applications to be able to deal with link-local addresses and connections. Btw, the PHP folks apparently finally did this right just recently ( see https://bugs.php.net/bug.php?id=65808 ) Further reading: http://codeidol.com/community/nix/interface-name-and-index-functions/4615/ $ man if_nametoindex NAME if_nametoindex, if_indextoname, if_nameindex, if_freenameindex -- provide mappings between interface names and indexes unsigned int if_nametoindex(const char *ifname); DESCRIPTION The if_nametoindex() function maps the interface name specified in ifname to its corresponding index. If the specified interface does not exist, it returns 0. RFC 4007: IPv6 Scoped Address Architecture, sect 11: textual representation RFC 6874 A <zone_id> SHOULD contain only ASCII characters classified as "unreserved" for use in URIs [RFC 3986] RFC 3986: unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" http://tools.ietf.org/html/rfc4291 http://tools.ietf.org/html/rfc3493 http://tools.ietf.org/html/rfc4007
From: Mark.Martinec [...] ijs.si
Actually ... it seems the problem is only in inconsistent parsing, and the scope is otherwise handled correctly when a port number is specified through LocalPort option. The following are handled correctly: LocalHost=>"fe80::21c:c0ff:feb1:8c91%em0", LocalPort=>4567 LocalHost=>"2001:1470:ff80:88:21c:c0ff:feb1:8c91", LocalPort=>4567 LocalHost=>"[2001:1470:ff80:88:21c:c0ff:feb1:8c91]:4567" but not this: LocalHost=>"[fe80::21c:c0ff:feb1:8c91%em0]:4567" which yields: "hostname nor servname provided"
From: Mark.Martinec [...] ijs.si
I just stumbled across this issue again (this time with a peer address), only to remember that we have a ticket already open. The following experiment demonstrates the inconsistency in parsing of PeerAddr (PeerHost), which may include a port number, but not when the address is scoped - in which case a separate PeerPort attribute is required: $ perl -MIO::Socket::IP -le '$s=IO::Socket::IP->new(PeerAddr=>"::1", PeerPort=>25) or die $!' (ok) $ perl -MIO::Socket::IP -le '$s=IO::Socket::IP->new(PeerAddr=>"[::1]", PeerPort=>25) or die $!' (ok) $ perl -MIO::Socket::IP -le '$s=IO::Socket::IP->new(PeerAddr=>"[::1]:25") or die $!' (ok) $ perl -MIO::Socket::IP -le '$s=IO::Socket::IP->new(PeerAddr=>"fe80::1%lo0", PeerPort=>25) or die $!' (ok) $ perl -MIO::Socket::IP -le '$s=IO::Socket::IP->new(PeerAddr=>"[fe80::1%lo0]", PeerPort=>25) or die $!' Invalid argument at -e line 1. $ perl -MIO::Socket::IP -le '$s=IO::Socket::IP->new(PeerAddr=>"[fe80::1%lo0]:25") or die $!' Expected 'PeerService' at -e line 1.
Ideally, this would be done by the underlying getaddrinfo() provided by the platform. I'm not /quite/ sure I want to get into parsing and interpreting that at the IO::Socket::IP level, because it suddenly adds lots of weird special-case logic at the wrong layer. -- Paul Evans