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