interface_test.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  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. //go:build !js
  5. package net
  6. import (
  7. "fmt"
  8. "reflect"
  9. "runtime"
  10. "testing"
  11. )
  12. // loopbackInterface returns an available logical network interface
  13. // for loopback tests. It returns nil if no suitable interface is
  14. // found.
  15. func loopbackInterface() *Interface {
  16. ift, err := Interfaces()
  17. if err != nil {
  18. return nil
  19. }
  20. for _, ifi := range ift {
  21. if ifi.Flags&FlagLoopback != 0 && ifi.Flags&FlagUp != 0 {
  22. return &ifi
  23. }
  24. }
  25. return nil
  26. }
  27. // ipv6LinkLocalUnicastAddr returns an IPv6 link-local unicast address
  28. // on the given network interface for tests. It returns "" if no
  29. // suitable address is found.
  30. func ipv6LinkLocalUnicastAddr(ifi *Interface) string {
  31. if ifi == nil {
  32. return ""
  33. }
  34. ifat, err := ifi.Addrs()
  35. if err != nil {
  36. return ""
  37. }
  38. for _, ifa := range ifat {
  39. if ifa, ok := ifa.(*IPNet); ok {
  40. if ifa.IP.To4() == nil && ifa.IP.IsLinkLocalUnicast() {
  41. return ifa.IP.String()
  42. }
  43. }
  44. }
  45. return ""
  46. }
  47. func TestInterfaces(t *testing.T) {
  48. ift, err := Interfaces()
  49. if err != nil {
  50. t.Fatal(err)
  51. }
  52. for _, ifi := range ift {
  53. ifxi, err := InterfaceByIndex(ifi.Index)
  54. if err != nil {
  55. t.Fatal(err)
  56. }
  57. switch runtime.GOOS {
  58. case "solaris", "illumos":
  59. if ifxi.Index != ifi.Index {
  60. t.Errorf("got %v; want %v", ifxi, ifi)
  61. }
  62. default:
  63. if !reflect.DeepEqual(ifxi, &ifi) {
  64. t.Errorf("got %v; want %v", ifxi, ifi)
  65. }
  66. }
  67. ifxn, err := InterfaceByName(ifi.Name)
  68. if err != nil {
  69. t.Fatal(err)
  70. }
  71. if !reflect.DeepEqual(ifxn, &ifi) {
  72. t.Errorf("got %v; want %v", ifxn, ifi)
  73. }
  74. t.Logf("%s: flags=%v index=%d mtu=%d hwaddr=%v", ifi.Name, ifi.Flags, ifi.Index, ifi.MTU, ifi.HardwareAddr)
  75. }
  76. }
  77. func TestInterfaceAddrs(t *testing.T) {
  78. ift, err := Interfaces()
  79. if err != nil {
  80. t.Fatal(err)
  81. }
  82. ifStats := interfaceStats(ift)
  83. ifat, err := InterfaceAddrs()
  84. if err != nil {
  85. t.Fatal(err)
  86. }
  87. uniStats, err := validateInterfaceUnicastAddrs(ifat)
  88. if err != nil {
  89. t.Fatal(err)
  90. }
  91. if err := checkUnicastStats(ifStats, uniStats); err != nil {
  92. t.Fatal(err)
  93. }
  94. }
  95. func TestInterfaceUnicastAddrs(t *testing.T) {
  96. ift, err := Interfaces()
  97. if err != nil {
  98. t.Fatal(err)
  99. }
  100. ifStats := interfaceStats(ift)
  101. if err != nil {
  102. t.Fatal(err)
  103. }
  104. var uniStats routeStats
  105. for _, ifi := range ift {
  106. ifat, err := ifi.Addrs()
  107. if err != nil {
  108. t.Fatal(ifi, err)
  109. }
  110. stats, err := validateInterfaceUnicastAddrs(ifat)
  111. if err != nil {
  112. t.Fatal(ifi, err)
  113. }
  114. uniStats.ipv4 += stats.ipv4
  115. uniStats.ipv6 += stats.ipv6
  116. }
  117. if err := checkUnicastStats(ifStats, &uniStats); err != nil {
  118. t.Fatal(err)
  119. }
  120. }
  121. func TestInterfaceMulticastAddrs(t *testing.T) {
  122. ift, err := Interfaces()
  123. if err != nil {
  124. t.Fatal(err)
  125. }
  126. ifStats := interfaceStats(ift)
  127. ifat, err := InterfaceAddrs()
  128. if err != nil {
  129. t.Fatal(err)
  130. }
  131. uniStats, err := validateInterfaceUnicastAddrs(ifat)
  132. if err != nil {
  133. t.Fatal(err)
  134. }
  135. var multiStats routeStats
  136. for _, ifi := range ift {
  137. ifmat, err := ifi.MulticastAddrs()
  138. if err != nil {
  139. t.Fatal(ifi, err)
  140. }
  141. stats, err := validateInterfaceMulticastAddrs(ifmat)
  142. if err != nil {
  143. t.Fatal(ifi, err)
  144. }
  145. multiStats.ipv4 += stats.ipv4
  146. multiStats.ipv6 += stats.ipv6
  147. }
  148. if err := checkMulticastStats(ifStats, uniStats, &multiStats); err != nil {
  149. t.Fatal(err)
  150. }
  151. }
  152. type ifStats struct {
  153. loop int // # of active loopback interfaces
  154. other int // # of active other interfaces
  155. }
  156. func interfaceStats(ift []Interface) *ifStats {
  157. var stats ifStats
  158. for _, ifi := range ift {
  159. if ifi.Flags&FlagUp != 0 {
  160. if ifi.Flags&FlagLoopback != 0 {
  161. stats.loop++
  162. } else {
  163. stats.other++
  164. }
  165. }
  166. }
  167. return &stats
  168. }
  169. type routeStats struct {
  170. ipv4, ipv6 int // # of active connected unicast, anycast or multicast routes
  171. }
  172. func validateInterfaceUnicastAddrs(ifat []Addr) (*routeStats, error) {
  173. // Note: BSD variants allow assigning any IPv4/IPv6 address
  174. // prefix to IP interface. For example,
  175. // - 0.0.0.0/0 through 255.255.255.255/32
  176. // - ::/0 through ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128
  177. // In other words, there is no tightly-coupled combination of
  178. // interface address prefixes and connected routes.
  179. stats := new(routeStats)
  180. for _, ifa := range ifat {
  181. switch ifa := ifa.(type) {
  182. case *IPNet:
  183. if ifa == nil || ifa.IP == nil || ifa.IP.IsMulticast() || ifa.Mask == nil {
  184. return nil, fmt.Errorf("unexpected value: %#v", ifa)
  185. }
  186. if len(ifa.IP) != IPv6len {
  187. return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa)
  188. }
  189. prefixLen, maxPrefixLen := ifa.Mask.Size()
  190. if ifa.IP.To4() != nil {
  191. if 0 >= prefixLen || prefixLen > 8*IPv4len || maxPrefixLen != 8*IPv4len {
  192. return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa)
  193. }
  194. if ifa.IP.IsLoopback() && prefixLen < 8 { // see RFC 1122
  195. return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa)
  196. }
  197. stats.ipv4++
  198. }
  199. if ifa.IP.To16() != nil && ifa.IP.To4() == nil {
  200. if 0 >= prefixLen || prefixLen > 8*IPv6len || maxPrefixLen != 8*IPv6len {
  201. return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa)
  202. }
  203. if ifa.IP.IsLoopback() && prefixLen != 8*IPv6len { // see RFC 4291
  204. return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa)
  205. }
  206. stats.ipv6++
  207. }
  208. case *IPAddr:
  209. if ifa == nil || ifa.IP == nil || ifa.IP.IsMulticast() {
  210. return nil, fmt.Errorf("unexpected value: %#v", ifa)
  211. }
  212. if len(ifa.IP) != IPv6len {
  213. return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa)
  214. }
  215. if ifa.IP.To4() != nil {
  216. stats.ipv4++
  217. }
  218. if ifa.IP.To16() != nil && ifa.IP.To4() == nil {
  219. stats.ipv6++
  220. }
  221. default:
  222. return nil, fmt.Errorf("unexpected type: %T", ifa)
  223. }
  224. }
  225. return stats, nil
  226. }
  227. func validateInterfaceMulticastAddrs(ifat []Addr) (*routeStats, error) {
  228. stats := new(routeStats)
  229. for _, ifa := range ifat {
  230. switch ifa := ifa.(type) {
  231. case *IPAddr:
  232. if ifa == nil || ifa.IP == nil || ifa.IP.IsUnspecified() || !ifa.IP.IsMulticast() {
  233. return nil, fmt.Errorf("unexpected value: %#v", ifa)
  234. }
  235. if len(ifa.IP) != IPv6len {
  236. return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa)
  237. }
  238. if ifa.IP.To4() != nil {
  239. stats.ipv4++
  240. }
  241. if ifa.IP.To16() != nil && ifa.IP.To4() == nil {
  242. stats.ipv6++
  243. }
  244. default:
  245. return nil, fmt.Errorf("unexpected type: %T", ifa)
  246. }
  247. }
  248. return stats, nil
  249. }
  250. func checkUnicastStats(ifStats *ifStats, uniStats *routeStats) error {
  251. // Test the existence of connected unicast routes for IPv4.
  252. if supportsIPv4() && ifStats.loop+ifStats.other > 0 && uniStats.ipv4 == 0 {
  253. return fmt.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v, %+v", ifStats, uniStats)
  254. }
  255. // Test the existence of connected unicast routes for IPv6.
  256. // We can assume the existence of ::1/128 when at least one
  257. // loopback interface is installed.
  258. if supportsIPv6() && ifStats.loop > 0 && uniStats.ipv6 == 0 {
  259. return fmt.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v, %+v", ifStats, uniStats)
  260. }
  261. return nil
  262. }
  263. func checkMulticastStats(ifStats *ifStats, uniStats, multiStats *routeStats) error {
  264. switch runtime.GOOS {
  265. case "aix", "dragonfly", "netbsd", "openbsd", "plan9", "solaris", "illumos":
  266. default:
  267. // Test the existence of connected multicast route
  268. // clones for IPv4. Unlike IPv6, IPv4 multicast
  269. // capability is not a mandatory feature, and so IPv4
  270. // multicast validation is ignored and we only check
  271. // IPv6 below.
  272. //
  273. // Test the existence of connected multicast route
  274. // clones for IPv6. Some platform never uses loopback
  275. // interface as the nexthop for multicast routing.
  276. // We can assume the existence of connected multicast
  277. // route clones when at least two connected unicast
  278. // routes, ::1/128 and other, are installed.
  279. if supportsIPv6() && ifStats.loop > 0 && uniStats.ipv6 > 1 && multiStats.ipv6 == 0 {
  280. return fmt.Errorf("num IPv6 multicast route clones = 0; want >0; summary: %+v, %+v, %+v", ifStats, uniStats, multiStats)
  281. }
  282. }
  283. return nil
  284. }
  285. func BenchmarkInterfaces(b *testing.B) {
  286. testHookUninstaller.Do(uninstallTestHooks)
  287. for i := 0; i < b.N; i++ {
  288. if _, err := Interfaces(); err != nil {
  289. b.Fatal(err)
  290. }
  291. }
  292. }
  293. func BenchmarkInterfaceByIndex(b *testing.B) {
  294. testHookUninstaller.Do(uninstallTestHooks)
  295. ifi := loopbackInterface()
  296. if ifi == nil {
  297. b.Skip("loopback interface not found")
  298. }
  299. for i := 0; i < b.N; i++ {
  300. if _, err := InterfaceByIndex(ifi.Index); err != nil {
  301. b.Fatal(err)
  302. }
  303. }
  304. }
  305. func BenchmarkInterfaceByName(b *testing.B) {
  306. testHookUninstaller.Do(uninstallTestHooks)
  307. ifi := loopbackInterface()
  308. if ifi == nil {
  309. b.Skip("loopback interface not found")
  310. }
  311. for i := 0; i < b.N; i++ {
  312. if _, err := InterfaceByName(ifi.Name); err != nil {
  313. b.Fatal(err)
  314. }
  315. }
  316. }
  317. func BenchmarkInterfaceAddrs(b *testing.B) {
  318. testHookUninstaller.Do(uninstallTestHooks)
  319. for i := 0; i < b.N; i++ {
  320. if _, err := InterfaceAddrs(); err != nil {
  321. b.Fatal(err)
  322. }
  323. }
  324. }
  325. func BenchmarkInterfacesAndAddrs(b *testing.B) {
  326. testHookUninstaller.Do(uninstallTestHooks)
  327. ifi := loopbackInterface()
  328. if ifi == nil {
  329. b.Skip("loopback interface not found")
  330. }
  331. for i := 0; i < b.N; i++ {
  332. if _, err := ifi.Addrs(); err != nil {
  333. b.Fatal(err)
  334. }
  335. }
  336. }
  337. func BenchmarkInterfacesAndMulticastAddrs(b *testing.B) {
  338. testHookUninstaller.Do(uninstallTestHooks)
  339. ifi := loopbackInterface()
  340. if ifi == nil {
  341. b.Skip("loopback interface not found")
  342. }
  343. for i := 0; i < b.N; i++ {
  344. if _, err := ifi.MulticastAddrs(); err != nil {
  345. b.Fatal(err)
  346. }
  347. }
  348. }