github.com/sean-/go@v0.0.0-20151219100004-97f854cd7bb6/src/net/interface_bsd.go (about)

     1  // Copyright 2011 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build darwin dragonfly freebsd netbsd openbsd
     6  
     7  package net
     8  
     9  import (
    10  	"os"
    11  	"syscall"
    12  	"unsafe"
    13  )
    14  
    15  // If the ifindex is zero, interfaceTable returns mappings of all
    16  // network interfaces.  Otherwise it returns a mapping of a specific
    17  // interface.
    18  func interfaceTable(ifindex int) ([]Interface, error) {
    19  	tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
    20  	if err != nil {
    21  		return nil, os.NewSyscallError("routerib", err)
    22  	}
    23  	msgs, err := syscall.ParseRoutingMessage(tab)
    24  	if err != nil {
    25  		return nil, os.NewSyscallError("parseroutingmessage", err)
    26  	}
    27  	return parseInterfaceTable(ifindex, msgs)
    28  }
    29  
    30  func parseInterfaceTable(ifindex int, msgs []syscall.RoutingMessage) ([]Interface, error) {
    31  	var ift []Interface
    32  loop:
    33  	for _, m := range msgs {
    34  		switch m := m.(type) {
    35  		case *syscall.InterfaceMessage:
    36  			if ifindex == 0 || ifindex == int(m.Header.Index) {
    37  				ifi, err := newLink(m)
    38  				if err != nil {
    39  					return nil, err
    40  				}
    41  				ift = append(ift, *ifi)
    42  				if ifindex == int(m.Header.Index) {
    43  					break loop
    44  				}
    45  			}
    46  		}
    47  	}
    48  	return ift, nil
    49  }
    50  
    51  func newLink(m *syscall.InterfaceMessage) (*Interface, error) {
    52  	sas, err := syscall.ParseRoutingSockaddr(m)
    53  	if err != nil {
    54  		return nil, os.NewSyscallError("parseroutingsockaddr", err)
    55  	}
    56  	ifi := &Interface{Index: int(m.Header.Index), Flags: linkFlags(m.Header.Flags)}
    57  	sa, _ := sas[syscall.RTAX_IFP].(*syscall.SockaddrDatalink)
    58  	if sa != nil {
    59  		// NOTE: SockaddrDatalink.Data is minimum work area,
    60  		// can be larger.
    61  		m.Data = m.Data[unsafe.Offsetof(sa.Data):]
    62  		var name [syscall.IFNAMSIZ]byte
    63  		for i := 0; i < int(sa.Nlen); i++ {
    64  			name[i] = byte(m.Data[i])
    65  		}
    66  		ifi.Name = string(name[:sa.Nlen])
    67  		ifi.MTU = int(m.Header.Data.Mtu)
    68  		addr := make([]byte, sa.Alen)
    69  		for i := 0; i < int(sa.Alen); i++ {
    70  			addr[i] = byte(m.Data[int(sa.Nlen)+i])
    71  		}
    72  		ifi.HardwareAddr = addr[:sa.Alen]
    73  	}
    74  	return ifi, nil
    75  }
    76  
    77  func linkFlags(rawFlags int32) Flags {
    78  	var f Flags
    79  	if rawFlags&syscall.IFF_UP != 0 {
    80  		f |= FlagUp
    81  	}
    82  	if rawFlags&syscall.IFF_BROADCAST != 0 {
    83  		f |= FlagBroadcast
    84  	}
    85  	if rawFlags&syscall.IFF_LOOPBACK != 0 {
    86  		f |= FlagLoopback
    87  	}
    88  	if rawFlags&syscall.IFF_POINTOPOINT != 0 {
    89  		f |= FlagPointToPoint
    90  	}
    91  	if rawFlags&syscall.IFF_MULTICAST != 0 {
    92  		f |= FlagMulticast
    93  	}
    94  	return f
    95  }
    96  
    97  // If the ifi is nil, interfaceAddrTable returns addresses for all
    98  // network interfaces.  Otherwise it returns addresses for a specific
    99  // interface.
   100  func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
   101  	index := 0
   102  	if ifi != nil {
   103  		index = ifi.Index
   104  	}
   105  	tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, index)
   106  	if err != nil {
   107  		return nil, os.NewSyscallError("routerib", err)
   108  	}
   109  	msgs, err := syscall.ParseRoutingMessage(tab)
   110  	if err != nil {
   111  		return nil, os.NewSyscallError("parseroutingmessage", err)
   112  	}
   113  	var ift []Interface
   114  	if index == 0 {
   115  		ift, err = parseInterfaceTable(index, msgs)
   116  		if err != nil {
   117  			return nil, err
   118  		}
   119  	}
   120  	var ifat []Addr
   121  	for _, m := range msgs {
   122  		switch m := m.(type) {
   123  		case *syscall.InterfaceAddrMessage:
   124  			if index == 0 || index == int(m.Header.Index) {
   125  				if index == 0 {
   126  					var err error
   127  					ifi, err = interfaceByIndex(ift, int(m.Header.Index))
   128  					if err != nil {
   129  						return nil, err
   130  					}
   131  				}
   132  				ifa, err := newAddr(ifi, m)
   133  				if err != nil {
   134  					return nil, err
   135  				}
   136  				if ifa != nil {
   137  					ifat = append(ifat, ifa)
   138  				}
   139  			}
   140  		}
   141  	}
   142  	return ifat, nil
   143  }
   144  
   145  func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (*IPNet, error) {
   146  	sas, err := syscall.ParseRoutingSockaddr(m)
   147  	if err != nil {
   148  		return nil, os.NewSyscallError("parseroutingsockaddr", err)
   149  	}
   150  	ifa := &IPNet{}
   151  	switch sa := sas[syscall.RTAX_NETMASK].(type) {
   152  	case *syscall.SockaddrInet4:
   153  		ifa.Mask = IPv4Mask(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
   154  	case *syscall.SockaddrInet6:
   155  		ifa.Mask = make(IPMask, IPv6len)
   156  		copy(ifa.Mask, sa.Addr[:])
   157  	}
   158  	switch sa := sas[syscall.RTAX_IFA].(type) {
   159  	case *syscall.SockaddrInet4:
   160  		ifa.IP = IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
   161  	case *syscall.SockaddrInet6:
   162  		ifa.IP = make(IP, IPv6len)
   163  		copy(ifa.IP, sa.Addr[:])
   164  		// NOTE: KAME based IPv6 protcol stack usually embeds
   165  		// the interface index in the interface-local or
   166  		// link-local address as the kernel-internal form.
   167  		if ifa.IP.IsLinkLocalUnicast() {
   168  			ifa.IP[2], ifa.IP[3] = 0, 0
   169  		}
   170  	}
   171  	if ifa.IP == nil || ifa.Mask == nil {
   172  		return nil, nil // Sockaddrs contain syscall.SockaddrDatalink on NetBSD
   173  	}
   174  	return ifa, nil
   175  }