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 } 176