You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

94 lines
2.1 KiB

  1. // Copyright 2012 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 nettest
  5. import "net"
  6. // IsMulticastCapable reports whether ifi is an IP multicast-capable
  7. // network interface. Network must be "ip", "ip4" or "ip6".
  8. func IsMulticastCapable(network string, ifi *net.Interface) (net.IP, bool) {
  9. switch network {
  10. case "ip", "ip4", "ip6":
  11. default:
  12. return nil, false
  13. }
  14. if ifi == nil || ifi.Flags&net.FlagUp == 0 || ifi.Flags&net.FlagMulticast == 0 {
  15. return nil, false
  16. }
  17. return hasRoutableIP(network, ifi)
  18. }
  19. // RoutedInterface returns a network interface that can route IP
  20. // traffic and satisfies flags. It returns nil when an appropriate
  21. // network interface is not found. Network must be "ip", "ip4" or
  22. // "ip6".
  23. func RoutedInterface(network string, flags net.Flags) *net.Interface {
  24. switch network {
  25. case "ip", "ip4", "ip6":
  26. default:
  27. return nil
  28. }
  29. ift, err := net.Interfaces()
  30. if err != nil {
  31. return nil
  32. }
  33. for _, ifi := range ift {
  34. if ifi.Flags&flags != flags {
  35. continue
  36. }
  37. if _, ok := hasRoutableIP(network, &ifi); !ok {
  38. continue
  39. }
  40. return &ifi
  41. }
  42. return nil
  43. }
  44. func hasRoutableIP(network string, ifi *net.Interface) (net.IP, bool) {
  45. ifat, err := ifi.Addrs()
  46. if err != nil {
  47. return nil, false
  48. }
  49. for _, ifa := range ifat {
  50. switch ifa := ifa.(type) {
  51. case *net.IPAddr:
  52. if ip := routableIP(network, ifa.IP); ip != nil {
  53. return ip, true
  54. }
  55. case *net.IPNet:
  56. if ip := routableIP(network, ifa.IP); ip != nil {
  57. return ip, true
  58. }
  59. }
  60. }
  61. return nil, false
  62. }
  63. func routableIP(network string, ip net.IP) net.IP {
  64. if !ip.IsLoopback() && !ip.IsLinkLocalUnicast() && !ip.IsGlobalUnicast() {
  65. return nil
  66. }
  67. switch network {
  68. case "ip4":
  69. if ip := ip.To4(); ip != nil {
  70. return ip
  71. }
  72. case "ip6":
  73. if ip.IsLoopback() { // addressing scope of the loopback address depends on each implementation
  74. return nil
  75. }
  76. if ip := ip.To16(); ip != nil && ip.To4() == nil {
  77. return ip
  78. }
  79. default:
  80. if ip := ip.To4(); ip != nil {
  81. return ip
  82. }
  83. if ip := ip.To16(); ip != nil {
  84. return ip
  85. }
  86. }
  87. return nil
  88. }