]> Cypherpunks repositories - gostls13.git/commitdiff
net: handle IP interface stack correctly on linux
authorMikio Hara <mikioh.mikioh@gmail.com>
Fri, 14 Feb 2014 16:07:51 +0000 (01:07 +0900)
committerMikio Hara <mikioh.mikioh@gmail.com>
Fri, 14 Feb 2014 16:07:51 +0000 (01:07 +0900)
A configuration like the following:

7: tun6rd: <NOARP,UP,LOWER_UP> 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: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> 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: <POINTOPOINT,NOARP,UP,LOWER_UP> 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

index 1207c0f269da08f20a813512308d8c3211c8fb98..1115d0fc40b6f366d3002d071feff133c1add70b 100644 (file)
@@ -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
 }