Project

General

Profile

Feature #10911

IPAddr.new should ignore zone identifiers

Added by postmodern (Hal Brodigan) almost 5 years ago. Updated about 1 month ago.

Status:
Assigned
Priority:
Normal
Target version:
-
[ruby-core:68331]

Description

Link local IPv6 addresses may have a zone identifier suffix:

fe80::1%lo0

IPAddr.new currently does not ignore the zone identifier and raises IPAddr::InvalidAddressError.


Files

ipaddr-ipv6-zone-id-10911.patch (5.17 KB) ipaddr-ipv6-zone-id-10911.patch jeremyevans0 (Jeremy Evans), 10/31/2019 04:16 PM

History

Updated by hsbt (Hiroshi SHIBATA) 9 months ago

  • Assignee set to knu (Akinori MUSHA)
  • Status changed from Open to Assigned

Updated by jeremyevans0 (Jeremy Evans) about 1 month ago

I don't think this is a bug. The decision to not support zone identifiers seems deliberate as there are tests that using a zone identifier raises an exception:

assert_raise(IPAddr::InvalidAddressError) { IPAddr.new("fe80::1%fxp0") }

Still, I think this would be a useful feature to add. We should not ignore the zone identifier, as it a property of the address. Attached is a patch that implements support for it, so that to_s and inspect will show the zone identifier. It doesn't consider the zone identifier when determining equality, just as the mask_addr is not currently considered for that. That may be a bug (#11531), but at least it is consistent.

Updated by Dan0042 (Daniel DeLorme) about 1 month ago

Looks like this testcase was in the original IPAddr commit from 2002:

commit 9ec0a96ad4235f2054976eab6c04efbe62b3c703
Author: knu <knu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date:   Mon Dec 23 17:07:49 2002 +0000

    * MANIFEST, lib/README, lib/ipaddr.rb: Add ipaddr.rb from rough.

Maybe knu (Akinori MUSHA) remembers why? I'm sure there must have been a reason.

But I think this could break the contract in other places that accept a IPv6 address but not a zone identifier. ex:

Socket.getaddrinfo("fe80::1%fxp0", nil) #=> SocketError (getaddrinfo: Name or service not known)
Socket.getaddrinfo("fe80::1", nil)      #=> [["AF_INET6", 0, "fe80::1", "fe80::1", 10, 1, 6], ["AF_INET6", 0, "fe80::1", "fe80::1", 10, 2, 17], ["AF_INET6", 0, "fe80::1", "fe80::1", 10, 3, 0]]

TCPSocket.new("fe80::1%fxp0", 42) #=> SocketError (getaddrinfo: Name or service not known)
TCPSocket.new("fe80::1", 42)      #=> Errno::EINVAL (Invalid argument - connect(2) for "fe80::1" port 42)

So "fe80::1%fxp0" is not even recognized as an IP address. This could result in unpleasantness in cases like this:

str = "fe80::1%fxp0"
ip = IPAddr.new(str) rescue nil   #validate IP address... ok!
TCPSocket.new(ip.to_s, 42) if ip  #and connect... fail!?

Updated by jeremyevans0 (Jeremy Evans) about 1 month ago

Dan0042 (Daniel DeLorme) wrote:

So "fe80::1%fxp0" is not even recognized as an IP address. This could result in unpleasantness in cases like this:

str = "fe80::1%fxp0"
ip = IPAddr.new(str) rescue nil   #validate IP address
TCPSocket.new(ip.to_s, 42) if ip  #and connect

Good point. We would probably want to fix socket to support this before adding support to ipaddr. I think it is reasonable for socket to support it, as tools dealing with IPv6 should handle zone identifiers. I tried ping6 and traceroute6:

$ ping6 fe80::1%lo0
PING fe80::1%lo0 (fe80::1%lo0): 56 data bytes
64 bytes from fe80::1%lo0: icmp_seq=0 hlim=64 time=0.630 ms
$ traceroute6 fe80::1
traceroute6 to fe80::1%lo (fe80::1%lo0), 64 hops max, 60 byte packets
 1  fe80::1%lo0 (fe80::1%lo0)  0.162 ms  0.098 ms  0.091 ms

Ignoring the zone identifier is not valid:

$ ping6 fe80::1
PING fe80::1 (fe80::1): 56 data bytes
ping6: sendmsg: Network is unreachable
$ traceroute6 fe80::1
traceroute6 to fe80::1 (fe80::1), 64 hops max, 60 byte packets
traceroute6: sendto: Network is unreachable

Also available in: Atom PDF