util.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. package ice
  2. import (
  3. "fmt"
  4. "net"
  5. "sync/atomic"
  6. "time"
  7. "github.com/pion/logging"
  8. "github.com/pion/stun"
  9. "github.com/pion/transport/vnet"
  10. )
  11. type atomicError struct{ v atomic.Value }
  12. func (a *atomicError) Store(err error) {
  13. a.v.Store(struct{ error }{err})
  14. }
  15. func (a *atomicError) Load() error {
  16. err, _ := a.v.Load().(struct{ error })
  17. return err.error
  18. }
  19. // The conditions of invalidation written below are defined in
  20. // https://tools.ietf.org/html/rfc8445#section-5.1.1.1
  21. func isSupportedIPv6(ip net.IP) bool {
  22. if len(ip) != net.IPv6len ||
  23. isZeros(ip[0:12]) || // !(IPv4-compatible IPv6)
  24. ip[0] == 0xfe && ip[1]&0xc0 == 0xc0 || // !(IPv6 site-local unicast)
  25. ip.IsLinkLocalUnicast() ||
  26. ip.IsLinkLocalMulticast() {
  27. return false
  28. }
  29. return true
  30. }
  31. func isZeros(ip net.IP) bool {
  32. for i := 0; i < len(ip); i++ {
  33. if ip[i] != 0 {
  34. return false
  35. }
  36. }
  37. return true
  38. }
  39. func parseAddr(in net.Addr) (net.IP, int, NetworkType, bool) {
  40. switch addr := in.(type) {
  41. case *net.UDPAddr:
  42. return addr.IP, addr.Port, NetworkTypeUDP4, true
  43. case *net.TCPAddr:
  44. return addr.IP, addr.Port, NetworkTypeTCP4, true
  45. }
  46. return nil, 0, 0, false
  47. }
  48. func createAddr(network NetworkType, ip net.IP, port int) net.Addr {
  49. switch {
  50. case network.IsTCP():
  51. return &net.TCPAddr{IP: ip, Port: port}
  52. default:
  53. return &net.UDPAddr{IP: ip, Port: port}
  54. }
  55. }
  56. func addrEqual(a, b net.Addr) bool {
  57. aIP, aPort, aType, aOk := parseAddr(a)
  58. if !aOk {
  59. return false
  60. }
  61. bIP, bPort, bType, bOk := parseAddr(b)
  62. if !bOk {
  63. return false
  64. }
  65. return aType == bType && aIP.Equal(bIP) && aPort == bPort
  66. }
  67. // getXORMappedAddr initiates a stun requests to serverAddr using conn, reads the response and returns
  68. // the XORMappedAddress returned by the stun server.
  69. //
  70. // Adapted from stun v0.2.
  71. func getXORMappedAddr(conn net.PacketConn, serverAddr net.Addr, deadline time.Duration) (*stun.XORMappedAddress, error) {
  72. if deadline > 0 {
  73. if err := conn.SetReadDeadline(time.Now().Add(deadline)); err != nil {
  74. return nil, err
  75. }
  76. }
  77. defer func() {
  78. if deadline > 0 {
  79. _ = conn.SetReadDeadline(time.Time{})
  80. }
  81. }()
  82. resp, err := stunRequest(
  83. func(p []byte) (int, error) {
  84. n, _, errr := conn.ReadFrom(p)
  85. return n, errr
  86. },
  87. func(b []byte) (int, error) {
  88. return conn.WriteTo(b, serverAddr)
  89. },
  90. )
  91. if err != nil {
  92. return nil, err
  93. }
  94. var addr stun.XORMappedAddress
  95. if err = addr.GetFrom(resp); err != nil {
  96. return nil, fmt.Errorf("%w: %v", errGetXorMappedAddrResponse, err)
  97. }
  98. return &addr, nil
  99. }
  100. func stunRequest(read func([]byte) (int, error), write func([]byte) (int, error)) (*stun.Message, error) {
  101. req, err := stun.Build(stun.BindingRequest, stun.TransactionID)
  102. if err != nil {
  103. return nil, err
  104. }
  105. if _, err = write(req.Raw); err != nil {
  106. return nil, err
  107. }
  108. const maxMessageSize = 1280
  109. bs := make([]byte, maxMessageSize)
  110. n, err := read(bs)
  111. if err != nil {
  112. return nil, err
  113. }
  114. res := &stun.Message{Raw: bs[:n]}
  115. if err := res.Decode(); err != nil {
  116. return nil, err
  117. }
  118. return res, nil
  119. }
  120. func localInterfaces(vnet *vnet.Net, interfaceFilter func(string) bool, networkTypes []NetworkType) ([]net.IP, error) { //nolint:gocognit
  121. ips := []net.IP{}
  122. ifaces, err := vnet.Interfaces()
  123. if err != nil {
  124. return ips, err
  125. }
  126. var IPv4Requested, IPv6Requested bool
  127. for _, typ := range networkTypes {
  128. if typ.IsIPv4() {
  129. IPv4Requested = true
  130. }
  131. if typ.IsIPv6() {
  132. IPv6Requested = true
  133. }
  134. }
  135. for _, iface := range ifaces {
  136. if iface.Flags&net.FlagUp == 0 {
  137. continue // interface down
  138. }
  139. if iface.Flags&net.FlagLoopback != 0 {
  140. continue // loopback interface
  141. }
  142. if interfaceFilter != nil && !interfaceFilter(iface.Name) {
  143. continue
  144. }
  145. addrs, err := iface.Addrs()
  146. if err != nil {
  147. continue
  148. }
  149. for _, addr := range addrs {
  150. var ip net.IP
  151. switch addr := addr.(type) {
  152. case *net.IPNet:
  153. ip = addr.IP
  154. case *net.IPAddr:
  155. ip = addr.IP
  156. }
  157. if ip == nil || ip.IsLoopback() {
  158. continue
  159. }
  160. if ipv4 := ip.To4(); ipv4 == nil {
  161. if !IPv6Requested {
  162. continue
  163. } else if !isSupportedIPv6(ip) {
  164. continue
  165. }
  166. } else if !IPv4Requested {
  167. continue
  168. }
  169. ips = append(ips, ip)
  170. }
  171. }
  172. return ips, nil
  173. }
  174. func listenUDPInPortRange(vnet *vnet.Net, log logging.LeveledLogger, portMax, portMin int, network string, laddr *net.UDPAddr) (vnet.UDPPacketConn, error) {
  175. if (laddr.Port != 0) || ((portMin == 0) && (portMax == 0)) {
  176. return vnet.ListenUDP(network, laddr)
  177. }
  178. var i, j int
  179. i = portMin
  180. if i == 0 {
  181. i = 1
  182. }
  183. j = portMax
  184. if j == 0 {
  185. j = 0xFFFF
  186. }
  187. if i > j {
  188. return nil, ErrPort
  189. }
  190. portStart := globalMathRandomGenerator.Intn(j-i+1) + i
  191. portCurrent := portStart
  192. for {
  193. laddr = &net.UDPAddr{IP: laddr.IP, Port: portCurrent}
  194. c, e := vnet.ListenUDP(network, laddr)
  195. if e == nil {
  196. return c, e
  197. }
  198. log.Debugf("failed to listen %s: %v", laddr.String(), e)
  199. portCurrent++
  200. if portCurrent > j {
  201. portCurrent = i
  202. }
  203. if portCurrent == portStart {
  204. break
  205. }
  206. }
  207. return nil, ErrPort
  208. }