mirror of
https://github.com/golang/go
synced 2024-11-21 15:34:45 -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:
parent
dc7f82559d
commit
946cb0ece1
@ -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\
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
49
src/pkg/net/interface_darwin.go
Normal file
49
src/pkg/net/interface_darwin.go
Normal 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
|
||||
}
|
49
src/pkg/net/interface_freebsd.go
Normal file
49
src/pkg/net/interface_freebsd.go
Normal 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
|
||||
}
|
@ -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])
|
||||
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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user