// 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 Linux package net import ( "os" "syscall" "unsafe" ) // IsUp returns true if ifi is up. func (ifi *Interface) IsUp() bool { if ifi == nil { return false } return ifi.rawFlags&syscall.IFF_UP != 0 } // IsLoopback returns true if ifi is a loopback interface. func (ifi *Interface) IsLoopback() bool { if ifi == nil { return false } return ifi.rawFlags&syscall.IFF_LOOPBACK != 0 } // CanBroadcast returns true if ifi supports a broadcast access // capability. func (ifi *Interface) CanBroadcast() bool { if ifi == nil { return false } return ifi.rawFlags&syscall.IFF_BROADCAST != 0 } // IsPointToPoint returns true if ifi belongs to a point-to-point // link. func (ifi *Interface) IsPointToPoint() bool { if ifi == nil { return false } return ifi.rawFlags&syscall.IFF_POINTOPOINT != 0 } // CanMulticast returns true if ifi supports a multicast access // capability. func (ifi *Interface) CanMulticast() bool { if ifi == nil { return false } return ifi.rawFlags&syscall.IFF_MULTICAST != 0 } // If the ifindex is zero, interfaceTable returns mappings of all // network interfaces. Otheriwse it returns a mapping of a specific // interface. func interfaceTable(ifindex int) ([]Interface, os.Error) { var ( ift []Interface tab []byte msgs []syscall.NetlinkMessage e int ) tab, e = syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC) if e != 0 { return nil, os.NewSyscallError("netlink rib", e) } msgs, e = syscall.ParseNetlinkMessage(tab) if e != 0 { return nil, os.NewSyscallError("netlink message", e) } for _, m := range msgs { switch m.Header.Type { case syscall.NLMSG_DONE: goto done case syscall.RTM_NEWLINK: ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0])) if ifindex == 0 || ifindex == int(ifim.Index) { attrs, e := syscall.ParseNetlinkRouteAttr(&m) if e != 0 { return nil, os.NewSyscallError("netlink routeattr", e) } ifi := newLink(attrs, ifim) ift = append(ift, ifi) } } } done: return ift, nil } func newLink(attrs []syscall.NetlinkRouteAttr, ifim *syscall.IfInfomsg) Interface { ifi := Interface{Index: int(ifim.Index), rawFlags: int(ifim.Flags)} for _, a := range attrs { switch a.Attr.Type { case syscall.IFLA_ADDRESS: var nonzero bool for _, b := range a.Value { if b != 0 { nonzero = true } } if nonzero { ifi.HardwareAddr = a.Value[:] } case syscall.IFLA_IFNAME: ifi.Name = string(a.Value[:]) case syscall.IFLA_MTU: ifi.MTU = int(uint32(a.Value[3])<<24 | uint32(a.Value[2])<<16 | uint32(a.Value[1])<<8 | uint32(a.Value[0])) } } return ifi } // If the ifindex is zero, interfaceAddrTable returns addresses // for all network interfaces. Otherwise it returns addresses // 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 ) tab, e = syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_INET) if e != 0 { return nil, os.NewSyscallError("netlink rib", e) } msgs4, e = syscall.ParseNetlinkMessage(tab) if e != 0 { return nil, os.NewSyscallError("netlink message", e) } ifat4, err = addrTable(msgs4, ifindex) if err != nil { return nil, err } tab, e = syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_INET6) if e != 0 { return nil, os.NewSyscallError("netlink rib", e) } msgs6, e = syscall.ParseNetlinkMessage(tab) if e != 0 { return nil, os.NewSyscallError("netlink message", e) } ifat6, err = addrTable(msgs6, ifindex) if err != nil { return nil, err } return append(ifat4, ifat6...), nil } func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, os.Error) { var ifat []Addr for _, m := range msgs { switch m.Header.Type { case syscall.NLMSG_DONE: goto done case syscall.RTM_NEWADDR: ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0])) if ifindex == 0 || ifindex == int(ifam.Index) { attrs, e := syscall.ParseNetlinkRouteAttr(&m) if e != 0 { return nil, os.NewSyscallError("netlink routeattr", e) } ifat = append(ifat, newAddr(attrs, int(ifam.Family))...) } } } done: return ifat, nil } func newAddr(attrs []syscall.NetlinkRouteAttr, family int) []Addr { var ifat []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[:]) } ifat = append(ifat, ifa.toAddr()) } } return ifat }