Source file src/net/interface_aix.go

Documentation: net

     1  // Copyright 2018 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  package net
     6  
     7  import (
     8  	"internal/poll"
     9  	"internal/syscall/unix"
    10  	"syscall"
    11  	"unsafe"
    12  )
    13  
    14  type rawSockaddrDatalink struct {
    15  	Len    uint8
    16  	Family uint8
    17  	Index  uint16
    18  	Type   uint8
    19  	Nlen   uint8
    20  	Alen   uint8
    21  	Slen   uint8
    22  	Data   [120]byte
    23  }
    24  
    25  type ifreq struct {
    26  	Name [16]uint8
    27  	Ifru [16]byte
    28  }
    29  
    30  const _KINFO_RT_IFLIST = (0x1 << 8) | 3 | (1 << 30)
    31  
    32  const _RTAX_NETMASK = 2
    33  const _RTAX_IFA = 5
    34  const _RTAX_MAX = 8
    35  
    36  func getIfList() ([]byte, error) {
    37  	needed, err := syscall.Getkerninfo(_KINFO_RT_IFLIST, 0, 0, 0)
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  	tab := make([]byte, needed)
    42  	_, err = syscall.Getkerninfo(_KINFO_RT_IFLIST, uintptr(unsafe.Pointer(&tab[0])), uintptr(unsafe.Pointer(&needed)), 0)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  	return tab[:needed], nil
    47  }
    48  
    49  // If the ifindex is zero, interfaceTable returns mappings of all
    50  // network interfaces. Otherwise it returns a mapping of a specific
    51  // interface.
    52  func interfaceTable(ifindex int) ([]Interface, error) {
    53  	tab, err := getIfList()
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  
    58  	sock, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, 0)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	defer poll.CloseFunc(sock)
    63  
    64  	var ift []Interface
    65  	for len(tab) > 0 {
    66  		ifm := (*syscall.IfMsgHdr)(unsafe.Pointer(&tab[0]))
    67  		if ifm.Msglen == 0 {
    68  			break
    69  		}
    70  		if ifm.Type == syscall.RTM_IFINFO {
    71  			if ifindex == 0 || ifindex == int(ifm.Index) {
    72  				sdl := (*rawSockaddrDatalink)(unsafe.Pointer(&tab[syscall.SizeofIfMsghdr]))
    73  
    74  				ifi := &Interface{Index: int(ifm.Index), Flags: linkFlags(ifm.Flags)}
    75  				ifi.Name = string(sdl.Data[:sdl.Nlen])
    76  				ifi.HardwareAddr = sdl.Data[sdl.Nlen : sdl.Nlen+sdl.Alen]
    77  
    78  				// Retrieve MTU
    79  				ifr := &ifreq{}
    80  				copy(ifr.Name[:], ifi.Name)
    81  				err = unix.Ioctl(sock, syscall.SIOCGIFMTU, uintptr(unsafe.Pointer(ifr)))
    82  				if err != nil {
    83  					return nil, err
    84  				}
    85  				ifi.MTU = int(ifr.Ifru[0])<<24 | int(ifr.Ifru[1])<<16 | int(ifr.Ifru[2])<<8 | int(ifr.Ifru[3])
    86  
    87  				ift = append(ift, *ifi)
    88  				if ifindex == int(ifm.Index) {
    89  					break
    90  				}
    91  			}
    92  		}
    93  		tab = tab[ifm.Msglen:]
    94  	}
    95  
    96  	return ift, nil
    97  }
    98  
    99  func linkFlags(rawFlags int32) Flags {
   100  	var f Flags
   101  	if rawFlags&syscall.IFF_UP != 0 {
   102  		f |= FlagUp
   103  	}
   104  	if rawFlags&syscall.IFF_BROADCAST != 0 {
   105  		f |= FlagBroadcast
   106  	}
   107  	if rawFlags&syscall.IFF_LOOPBACK != 0 {
   108  		f |= FlagLoopback
   109  	}
   110  	if rawFlags&syscall.IFF_POINTOPOINT != 0 {
   111  		f |= FlagPointToPoint
   112  	}
   113  	if rawFlags&syscall.IFF_MULTICAST != 0 {
   114  		f |= FlagMulticast
   115  	}
   116  	return f
   117  }
   118  
   119  // If the ifi is nil, interfaceAddrTable returns addresses for all
   120  // network interfaces. Otherwise it returns addresses for a specific
   121  // interface.
   122  func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
   123  	tab, err := getIfList()
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  
   128  	var ifat []Addr
   129  	for len(tab) > 0 {
   130  		ifm := (*syscall.IfMsgHdr)(unsafe.Pointer(&tab[0]))
   131  		if ifm.Msglen == 0 {
   132  			break
   133  		}
   134  		if ifm.Type == syscall.RTM_NEWADDR {
   135  			if ifi == nil || ifi.Index == int(ifm.Index) {
   136  				mask := ifm.Addrs
   137  				off := uint(syscall.SizeofIfMsghdr)
   138  
   139  				var iprsa, nmrsa *syscall.RawSockaddr
   140  				for i := uint(0); i < _RTAX_MAX; i++ {
   141  					if mask&(1<<i) == 0 {
   142  						continue
   143  					}
   144  					rsa := (*syscall.RawSockaddr)(unsafe.Pointer(&tab[off]))
   145  					if i == _RTAX_NETMASK {
   146  						nmrsa = rsa
   147  					}
   148  					if i == _RTAX_IFA {
   149  						iprsa = rsa
   150  					}
   151  					off += (uint(rsa.Len) + 3) &^ 3
   152  				}
   153  				if iprsa != nil && nmrsa != nil {
   154  					var mask IPMask
   155  					var ip IP
   156  
   157  					switch iprsa.Family {
   158  					case syscall.AF_INET:
   159  						ipsa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(iprsa))
   160  						nmsa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(nmrsa))
   161  						ip = IPv4(ipsa.Addr[0], ipsa.Addr[1], ipsa.Addr[2], ipsa.Addr[3])
   162  						mask = IPv4Mask(nmsa.Addr[0], nmsa.Addr[1], nmsa.Addr[2], nmsa.Addr[3])
   163  					case syscall.AF_INET6:
   164  						ipsa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(iprsa))
   165  						nmsa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(nmrsa))
   166  						ip = make(IP, IPv6len)
   167  						copy(ip, ipsa.Addr[:])
   168  						mask = make(IPMask, IPv6len)
   169  						copy(mask, nmsa.Addr[:])
   170  					}
   171  					ifa := &IPNet{IP: ip, Mask: mask}
   172  					ifat = append(ifat, ifa)
   173  				}
   174  			}
   175  		}
   176  		tab = tab[ifm.Msglen:]
   177  	}
   178  
   179  	return ifat, nil
   180  }
   181  
   182  // interfaceMulticastAddrTable returns addresses for a specific
   183  // interface.
   184  func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
   185  	return nil, nil
   186  }
   187  

View as plain text