inetaf/netaddr

Is<property>() methods disagree with net.IP for 4in6 addresses

moreati opened this issue · 5 comments

For IPv4 addresses mapped to IPv6 (e.g. ::ffff:127.0.0.1) netaddr.IP methods (e.g. IsLoopback()) return false, but net.IP returns true (tested with go 1.16.4).

Given the goal of compatibility with net.IP this should probably be documented or fixed within this module. My presumption is fix, but I'm programmer, not a network expert.

This is one category found by #182.

https://play.golang.org/p/z2KVy-FsKmD

go1.16.4
                           netaddr.IP     net.IP      Discrepency
String                     ::ffff:e000:0  224.0.0.0   
IsInterfaceLocalMulticast  false          false       
IsLinkLocalMulticast       false          true        true
IsLinkLocalUnicast         false          false       
IsLoopback                 false          false       
IsMulticast                false          true        true
                           netaddr.IP     net.IP      Discrepency
String                     ::ffff:e00f:0  224.15.0.0  
IsInterfaceLocalMulticast  false          false       
IsLinkLocalMulticast       false          false       
IsLinkLocalUnicast         false          false       
IsLoopback                 false          false       
IsMulticast                false          true        true
                           netaddr.IP     net.IP      Discrepency
String                     ::ffff:7f00:1  127.0.0.1   
IsInterfaceLocalMulticast  false          false       
IsLinkLocalMulticast       false          false       
IsLinkLocalUnicast         false          false       
IsLoopback                 false          true        true
IsMulticast                false          false       

Python 3.9.5 ipaddress (for the properties it has in common) agrees with netaddr

Code
import ipaddress
import platform

print(f"Python {platform.python_version()}")

addresses = [
    "::ffff:e000:0",
    "::ffff:e00f:0",
    "::ffff:7f00:1",
]

attributes = [
    "is_multicast",
    "is_loopback",
]

for s in addresses:
    ip = ipaddress.ip_address(s)
    print(f"\t\t{ip}")
    for attr in attributes:
        result = getattr(ip, attr)
        print(f"{attr}\t{result}")
± python3.9 issue183.py 
Python 3.9.5
		::ffff:e000:0
is_multicast	False
is_loopback	False
		::ffff:e00f:0
is_multicast	False
is_loopback	False
		::ffff:7f00:1
is_multicast	False
is_loopback	False

More background research

Platform Callable/property Result Discussions, bugs/PRs
Python 3.9 ipaddress.ip_address.is_loopback false
Rust 1.52.1 std::net::IpAddr: is_loopback() false rust-lang/rust#69772, rust-lang/rust#85655
.NET 4,7,2 System.Net.IPAddress.IsLoopback() false
.NET Rosalyn 3.8 System.Net..IPAddress.IsLoopback() false
.NET 5.0 System.Net..IPAddress.IsLoopback() true dotnet/runtime#28740

Last updated: 2021-06-10

TODO

@moreati, thanks for the info!

I think we want to keep all the IsFoo methods not unwrapping. The 4-in-6 handling being too aggressive in Go std's net package was one of the problems we wanted to fix with netaddr. (see the third bullet under Motivation at https://pkg.go.dev/inet.af/netaddr)

But, yeah, we can document it.

@danderson, @mdlayher, @josharian, sound good?

Agreed. +1 to documenting but I still think 4-in-6 mapping is too niche for the prominence it has in the current stdlib.

Might be useful for this issue: IsPrivate from the latest Go changelog: https://tip.golang.org/doc/go1.17
scroll down to the net package changelog.