github.com/shijuvar/go@v0.0.0-20141209052335-e8f13700b70c/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 }