1
0

discover.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // Copyright 2013, Cong Ding. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. //
  15. // Author: Cong Ding <dinggnu@gmail.com>
  16. package stun
  17. import (
  18. "errors"
  19. "net"
  20. )
  21. // Follow RFC 3489 and RFC 5389.
  22. // Figure 2: Flow for type discovery process (from RFC 3489).
  23. // +--------+
  24. // | Test |
  25. // | I |
  26. // +--------+
  27. // |
  28. // |
  29. // V
  30. // /\ /\
  31. // N / \ Y / \ Y +--------+
  32. // UDP <-------/Resp\--------->/ IP \------------->| Test |
  33. // Blocked \ ? / \Same/ | II |
  34. // \ / \? / +--------+
  35. // \/ \/ |
  36. // | N |
  37. // | V
  38. // V /\
  39. // +--------+ Sym. N / \
  40. // | Test | UDP <---/Resp\
  41. // | II | Firewall \ ? /
  42. // +--------+ \ /
  43. // | \/
  44. // V |Y
  45. // /\ /\ |
  46. // Symmetric N / \ +--------+ N / \ V
  47. // NAT <--- / IP \<-----| Test |<--- /Resp\ Open
  48. // \Same/ | I | \ ? / Internet
  49. // \? / +--------+ \ /
  50. // \/ \/
  51. // |Y |Y
  52. // | |
  53. // | V
  54. // | Full
  55. // | Cone
  56. // V /\
  57. // +--------+ / \ Y
  58. // | Test |------>/Resp\---->Restricted
  59. // | III | \ ? /
  60. // +--------+ \ /
  61. // \/
  62. // |N
  63. // | Port
  64. // +------>Restricted
  65. func (c *Client) discover(conn net.PacketConn, addr *net.UDPAddr) (NATType, *Host, error) {
  66. // Perform test1 to check if it is under NAT.
  67. c.logger.Debugln("Do Test1")
  68. c.logger.Debugln("Send To:", addr)
  69. resp, err := c.test1(conn, addr)
  70. if err != nil {
  71. return NATError, nil, err
  72. }
  73. c.logger.Debugln("Received:", resp)
  74. if resp == nil {
  75. return NATBlocked, nil, nil
  76. }
  77. // identical used to check if it is open Internet or not.
  78. identical := resp.identical
  79. // changedAddr is used to perform second time test1 and test3.
  80. changedAddr := resp.changedAddr
  81. // mappedAddr is used as the return value, its IP is used for tests
  82. mappedAddr := resp.mappedAddr
  83. // Make sure IP and port are not changed.
  84. if resp.serverAddr.IP() != addr.IP.String() ||
  85. resp.serverAddr.Port() != uint16(addr.Port) {
  86. return NATError, mappedAddr, errors.New("Server error: response IP/port")
  87. }
  88. // if changedAddr is not available, use otherAddr as changedAddr,
  89. // which is updated in RFC 5780
  90. if changedAddr == nil {
  91. changedAddr = resp.otherAddr
  92. }
  93. // changedAddr shall not be nil
  94. if changedAddr == nil {
  95. return NATError, mappedAddr, errors.New("Server error: no changed address.")
  96. }
  97. // Perform test2 to see if the client can receive packet sent from
  98. // another IP and port.
  99. c.logger.Debugln("Do Test2")
  100. c.logger.Debugln("Send To:", addr)
  101. resp, err = c.test2(conn, addr)
  102. if err != nil {
  103. return NATError, mappedAddr, err
  104. }
  105. c.logger.Debugln("Received:", resp)
  106. // Make sure IP and port are changed.
  107. if resp != nil &&
  108. (resp.serverAddr.IP() == addr.IP.String() ||
  109. resp.serverAddr.Port() == uint16(addr.Port)) {
  110. return NATError, mappedAddr, errors.New("Server error: response IP/port")
  111. }
  112. if identical {
  113. if resp == nil {
  114. return NATSymmetricUDPFirewall, mappedAddr, nil
  115. }
  116. return NATNone, mappedAddr, nil
  117. }
  118. if resp != nil {
  119. return NATFull, mappedAddr, nil
  120. }
  121. // Perform test1 to another IP and port to see if the NAT use the same
  122. // external IP.
  123. c.logger.Debugln("Do Test1")
  124. c.logger.Debugln("Send To:", changedAddr)
  125. caddr, err := net.ResolveUDPAddr("udp", changedAddr.String())
  126. if err != nil {
  127. c.logger.Debugf("ResolveUDPAddr error: %v", err)
  128. }
  129. resp, err = c.test1(conn, caddr)
  130. if err != nil {
  131. return NATError, mappedAddr, err
  132. }
  133. c.logger.Debugln("Received:", resp)
  134. if resp == nil {
  135. // It should be NAT_BLOCKED, but will be detected in the first
  136. // step. So this will never happen.
  137. return NATUnknown, mappedAddr, nil
  138. }
  139. // Make sure IP/port is not changed.
  140. if resp.serverAddr.IP() != caddr.IP.String() ||
  141. resp.serverAddr.Port() != uint16(caddr.Port) {
  142. return NATError, mappedAddr, errors.New("Server error: response IP/port")
  143. }
  144. if mappedAddr.IP() == resp.mappedAddr.IP() && mappedAddr.Port() == resp.mappedAddr.Port() {
  145. // Perform test3 to see if the client can receive packet sent
  146. // from another port.
  147. c.logger.Debugln("Do Test3")
  148. c.logger.Debugln("Send To:", caddr)
  149. resp, err = c.test3(conn, caddr)
  150. if err != nil {
  151. return NATError, mappedAddr, err
  152. }
  153. c.logger.Debugln("Received:", resp)
  154. if resp == nil {
  155. return NATPortRestricted, mappedAddr, nil
  156. }
  157. // Make sure IP is not changed, and port is changed.
  158. if resp.serverAddr.IP() != caddr.IP.String() ||
  159. resp.serverAddr.Port() == uint16(caddr.Port) {
  160. return NATError, mappedAddr, errors.New("Server error: response IP/port")
  161. }
  162. return NATRestricted, mappedAddr, nil
  163. }
  164. return NATSymmetric, mappedAddr, nil
  165. }