external_ip_mapper_test.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. package ice
  4. import (
  5. "net"
  6. "testing"
  7. "github.com/stretchr/testify/assert"
  8. )
  9. func TestExternalIPMapper(t *testing.T) {
  10. t.Run("validateIPString", func(t *testing.T) {
  11. var ip net.IP
  12. var isIPv4 bool
  13. var err error
  14. ip, isIPv4, err = validateIPString("1.2.3.4")
  15. assert.NoError(t, err, "should succeed")
  16. assert.True(t, isIPv4, "should be true")
  17. assert.Equal(t, "1.2.3.4", ip.String(), "should be true")
  18. ip, isIPv4, err = validateIPString("2601:4567::5678")
  19. assert.NoError(t, err, "should succeed")
  20. assert.False(t, isIPv4, "should be false")
  21. assert.Equal(t, "2601:4567::5678", ip.String(), "should be true")
  22. _, _, err = validateIPString("bad.6.6.6")
  23. assert.Error(t, err, "should fail")
  24. })
  25. t.Run("newExternalIPMapper", func(t *testing.T) {
  26. var m *externalIPMapper
  27. var err error
  28. // ips being nil should succeed but mapper will be nil also
  29. m, err = newExternalIPMapper(CandidateTypeUnspecified, nil)
  30. assert.NoError(t, err, "should succeed")
  31. assert.Nil(t, m, "should be nil")
  32. // ips being empty should succeed but mapper will still be nil
  33. m, err = newExternalIPMapper(CandidateTypeUnspecified, []string{})
  34. assert.NoError(t, err, "should succeed")
  35. assert.Nil(t, m, "should be nil")
  36. // IPv4 with no explicit local IP, defaults to CandidateTypeHost
  37. m, err = newExternalIPMapper(CandidateTypeUnspecified, []string{
  38. "1.2.3.4",
  39. })
  40. assert.NoError(t, err, "should succeed")
  41. assert.NotNil(t, m, "should not be nil")
  42. assert.Equal(t, CandidateTypeHost, m.candidateType, "should match")
  43. assert.NotNil(t, m.ipv4Mapping.ipSole)
  44. assert.Nil(t, m.ipv6Mapping.ipSole)
  45. assert.Equal(t, 0, len(m.ipv4Mapping.ipMap), "should match")
  46. assert.Equal(t, 0, len(m.ipv6Mapping.ipMap), "should match")
  47. // IPv4 with no explicit local IP, using CandidateTypeServerReflexive
  48. m, err = newExternalIPMapper(CandidateTypeServerReflexive, []string{
  49. "1.2.3.4",
  50. })
  51. assert.NoError(t, err, "should succeed")
  52. assert.NotNil(t, m, "should not be nil")
  53. assert.Equal(t, CandidateTypeServerReflexive, m.candidateType, "should match")
  54. assert.NotNil(t, m.ipv4Mapping.ipSole)
  55. assert.Nil(t, m.ipv6Mapping.ipSole)
  56. assert.Equal(t, 0, len(m.ipv4Mapping.ipMap), "should match")
  57. assert.Equal(t, 0, len(m.ipv6Mapping.ipMap), "should match")
  58. // IPv4 with no explicit local IP, defaults to CandidateTypeHost
  59. m, err = newExternalIPMapper(CandidateTypeUnspecified, []string{
  60. "2601:4567::5678",
  61. })
  62. assert.NoError(t, err, "should succeed")
  63. assert.NotNil(t, m, "should not be nil")
  64. assert.Equal(t, CandidateTypeHost, m.candidateType, "should match")
  65. assert.Nil(t, m.ipv4Mapping.ipSole)
  66. assert.NotNil(t, m.ipv6Mapping.ipSole)
  67. assert.Equal(t, 0, len(m.ipv4Mapping.ipMap), "should match")
  68. assert.Equal(t, 0, len(m.ipv6Mapping.ipMap), "should match")
  69. // IPv4 and IPv6 in the mix
  70. m, err = newExternalIPMapper(CandidateTypeUnspecified, []string{
  71. "1.2.3.4",
  72. "2601:4567::5678",
  73. })
  74. assert.NoError(t, err, "should succeed")
  75. assert.NotNil(t, m, "should not be nil")
  76. assert.Equal(t, CandidateTypeHost, m.candidateType, "should match")
  77. assert.NotNil(t, m.ipv4Mapping.ipSole)
  78. assert.NotNil(t, m.ipv6Mapping.ipSole)
  79. assert.Equal(t, 0, len(m.ipv4Mapping.ipMap), "should match")
  80. assert.Equal(t, 0, len(m.ipv6Mapping.ipMap), "should match")
  81. // Unsupported candidate type - CandidateTypePeerReflexive
  82. m, err = newExternalIPMapper(CandidateTypePeerReflexive, []string{
  83. "1.2.3.4",
  84. })
  85. assert.Error(t, err, "should fail")
  86. assert.Nil(t, m, "should be nil")
  87. // Unsupported candidate type - CandidateTypeRelay
  88. m, err = newExternalIPMapper(CandidateTypePeerReflexive, []string{
  89. "1.2.3.4",
  90. })
  91. assert.Error(t, err, "should fail")
  92. assert.Nil(t, m, "should be nil")
  93. // Cannot duplicate mapping IPv4 family
  94. m, err = newExternalIPMapper(CandidateTypeServerReflexive, []string{
  95. "1.2.3.4",
  96. "5.6.7.8",
  97. })
  98. assert.Error(t, err, "should fail")
  99. assert.Nil(t, m, "should be nil")
  100. // Cannot duplicate mapping IPv6 family
  101. m, err = newExternalIPMapper(CandidateTypeServerReflexive, []string{
  102. "2201::1",
  103. "2201::0002",
  104. })
  105. assert.Error(t, err, "should fail")
  106. assert.Nil(t, m, "should be nil")
  107. // Invalide external IP string
  108. m, err = newExternalIPMapper(CandidateTypeServerReflexive, []string{
  109. "bad.2.3.4",
  110. })
  111. assert.Error(t, err, "should fail")
  112. assert.Nil(t, m, "should be nil")
  113. // Invalide local IP string
  114. m, err = newExternalIPMapper(CandidateTypeServerReflexive, []string{
  115. "1.2.3.4/10.0.0.bad",
  116. })
  117. assert.Error(t, err, "should fail")
  118. assert.Nil(t, m, "should be nil")
  119. })
  120. t.Run("newExternalIPMapper with explicit local IP", func(t *testing.T) {
  121. var m *externalIPMapper
  122. var err error
  123. // IPv4 with explicit local IP, defaults to CandidateTypeHost
  124. m, err = newExternalIPMapper(CandidateTypeUnspecified, []string{
  125. "1.2.3.4/10.0.0.1",
  126. })
  127. assert.NoError(t, err, "should succeed")
  128. assert.NotNil(t, m, "should not be nil")
  129. assert.Equal(t, CandidateTypeHost, m.candidateType, "should match")
  130. assert.Nil(t, m.ipv4Mapping.ipSole)
  131. assert.Nil(t, m.ipv6Mapping.ipSole)
  132. assert.Equal(t, 1, len(m.ipv4Mapping.ipMap), "should match")
  133. assert.Equal(t, 0, len(m.ipv6Mapping.ipMap), "should match")
  134. // Cannot assign two ext IPs for one local IPv4
  135. m, err = newExternalIPMapper(CandidateTypeUnspecified, []string{
  136. "1.2.3.4/10.0.0.1",
  137. "1.2.3.5/10.0.0.1",
  138. })
  139. assert.Error(t, err, "should fail")
  140. assert.Nil(t, m, "should be nil")
  141. // Cannot assign two ext IPs for one local IPv6
  142. m, err = newExternalIPMapper(CandidateTypeUnspecified, []string{
  143. "2200::1/fe80::1",
  144. "2200::0002/fe80::1",
  145. })
  146. assert.Error(t, err, "should fail")
  147. assert.Nil(t, m, "should be nil")
  148. // Cannot mix different IP family in a pair (1)
  149. m, err = newExternalIPMapper(CandidateTypeUnspecified, []string{
  150. "2200::1/10.0.0.1",
  151. })
  152. assert.Error(t, err, "should fail")
  153. assert.Nil(t, m, "should be nil")
  154. // Cannot mix different IP family in a pair (2)
  155. m, err = newExternalIPMapper(CandidateTypeUnspecified, []string{
  156. "1.2.3.4/fe80::1",
  157. })
  158. assert.Error(t, err, "should fail")
  159. assert.Nil(t, m, "should be nil")
  160. // Invalid pair
  161. m, err = newExternalIPMapper(CandidateTypeUnspecified, []string{
  162. "1.2.3.4/192.168.0.2/10.0.0.1",
  163. })
  164. assert.Error(t, err, "should fail")
  165. assert.Nil(t, m, "should be nil")
  166. })
  167. t.Run("newExternalIPMapper with implicit and explicit local IP", func(t *testing.T) {
  168. // Mixing implicit and explicit local IPs not allowed
  169. _, err := newExternalIPMapper(CandidateTypeUnspecified, []string{
  170. "1.2.3.4",
  171. "1.2.3.5/10.0.0.1",
  172. })
  173. assert.Error(t, err, "should fail")
  174. // Mixing implicit and explicit local IPs not allowed
  175. _, err = newExternalIPMapper(CandidateTypeUnspecified, []string{
  176. "1.2.3.5/10.0.0.1",
  177. "1.2.3.4",
  178. })
  179. assert.Error(t, err, "should fail")
  180. })
  181. t.Run("findExternalIP without explicit local IP", func(t *testing.T) {
  182. var m *externalIPMapper
  183. var err error
  184. var extIP net.IP
  185. // IPv4 with explicit local IP, defaults to CandidateTypeHost
  186. m, err = newExternalIPMapper(CandidateTypeUnspecified, []string{
  187. "1.2.3.4",
  188. "2200::1",
  189. })
  190. assert.NoError(t, err, "should succeed")
  191. assert.NotNil(t, m, "should not be nil")
  192. assert.NotNil(t, m.ipv4Mapping.ipSole)
  193. assert.NotNil(t, m.ipv6Mapping.ipSole)
  194. // Find external IPv4
  195. extIP, err = m.findExternalIP("10.0.0.1")
  196. assert.NoError(t, err, "should succeed")
  197. assert.Equal(t, "1.2.3.4", extIP.String(), "should match")
  198. // Find external IPv6
  199. extIP, err = m.findExternalIP("fe80::0001") // Use '0001' instead of '1' on purpose
  200. assert.NoError(t, err, "should succeed")
  201. assert.Equal(t, "2200::1", extIP.String(), "should match")
  202. // Bad local IP string
  203. _, err = m.findExternalIP("really.bad")
  204. assert.Error(t, err, "should fail")
  205. })
  206. t.Run("findExternalIP with explicit local IP", func(t *testing.T) {
  207. var m *externalIPMapper
  208. var err error
  209. var extIP net.IP
  210. // IPv4 with explicit local IP, defaults to CandidateTypeHost
  211. m, err = newExternalIPMapper(CandidateTypeUnspecified, []string{
  212. "1.2.3.4/10.0.0.1",
  213. "1.2.3.5/10.0.0.2",
  214. "2200::1/fe80::1",
  215. "2200::2/fe80::2",
  216. })
  217. assert.NoError(t, err, "should succeed")
  218. assert.NotNil(t, m, "should not be nil")
  219. // Find external IPv4
  220. extIP, err = m.findExternalIP("10.0.0.1")
  221. assert.NoError(t, err, "should succeed")
  222. assert.Equal(t, "1.2.3.4", extIP.String(), "should match")
  223. extIP, err = m.findExternalIP("10.0.0.2")
  224. assert.NoError(t, err, "should succeed")
  225. assert.Equal(t, "1.2.3.5", extIP.String(), "should match")
  226. _, err = m.findExternalIP("10.0.0.3")
  227. assert.Error(t, err, "should fail")
  228. // Find external IPv6
  229. extIP, err = m.findExternalIP("fe80::0001") // Use '0001' instead of '1' on purpose
  230. assert.NoError(t, err, "should succeed")
  231. assert.Equal(t, "2200::1", extIP.String(), "should match")
  232. extIP, err = m.findExternalIP("fe80::0002") // Use '0002' instead of '2' on purpose
  233. assert.NoError(t, err, "should succeed")
  234. assert.Equal(t, "2200::2", extIP.String(), "should match")
  235. _, err = m.findExternalIP("fe80::3")
  236. assert.Error(t, err, "should fail")
  237. // Bad local IP string
  238. _, err = m.findExternalIP("really.bad")
  239. assert.Error(t, err, "should fail")
  240. })
  241. t.Run("findExternalIP with empty map", func(t *testing.T) {
  242. var m *externalIPMapper
  243. var err error
  244. m, err = newExternalIPMapper(CandidateTypeUnspecified, []string{
  245. "1.2.3.4",
  246. })
  247. assert.NoError(t, err, "should succeed")
  248. // Attempt to find IPv6 that does not exist in the map
  249. extIP, err := m.findExternalIP("fe80::1")
  250. assert.NoError(t, err, "should succeed")
  251. assert.Equal(t, "fe80::1", extIP.String(), "should match")
  252. m, err = newExternalIPMapper(CandidateTypeUnspecified, []string{
  253. "2200::1",
  254. })
  255. assert.NoError(t, err, "should succeed")
  256. // Attempt to find IPv4 that does not exist in the map
  257. extIP, err = m.findExternalIP("10.0.0.1")
  258. assert.NoError(t, err, "should succeed")
  259. assert.Equal(t, "10.0.0.1", extIP.String(), "should match")
  260. })
  261. }