interface_linux.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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. package net
  5. import (
  6. "os"
  7. "syscall"
  8. "unsafe"
  9. )
  10. // If the ifindex is zero, interfaceTable returns mappings of all
  11. // network interfaces. Otherwise it returns a mapping of a specific
  12. // interface.
  13. func interfaceTable(ifindex int) ([]Interface, error) {
  14. tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
  15. if err != nil {
  16. return nil, os.NewSyscallError("netlink rib", err)
  17. }
  18. msgs, err := syscall.ParseNetlinkMessage(tab)
  19. if err != nil {
  20. return nil, os.NewSyscallError("netlink message", err)
  21. }
  22. var ift []Interface
  23. loop:
  24. for _, m := range msgs {
  25. switch m.Header.Type {
  26. case syscall.NLMSG_DONE:
  27. break loop
  28. case syscall.RTM_NEWLINK:
  29. ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0]))
  30. if ifindex == 0 || ifindex == int(ifim.Index) {
  31. attrs, err := syscall.ParseNetlinkRouteAttr(&m)
  32. if err != nil {
  33. return nil, os.NewSyscallError("netlink routeattr", err)
  34. }
  35. ift = append(ift, *newLink(ifim, attrs))
  36. if ifindex == int(ifim.Index) {
  37. break loop
  38. }
  39. }
  40. }
  41. }
  42. return ift, nil
  43. }
  44. const (
  45. // See linux/if_arp.h.
  46. // Note that Linux doesn't support IPv4 over IPv6 tunneling.
  47. sysARPHardwareIPv4IPv4 = 768 // IPv4 over IPv4 tunneling
  48. sysARPHardwareIPv6IPv6 = 769 // IPv6 over IPv6 tunneling
  49. sysARPHardwareIPv6IPv4 = 776 // IPv6 over IPv4 tunneling
  50. sysARPHardwareGREIPv4 = 778 // any over GRE over IPv4 tunneling
  51. sysARPHardwareGREIPv6 = 823 // any over GRE over IPv6 tunneling
  52. )
  53. func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) *Interface {
  54. ifi := &Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)}
  55. for _, a := range attrs {
  56. switch a.Attr.Type {
  57. case syscall.IFLA_ADDRESS:
  58. // We never return any /32 or /128 IP address
  59. // prefix on any IP tunnel interface as the
  60. // hardware address.
  61. switch len(a.Value) {
  62. case IPv4len:
  63. switch ifim.Type {
  64. case sysARPHardwareIPv4IPv4, sysARPHardwareGREIPv4, sysARPHardwareIPv6IPv4:
  65. continue
  66. }
  67. case IPv6len:
  68. switch ifim.Type {
  69. case sysARPHardwareIPv6IPv6, sysARPHardwareGREIPv6:
  70. continue
  71. }
  72. }
  73. var nonzero bool
  74. for _, b := range a.Value {
  75. if b != 0 {
  76. nonzero = true
  77. break
  78. }
  79. }
  80. if nonzero {
  81. ifi.HardwareAddr = a.Value[:]
  82. }
  83. case syscall.IFLA_IFNAME:
  84. ifi.Name = string(a.Value[:len(a.Value)-1])
  85. case syscall.IFLA_MTU:
  86. ifi.MTU = int(*(*uint32)(unsafe.Pointer(&a.Value[:4][0])))
  87. }
  88. }
  89. return ifi
  90. }
  91. func linkFlags(rawFlags uint32) Flags {
  92. var f Flags
  93. if rawFlags&syscall.IFF_UP != 0 {
  94. f |= FlagUp
  95. }
  96. if rawFlags&syscall.IFF_BROADCAST != 0 {
  97. f |= FlagBroadcast
  98. }
  99. if rawFlags&syscall.IFF_LOOPBACK != 0 {
  100. f |= FlagLoopback
  101. }
  102. if rawFlags&syscall.IFF_POINTOPOINT != 0 {
  103. f |= FlagPointToPoint
  104. }
  105. if rawFlags&syscall.IFF_MULTICAST != 0 {
  106. f |= FlagMulticast
  107. }
  108. return f
  109. }
  110. // If the ifi is nil, interfaceAddrTable returns addresses for all
  111. // network interfaces. Otherwise it returns addresses for a specific
  112. // interface.
  113. func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
  114. tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
  115. if err != nil {
  116. return nil, os.NewSyscallError("netlink rib", err)
  117. }
  118. msgs, err := syscall.ParseNetlinkMessage(tab)
  119. if err != nil {
  120. return nil, os.NewSyscallError("netlink message", err)
  121. }
  122. var ift []Interface
  123. if ifi == nil {
  124. var err error
  125. ift, err = interfaceTable(0)
  126. if err != nil {
  127. return nil, err
  128. }
  129. }
  130. ifat, err := addrTable(ift, ifi, msgs)
  131. if err != nil {
  132. return nil, err
  133. }
  134. return ifat, nil
  135. }
  136. func addrTable(ift []Interface, ifi *Interface, msgs []syscall.NetlinkMessage) ([]Addr, error) {
  137. var ifat []Addr
  138. loop:
  139. for _, m := range msgs {
  140. switch m.Header.Type {
  141. case syscall.NLMSG_DONE:
  142. break loop
  143. case syscall.RTM_NEWADDR:
  144. ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
  145. if len(ift) != 0 || ifi.Index == int(ifam.Index) {
  146. if len(ift) != 0 {
  147. var err error
  148. ifi, err = interfaceByIndex(ift, int(ifam.Index))
  149. if err != nil {
  150. return nil, err
  151. }
  152. }
  153. attrs, err := syscall.ParseNetlinkRouteAttr(&m)
  154. if err != nil {
  155. return nil, os.NewSyscallError("netlink routeattr", err)
  156. }
  157. ifa := newAddr(ifi, ifam, attrs)
  158. if ifa != nil {
  159. ifat = append(ifat, ifa)
  160. }
  161. }
  162. }
  163. }
  164. return ifat, nil
  165. }
  166. func newAddr(ifi *Interface, ifam *syscall.IfAddrmsg, attrs []syscall.NetlinkRouteAttr) Addr {
  167. var ipPointToPoint bool
  168. // Seems like we need to make sure whether the IP interface
  169. // stack consists of IP point-to-point numbered or unnumbered
  170. // addressing over point-to-point link encapsulation.
  171. if ifi.Flags&FlagPointToPoint != 0 {
  172. for _, a := range attrs {
  173. if a.Attr.Type == syscall.IFA_LOCAL {
  174. ipPointToPoint = true
  175. break
  176. }
  177. }
  178. }
  179. for _, a := range attrs {
  180. if ipPointToPoint && a.Attr.Type == syscall.IFA_ADDRESS || !ipPointToPoint && a.Attr.Type == syscall.IFA_LOCAL {
  181. continue
  182. }
  183. switch ifam.Family {
  184. case syscall.AF_INET:
  185. return &IPNet{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3]), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv4len)}
  186. case syscall.AF_INET6:
  187. ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv6len)}
  188. copy(ifa.IP, a.Value[:])
  189. return ifa
  190. }
  191. }
  192. return nil
  193. }
  194. // interfaceMulticastAddrTable returns addresses for a specific
  195. // interface.
  196. func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
  197. ifmat4 := parseProcNetIGMP("/proc/net/igmp", ifi)
  198. ifmat6 := parseProcNetIGMP6("/proc/net/igmp6", ifi)
  199. return append(ifmat4, ifmat6...), nil
  200. }
  201. func parseProcNetIGMP(path string, ifi *Interface) []Addr {
  202. fd, err := open(path)
  203. if err != nil {
  204. return nil
  205. }
  206. defer fd.close()
  207. var (
  208. ifmat []Addr
  209. name string
  210. )
  211. fd.readLine() // skip first line
  212. b := make([]byte, IPv4len)
  213. for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
  214. f := splitAtBytes(l, " :\r\t\n")
  215. if len(f) < 4 {
  216. continue
  217. }
  218. switch {
  219. case l[0] != ' ' && l[0] != '\t': // new interface line
  220. name = f[1]
  221. case len(f[0]) == 8:
  222. if ifi == nil || name == ifi.Name {
  223. // The Linux kernel puts the IP
  224. // address in /proc/net/igmp in native
  225. // endianness.
  226. for i := 0; i+1 < len(f[0]); i += 2 {
  227. b[i/2], _ = xtoi2(f[0][i:i+2], 0)
  228. }
  229. i := *(*uint32)(unsafe.Pointer(&b[:4][0]))
  230. ifma := IPAddr{IP: IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i))}
  231. ifmat = append(ifmat, ifma.toAddr())
  232. }
  233. }
  234. }
  235. return ifmat
  236. }
  237. func parseProcNetIGMP6(path string, ifi *Interface) []Addr {
  238. fd, err := open(path)
  239. if err != nil {
  240. return nil
  241. }
  242. defer fd.close()
  243. var ifmat []Addr
  244. b := make([]byte, IPv6len)
  245. for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
  246. f := splitAtBytes(l, " \r\t\n")
  247. if len(f) < 6 {
  248. continue
  249. }
  250. if ifi == nil || f[1] == ifi.Name {
  251. for i := 0; i+1 < len(f[2]); i += 2 {
  252. b[i/2], _ = xtoi2(f[2][i:i+2], 0)
  253. }
  254. ifma := IPAddr{IP: IP{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]}}
  255. ifmat = append(ifmat, ifma.toAddr())
  256. }
  257. }
  258. return ifmat
  259. }