]> Cypherpunks repositories - gostls13.git/commitdiff
net: joined group addresses for a specific interface for darwin, freebsd, linux
authorMikio Hara <mikioh.mikioh@gmail.com>
Thu, 4 Aug 2011 04:22:52 +0000 (00:22 -0400)
committerRuss Cox <rsc@golang.org>
Thu, 4 Aug 2011 04:22:52 +0000 (00:22 -0400)
This CL enables to list the multicast, joined group addresses
for a specific interface by using Interface.MulticastAddrs
method.

R=rsc
CC=golang-dev
https://golang.org/cl/4808062

src/pkg/net/Makefile
src/pkg/net/interface.go
src/pkg/net/interface_bsd.go
src/pkg/net/interface_darwin.go [new file with mode: 0644]
src/pkg/net/interface_freebsd.go [new file with mode: 0644]
src/pkg/net/interface_linux.go
src/pkg/net/interface_stub.go
src/pkg/net/interface_test.go
src/pkg/net/interface_windows.go

index 536fe369d10b90d4a4298687ae1f20697b36e540..d17f52ce00321588737afd32b203451945e36a46 100644 (file)
@@ -29,6 +29,7 @@ GOFILES_freebsd=\
        fd.go\
        file.go\
        interface_bsd.go\
+       interface_freebsd.go\
        lookup_unix.go\
        newpollserver.go\
        port.go\
@@ -45,6 +46,7 @@ GOFILES_darwin=\
        fd.go\
        file.go\
        interface_bsd.go\
+       interface_darwin.go\
        lookup_unix.go\
        newpollserver.go\
        port.go\
index f6de36f645825bb6cea3c3e0a6915edd8b44b8b5..8a14cb2320299c04eef2f6c6b21a016a017219ac 100644 (file)
@@ -79,6 +79,15 @@ func (ifi *Interface) Addrs() ([]Addr, os.Error) {
        return interfaceAddrTable(ifi.Index)
 }
 
+// MulticastAddrs returns multicast, joined group addresses for
+// a specific interface.
+func (ifi *Interface) MulticastAddrs() ([]Addr, os.Error) {
+       if ifi == nil {
+               return nil, os.NewError("net: invalid interface")
+       }
+       return interfaceMulticastAddrTable(ifi.Index)
+}
+
 // Interfaces returns a list of the systems's network interfaces.
 func Interfaces() ([]Interface, os.Error) {
        return interfaceTable(0)
index a4c3e71feb6702ca185ce03063a7625526525042..130820d4a49d994fb38ddd8b8614f964eeda4980 100644 (file)
@@ -148,25 +148,55 @@ func newAddr(m *syscall.InterfaceAddrMessage) ([]Addr, os.Error) {
        }
 
        for _, s := range sas {
-               var ifa IPAddr
+
                switch v := s.(type) {
                case *syscall.SockaddrInet4:
-                       ifa.IP = IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])
+                       ifa := &IPAddr{IP: IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])}
+                       ifat = append(ifat, ifa.toAddr())
                case *syscall.SockaddrInet6:
-                       ifa.IP = make(IP, IPv6len)
+                       ifa := &IPAddr{IP: make(IP, IPv6len)}
                        copy(ifa.IP, v.Addr[:])
                        // NOTE: KAME based IPv6 protcol stack usually embeds
                        // the interface index in the interface-local or link-
                        // local address as the kernel-internal form.
-                       if ifa.IP.IsLinkLocalUnicast() ||
-                               ifa.IP.IsInterfaceLocalMulticast() ||
-                               ifa.IP.IsLinkLocalMulticast() {
+                       if ifa.IP.IsLinkLocalUnicast() {
                                // remove embedded scope zone ID
                                ifa.IP[2], ifa.IP[3] = 0, 0
                        }
+                       ifat = append(ifat, ifa.toAddr())
                }
-               ifat = append(ifat, ifa.toAddr())
        }
 
        return ifat, nil
 }
+
+func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, os.Error) {
+       var ifmat []Addr
+
+       sas, e := syscall.ParseRoutingSockaddr(m)
+       if e != 0 {
+               return nil, os.NewSyscallError("route sockaddr", e)
+       }
+
+       for _, s := range sas {
+               switch v := s.(type) {
+               case *syscall.SockaddrInet4:
+                       ifma := &IPAddr{IP: IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])}
+                       ifmat = append(ifmat, ifma.toAddr())
+               case *syscall.SockaddrInet6:
+                       ifma := &IPAddr{IP: make(IP, IPv6len)}
+                       copy(ifma.IP, v.Addr[:])
+                       // NOTE: KAME based IPv6 protcol stack usually embeds
+                       // the interface index in the interface-local or link-
+                       // local address as the kernel-internal form.
+                       if ifma.IP.IsInterfaceLocalMulticast() ||
+                               ifma.IP.IsLinkLocalMulticast() {
+                               // remove embedded scope zone ID
+                               ifma.IP[2], ifma.IP[3] = 0, 0
+                       }
+                       ifmat = append(ifmat, ifma.toAddr())
+               }
+       }
+
+       return ifmat, nil
+}
diff --git a/src/pkg/net/interface_darwin.go b/src/pkg/net/interface_darwin.go
new file mode 100644 (file)
index 0000000..6fbcd37
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification for Darwin
+
+package net
+
+import (
+       "os"
+       "syscall"
+)
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces.  Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+       var (
+               tab   []byte
+               e     int
+               msgs  []syscall.RoutingMessage
+               ifmat []Addr
+       )
+
+       tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifindex)
+       if e != 0 {
+               return nil, os.NewSyscallError("route rib", e)
+       }
+
+       msgs, e = syscall.ParseRoutingMessage(tab)
+       if e != 0 {
+               return nil, os.NewSyscallError("route message", e)
+       }
+
+       for _, m := range msgs {
+               switch v := m.(type) {
+               case *syscall.InterfaceMulticastAddrMessage:
+                       if ifindex == 0 || ifindex == int(v.Header.Index) {
+                               ifma, err := newMulticastAddr(v)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               ifmat = append(ifmat, ifma...)
+                       }
+               }
+       }
+
+       return ifmat, nil
+}
diff --git a/src/pkg/net/interface_freebsd.go b/src/pkg/net/interface_freebsd.go
new file mode 100644 (file)
index 0000000..e0ff6ca
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification for FreeBSD
+
+package net
+
+import (
+       "os"
+       "syscall"
+)
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces.  Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+       var (
+               tab   []byte
+               e     int
+               msgs  []syscall.RoutingMessage
+               ifmat []Addr
+       )
+
+       tab, e = syscall.RouteRIB(syscall.NET_RT_IFMALIST, ifindex)
+       if e != 0 {
+               return nil, os.NewSyscallError("route rib", e)
+       }
+
+       msgs, e = syscall.ParseRoutingMessage(tab)
+       if e != 0 {
+               return nil, os.NewSyscallError("route message", e)
+       }
+
+       for _, m := range msgs {
+               switch v := m.(type) {
+               case *syscall.InterfaceMulticastAddrMessage:
+                       if ifindex == 0 || ifindex == int(v.Header.Index) {
+                               ifma, err := newMulticastAddr(v)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               ifmat = append(ifmat, ifma...)
+                       }
+               }
+       }
+
+       return ifmat, nil
+}
index e869cd63049080fc4a99cc67828159cf16ac29ee..5af531dee6584378447ff0e2e43ccd6a357d8b1b 100644 (file)
@@ -7,6 +7,7 @@
 package net
 
 import (
+       "fmt"
        "os"
        "syscall"
        "unsafe"
@@ -102,13 +103,13 @@ func linkFlags(rawFlags uint32) Flags {
 // for a specific interface.
 func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
        var (
+               tab   []byte
+               e     int
+               err   os.Error
                ifat4 []Addr
                ifat6 []Addr
-               tab   []byte
                msgs4 []syscall.NetlinkMessage
                msgs6 []syscall.NetlinkMessage
-               e     int
-               err   os.Error
        )
 
        tab, e = syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_INET)
@@ -169,17 +170,102 @@ func newAddr(attrs []syscall.NetlinkRouteAttr, family int) []Addr {
        for _, a := range attrs {
                switch a.Attr.Type {
                case syscall.IFA_ADDRESS:
-                       ifa := IPAddr{}
                        switch family {
                        case syscall.AF_INET:
-                               ifa.IP = IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])
+                               ifa := &IPAddr{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])}
+                               ifat = append(ifat, ifa.toAddr())
                        case syscall.AF_INET6:
-                               ifa.IP = make(IP, IPv6len)
+                               ifa := &IPAddr{IP: make(IP, IPv6len)}
                                copy(ifa.IP, a.Value[:])
+                               ifat = append(ifat, ifa.toAddr())
                        }
-                       ifat = append(ifat, ifa.toAddr())
                }
        }
 
        return ifat
 }
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces.  Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+       var (
+               ifi    *Interface
+               err    os.Error
+               ifmat4 []Addr
+               ifmat6 []Addr
+       )
+
+       if ifindex > 0 {
+               ifi, err = InterfaceByIndex(ifindex)
+               if err != nil {
+                       return nil, err
+               }
+       }
+
+       ifmat4, err = parseProcNetIGMP(ifi)
+       if err != nil {
+               return nil, err
+       }
+
+       ifmat6, err = parseProcNetIGMP6(ifi)
+       if err != nil {
+               return nil, err
+       }
+
+       return append(ifmat4, ifmat6...), nil
+}
+
+func parseProcNetIGMP(ifi *Interface) ([]Addr, os.Error) {
+       var (
+               ifmat []Addr
+               name  string
+       )
+
+       fd, err := open("/proc/net/igmp")
+       if err != nil {
+               return nil, err
+       }
+       defer fd.close()
+
+       fd.readLine() // skip first line
+       b := make([]byte, IPv4len)
+       for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
+               f := getFields(l)
+               switch len(f) {
+               case 4:
+                       if ifi == nil || name == ifi.Name {
+                               fmt.Sscanf(f[0], "%08x", &b)
+                               ifma := IPAddr{IP: IPv4(b[3], b[2], b[1], b[0])}
+                               ifmat = append(ifmat, ifma.toAddr())
+                       }
+               case 5:
+                       name = f[1]
+               }
+       }
+
+       return ifmat, nil
+}
+
+func parseProcNetIGMP6(ifi *Interface) ([]Addr, os.Error) {
+       var ifmat []Addr
+
+       fd, err := open("/proc/net/igmp6")
+       if err != nil {
+               return nil, err
+       }
+       defer fd.close()
+
+       b := make([]byte, IPv6len)
+       for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
+               f := getFields(l)
+               if ifi == nil || f[1] == ifi.Name {
+                       fmt.Sscanf(f[2], "%32x", &b)
+                       ifma := IPAddr{IP: IP{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]}}
+                       ifmat = append(ifmat, ifma.toAddr())
+
+               }
+       }
+
+       return ifmat, nil
+}
index 24a7431c56ade6f7ba2b3e95c4c543ad12bdce15..950de6c592646ed07b7dc1b7be7177fe4e71d726 100644 (file)
@@ -21,3 +21,10 @@ func interfaceTable(ifindex int) ([]Interface, os.Error) {
 func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
        return nil, nil
 }
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces.  Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+       return nil, nil
+}
index ac523a049029efc16bc4301b4e35b253d2a449ef..0e4089abf8affeada09a49d0c35dc8b3e5100587 100644 (file)
@@ -45,10 +45,17 @@ func TestInterfaces(t *testing.T) {
                if err != nil {
                        t.Fatalf("Interface.Addrs() failed: %v", err)
                }
+               ifmat, err := ifi.MulticastAddrs()
+               if err != nil {
+                       t.Fatalf("Interface.MulticastAddrs() failed: %v", err)
+               }
                t.Logf("%q: flags %q, ifindex %v, mtu %v\n", ifi.Name, ifi.Flags.String(), ifi.Index, ifi.MTU)
                for _, ifa := range ifat {
                        t.Logf("\tinterface address %q\n", ifa.String())
                }
+               for _, ifma := range ifmat {
+                       t.Logf("\tjoined group address %q\n", ifma.String())
+               }
                t.Logf("\thardware address %q", ifi.HardwareAddr.String())
        }
 }
index 571f74cdc85cefd345ce136a053a6f486f12b604..7f5169c87977f6292e26700fd5deb96443576519 100644 (file)
@@ -149,3 +149,10 @@ func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
        }
        return ifat, nil
 }
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces.  Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+       return nil, nil
+}