1
0
mirror of https://github.com/golang/go synced 2024-11-21 23:14:40 -07:00

net: joined group addresses for a specific interface for darwin, freebsd, linux

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
This commit is contained in:
Mikio Hara 2011-08-04 00:22:52 -04:00 committed by Russ Cox
parent dc7f82559d
commit 946cb0ece1
9 changed files with 261 additions and 15 deletions

View 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\

View 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)

View 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())
}
}
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
}

View File

@ -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
}

View File

@ -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
}

View 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 (
ifat4 []Addr
ifat6 []Addr
tab []byte
msgs4 []syscall.NetlinkMessage
msgs6 []syscall.NetlinkMessage
e int
err os.Error
ifat4 []Addr
ifat6 []Addr
msgs4 []syscall.NetlinkMessage
msgs6 []syscall.NetlinkMessage
)
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])
case syscall.AF_INET6:
ifa.IP = make(IP, IPv6len)
copy(ifa.IP, a.Value[:])
}
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 := &IPAddr{IP: make(IP, IPv6len)}
copy(ifa.IP, a.Value[:])
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
}

View 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
}

View 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())
}
}

View 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
}