github.com/ccccaoqing/test@v0.0.0-20220510085219-3985d23445c0/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("route rib", err)
    22  	}
    23  	msgs, err := syscall.ParseRoutingMessage(tab)
    24  	if err != nil {
    25  		return nil, os.NewSyscallError("route message", 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("route sockaddr", err)
    55  	}
    56  	ifi := &Interface{Index: int(m.Header.Index), Flags: linkFlags(m.Header.Flags)}
    57  	for _, sa := range sas {
    58  		switch sa := sa.(type) {
    59  		case *syscall.SockaddrDatalink:
    60  			// NOTE: SockaddrDatalink.Data is minimum work area,
    61  			// can be larger.
    62  			m.Data = m.Data[unsafe.Offsetof(sa.Data):]
    63  			var name [syscall.IFNAMSIZ]byte
    64  			for i := 0; i < int(sa.Nlen); i++ {
    65  				name[i] = byte(m.Data[i])
    66  			}
    67  			ifi.Name = string(name[:sa.Nlen])
    68  			ifi.MTU = int(m.Header.Data.Mtu)
    69  			addr := make([]byte, sa.Alen)
    70  			for i := 0; i < int(sa.Alen); i++ {
    71  				addr[i] = byte(m.Data[int(sa.Nlen)+i])
    72  			}
    73  			ifi.HardwareAddr = addr[:sa.Alen]
    74  		}
    75  	}
    76  	return ifi, nil
    77  }
    78  
    79  func linkFlags(rawFlags int32) Flags {
    80  	var f Flags
    81  	if rawFlags&syscall.IFF_UP != 0 {
    82  		f |= FlagUp
    83  	}
    84  	if rawFlags&syscall.IFF_BROADCAST != 0 {
    85  		f |= FlagBroadcast
    86  	}
    87  	if rawFlags&syscall.IFF_LOOPBACK != 0 {
    88  		f |= FlagLoopback
    89  	}
    90  	if rawFlags&syscall.IFF_POINTOPOINT != 0 {
    91  		f |= FlagPointToPoint
    92  	}
    93  	if rawFlags&syscall.IFF_MULTICAST != 0 {
    94  		f |= FlagMulticast
    95  	}
    96  	return f
    97  }
    98  
    99  // If the ifi is nil, interfaceAddrTable returns addresses for all
   100  // network interfaces.  Otherwise it returns addresses for a specific
   101  // interface.
   102  func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
   103  	index := 0
   104  	if ifi != nil {
   105  		index = ifi.Index
   106  	}
   107  	tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, index)
   108  	if err != nil {
   109  		return nil, os.NewSyscallError("route rib", err)
   110  	}
   111  	msgs, err := syscall.ParseRoutingMessage(tab)
   112  	if err != nil {
   113  		return nil, os.NewSyscallError("route message", err)
   114  	}
   115  	var ift []Interface
   116  	if index == 0 {
   117  		ift, err = parseInterfaceTable(index, msgs)
   118  		if err != nil {
   119  			return nil, err
   120  		}
   121  	}
   122  	var ifat []Addr
   123  	for _, m := range msgs {
   124  		switch m := m.(type) {
   125  		case *syscall.InterfaceAddrMessage:
   126  			if index == 0 || index == int(m.Header.Index) {
   127  				if index == 0 {
   128  					var err error
   129  					ifi, err = interfaceByIndex(ift, int(m.Header.Index))
   130  					if err != nil {
   131  						return nil, err
   132  					}
   133  				}
   134  				ifa, err := newAddr(ifi, m)
   135  				if err != nil {
   136  					return nil, err
   137  				}
   138  				if ifa != nil {
   139  					ifat = append(ifat, ifa)
   140  				}
   141  			}
   142  		}
   143  	}
   144  	return ifat, nil
   145  }
   146  
   147  func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (Addr, error) {
   148  	sas, err := syscall.ParseRoutingSockaddr(m)
   149  	if err != nil {
   150  		return nil, os.NewSyscallError("route sockaddr", err)
   151  	}
   152  	ifa := &IPNet{}
   153  	for i, sa := range sas {
   154  		switch sa := sa.(type) {
   155  		case *syscall.SockaddrInet4:
   156  			switch i {
   157  			case 0:
   158  				ifa.Mask = IPv4Mask(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
   159  			case 1:
   160  				ifa.IP = IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
   161  			}
   162  		case *syscall.SockaddrInet6:
   163  			switch i {
   164  			case 0:
   165  				ifa.Mask = make(IPMask, IPv6len)
   166  				copy(ifa.Mask, sa.Addr[:])
   167  			case 1:
   168  				ifa.IP = make(IP, IPv6len)
   169  				copy(ifa.IP, sa.Addr[:])
   170  				// NOTE: KAME based IPv6 protcol stack usually embeds
   171  				// the interface index in the interface-local or link-
   172  				// local address as the kernel-internal form.
   173  				if ifa.IP.IsLinkLocalUnicast() {
   174  					ifa.IP[2], ifa.IP[3] = 0, 0
   175  				}
   176  			}
   177  		default: // Sockaddrs contain syscall.SockaddrDatalink on NetBSD
   178  			return nil, nil
   179  		}
   180  	}
   181  	return ifa, nil
   182  }