From 8c0a52f28d16569361b18190cf7ff280aa5301bf Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Sat, 15 Feb 2014 01:07:51 +0900 Subject: [PATCH] net: handle IP interface stack correctly on linux A configuration like the following: 7: tun6rd: mtu 1280 link/sit 10.11.12.13 brd 0.0.0.0 inet 1.2.3.4/24 scope global tun6rd inet6 2014:1001:a0b:c0d::1/32 scope global inet6 ::10.11.12.13/128 scope global 9: ppp0: mtu 1496 link/ppp inet 192.168.101.234 peer 192.168.102.234/32 scope global ppp0 inet 10.20.30.40/24 scope global ppp0 inet6 2014:1002::1/64 scope global 11: tun0@NONE: mtu 1480 link/ipip 192.168.202.34 peer 192.168.202.69 inet 192.168.10.1/24 scope global tunnel0 inet6 2014:1003::1/64 scope global will be handled like below. "tun6rd": flags "up", ifindex 7, mtu 1280 hardware address "" interface address "1.2.3.4/24" interface address "2014:1001:a0b:c0d::1/32" interface address "::a0b:c0d/128" "ppp0": flags "up|pointtopoint|multicast", ifindex 9, mtu 1496 hardware address "" interface address "192.168.101.234/32" interface address "10.20.30.40/24" interface address "2014:1002::1/64" "tun0": flags "up|pointtopoint", ifindex 11, mtu 1480 hardware address "" interface address "192.168.10.1/24" interface address "2014:1003::1/64" Fixes #6433. Update #4839 LGTM=iant R=iant CC=golang-codereviews https://golang.org/cl/57700043 --- src/pkg/net/interface_linux.go | 58 ++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/src/pkg/net/interface_linux.go b/src/pkg/net/interface_linux.go index 1207c0f269..1115d0fc40 100644 --- a/src/pkg/net/interface_linux.go +++ b/src/pkg/net/interface_linux.go @@ -45,15 +45,41 @@ loop: return ift, nil } +const ( + // See linux/if_arp.h. + // Note that Linux doesn't support IPv4 over IPv6 tunneling. + sysARPHardwareIPv4IPv4 = 768 // IPv4 over IPv4 tunneling + sysARPHardwareIPv6IPv6 = 769 // IPv6 over IPv6 tunneling + sysARPHardwareIPv6IPv4 = 776 // IPv6 over IPv4 tunneling + sysARPHardwareGREIPv4 = 778 // any over GRE over IPv4 tunneling + sysARPHardwareGREIPv6 = 823 // any over GRE over IPv6 tunneling +) + func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) *Interface { ifi := &Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)} for _, a := range attrs { switch a.Attr.Type { case syscall.IFLA_ADDRESS: + // We never return any /32 or /128 IP address + // prefix on any IP tunnel interface as the + // hardware address. + switch len(a.Value) { + case IPv4len: + switch ifim.Type { + case sysARPHardwareIPv4IPv4, sysARPHardwareGREIPv4, sysARPHardwareIPv6IPv4: + continue + } + case IPv6len: + switch ifim.Type { + case sysARPHardwareIPv6IPv6, sysARPHardwareGREIPv6: + continue + } + } var nonzero bool for _, b := range a.Value { if b != 0 { nonzero = true + break } } if nonzero { @@ -147,19 +173,31 @@ loop: } func newAddr(ifi *Interface, ifam *syscall.IfAddrmsg, attrs []syscall.NetlinkRouteAttr) Addr { - for _, a := range attrs { - if ifi.Flags&FlagPointToPoint != 0 && a.Attr.Type == syscall.IFA_LOCAL || - ifi.Flags&FlagPointToPoint == 0 && a.Attr.Type == syscall.IFA_ADDRESS { - switch ifam.Family { - case syscall.AF_INET: - return &IPNet{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3]), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv4len)} - case syscall.AF_INET6: - ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv6len)} - copy(ifa.IP, a.Value[:]) - return ifa + var ipPointToPoint bool + // Seems like we need to make sure whether the IP interface + // stack consists of IP point-to-point numbered or unnumbered + // addressing over point-to-point link encapsulation. + if ifi.Flags&FlagPointToPoint != 0 { + for _, a := range attrs { + if a.Attr.Type == syscall.IFA_LOCAL { + ipPointToPoint = true + break } } } + for _, a := range attrs { + if ipPointToPoint && a.Attr.Type == syscall.IFA_ADDRESS || !ipPointToPoint && a.Attr.Type == syscall.IFA_LOCAL { + continue + } + switch ifam.Family { + case syscall.AF_INET: + return &IPNet{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3]), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv4len)} + case syscall.AF_INET6: + ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv6len)} + copy(ifa.IP, a.Value[:]) + return ifa + } + } return nil } -- 2.48.1