interface.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  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. "errors"
  7. "internal/itoa"
  8. "sync"
  9. "time"
  10. )
  11. // BUG(mikio): On JS, methods and functions related to
  12. // Interface are not implemented.
  13. // BUG(mikio): On AIX, DragonFly BSD, NetBSD, OpenBSD, Plan 9 and
  14. // Solaris, the MulticastAddrs method of Interface is not implemented.
  15. var (
  16. errInvalidInterface = errors.New("invalid network interface")
  17. errInvalidInterfaceIndex = errors.New("invalid network interface index")
  18. errInvalidInterfaceName = errors.New("invalid network interface name")
  19. errNoSuchInterface = errors.New("no such network interface")
  20. errNoSuchMulticastInterface = errors.New("no such multicast network interface")
  21. )
  22. // Interface represents a mapping between network interface name
  23. // and index. It also represents network interface facility
  24. // information.
  25. type Interface struct {
  26. Index int // positive integer that starts at one, zero is never used
  27. MTU int // maximum transmission unit
  28. Name string // e.g., "en0", "lo0", "eth0.100"
  29. HardwareAddr HardwareAddr // IEEE MAC-48, EUI-48 and EUI-64 form
  30. Flags Flags // e.g., FlagUp, FlagLoopback, FlagMulticast
  31. }
  32. type Flags uint
  33. const (
  34. FlagUp Flags = 1 << iota // interface is up
  35. FlagBroadcast // interface supports broadcast access capability
  36. FlagLoopback // interface is a loopback interface
  37. FlagPointToPoint // interface belongs to a point-to-point link
  38. FlagMulticast // interface supports multicast access capability
  39. )
  40. var flagNames = []string{
  41. "up",
  42. "broadcast",
  43. "loopback",
  44. "pointtopoint",
  45. "multicast",
  46. }
  47. func (f Flags) String() string {
  48. s := ""
  49. for i, name := range flagNames {
  50. if f&(1<<uint(i)) != 0 {
  51. if s != "" {
  52. s += "|"
  53. }
  54. s += name
  55. }
  56. }
  57. if s == "" {
  58. s = "0"
  59. }
  60. return s
  61. }
  62. // Addrs returns a list of unicast interface addresses for a specific
  63. // interface.
  64. func (ifi *Interface) Addrs() ([]Addr, error) {
  65. if ifi == nil {
  66. return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
  67. }
  68. ifat, err := interfaceAddrTable(ifi)
  69. if err != nil {
  70. err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
  71. }
  72. return ifat, err
  73. }
  74. // MulticastAddrs returns a list of multicast, joined group addresses
  75. // for a specific interface.
  76. func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
  77. if ifi == nil {
  78. return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
  79. }
  80. ifat, err := interfaceMulticastAddrTable(ifi)
  81. if err != nil {
  82. err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
  83. }
  84. return ifat, err
  85. }
  86. // Interfaces returns a list of the system's network interfaces.
  87. func Interfaces() ([]Interface, error) {
  88. ift, err := interfaceTable(0)
  89. if err != nil {
  90. return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
  91. }
  92. if len(ift) != 0 {
  93. zoneCache.update(ift, false)
  94. }
  95. return ift, nil
  96. }
  97. // InterfaceAddrs returns a list of the system's unicast interface
  98. // addresses.
  99. //
  100. // The returned list does not identify the associated interface; use
  101. // Interfaces and Interface.Addrs for more detail.
  102. func InterfaceAddrs() ([]Addr, error) {
  103. ifat, err := interfaceAddrTable(nil)
  104. if err != nil {
  105. err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
  106. }
  107. return ifat, err
  108. }
  109. // InterfaceByIndex returns the interface specified by index.
  110. //
  111. // On Solaris, it returns one of the logical network interfaces
  112. // sharing the logical data link; for more precision use
  113. // InterfaceByName.
  114. func InterfaceByIndex(index int) (*Interface, error) {
  115. if index <= 0 {
  116. return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceIndex}
  117. }
  118. ift, err := interfaceTable(index)
  119. if err != nil {
  120. return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
  121. }
  122. ifi, err := interfaceByIndex(ift, index)
  123. if err != nil {
  124. err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
  125. }
  126. return ifi, err
  127. }
  128. func interfaceByIndex(ift []Interface, index int) (*Interface, error) {
  129. for _, ifi := range ift {
  130. if index == ifi.Index {
  131. return &ifi, nil
  132. }
  133. }
  134. return nil, errNoSuchInterface
  135. }
  136. // InterfaceByName returns the interface specified by name.
  137. func InterfaceByName(name string) (*Interface, error) {
  138. if name == "" {
  139. return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceName}
  140. }
  141. ift, err := interfaceTable(0)
  142. if err != nil {
  143. return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
  144. }
  145. if len(ift) != 0 {
  146. zoneCache.update(ift, false)
  147. }
  148. for _, ifi := range ift {
  149. if name == ifi.Name {
  150. return &ifi, nil
  151. }
  152. }
  153. return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errNoSuchInterface}
  154. }
  155. // An ipv6ZoneCache represents a cache holding partial network
  156. // interface information. It is used for reducing the cost of IPv6
  157. // addressing scope zone resolution.
  158. //
  159. // Multiple names sharing the index are managed by first-come
  160. // first-served basis for consistency.
  161. type ipv6ZoneCache struct {
  162. sync.RWMutex // guard the following
  163. lastFetched time.Time // last time routing information was fetched
  164. toIndex map[string]int // interface name to its index
  165. toName map[int]string // interface index to its name
  166. }
  167. var zoneCache = ipv6ZoneCache{
  168. toIndex: make(map[string]int),
  169. toName: make(map[int]string),
  170. }
  171. // update refreshes the network interface information if the cache was last
  172. // updated more than 1 minute ago, or if force is set. It reports whether the
  173. // cache was updated.
  174. func (zc *ipv6ZoneCache) update(ift []Interface, force bool) (updated bool) {
  175. zc.Lock()
  176. defer zc.Unlock()
  177. now := time.Now()
  178. if !force && zc.lastFetched.After(now.Add(-60*time.Second)) {
  179. return false
  180. }
  181. zc.lastFetched = now
  182. if len(ift) == 0 {
  183. var err error
  184. if ift, err = interfaceTable(0); err != nil {
  185. return false
  186. }
  187. }
  188. zc.toIndex = make(map[string]int, len(ift))
  189. zc.toName = make(map[int]string, len(ift))
  190. for _, ifi := range ift {
  191. zc.toIndex[ifi.Name] = ifi.Index
  192. if _, ok := zc.toName[ifi.Index]; !ok {
  193. zc.toName[ifi.Index] = ifi.Name
  194. }
  195. }
  196. return true
  197. }
  198. func (zc *ipv6ZoneCache) name(index int) string {
  199. if index == 0 {
  200. return ""
  201. }
  202. updated := zoneCache.update(nil, false)
  203. zoneCache.RLock()
  204. name, ok := zoneCache.toName[index]
  205. zoneCache.RUnlock()
  206. if !ok && !updated {
  207. zoneCache.update(nil, true)
  208. zoneCache.RLock()
  209. name, ok = zoneCache.toName[index]
  210. zoneCache.RUnlock()
  211. }
  212. if !ok { // last resort
  213. name = itoa.Uitoa(uint(index))
  214. }
  215. return name
  216. }
  217. func (zc *ipv6ZoneCache) index(name string) int {
  218. if name == "" {
  219. return 0
  220. }
  221. updated := zoneCache.update(nil, false)
  222. zoneCache.RLock()
  223. index, ok := zoneCache.toIndex[name]
  224. zoneCache.RUnlock()
  225. if !ok && !updated {
  226. zoneCache.update(nil, true)
  227. zoneCache.RLock()
  228. index, ok = zoneCache.toIndex[name]
  229. zoneCache.RUnlock()
  230. }
  231. if !ok { // last resort
  232. index, _, _ = dtoi(name)
  233. }
  234. return index
  235. }