sdp_test.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. //go:build PSIPHON_ENABLE_INPROXY
  2. /*
  3. * Copyright (c) 2024, Psiphon Inc.
  4. * All rights reserved.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. package inproxy
  21. import (
  22. "context"
  23. "fmt"
  24. "net"
  25. "strings"
  26. "testing"
  27. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  28. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
  29. )
  30. func TestProcessSDP(t *testing.T) {
  31. err := runTestProcessSDP()
  32. if err != nil {
  33. t.Error(errors.Trace(err).Error())
  34. }
  35. }
  36. func runTestProcessSDP() error {
  37. config := &webRTCConfig{
  38. Logger: newTestLogger(),
  39. WebRTCDialCoordinator: &testWebRTCDialCoordinator{
  40. disableSTUN: true,
  41. disablePortMapping: true,
  42. },
  43. }
  44. hasPersonalCompartmentIDs := false
  45. errorOnNoCandidates := true
  46. disableIPv6Candidates := false
  47. allowPrivateIPAddressCandidates := false
  48. filterPrivateIPAddressCandidates := false
  49. // Create a valid, base SDP, including private network (bogon) candidates.
  50. SetAllowBogonWebRTCConnections(true)
  51. defer SetAllowBogonWebRTCConnections(false)
  52. conn, webRTCSDP, metrics, err := newWebRTCConnForOffer(
  53. context.Background(), config, hasPersonalCompartmentIDs)
  54. if err != nil {
  55. return errors.Trace(err)
  56. }
  57. defer conn.Close()
  58. SDP := []byte(webRTCSDP.SDP)
  59. // Test disallow IPv6
  60. disableIPv6Candidates = true
  61. if metrics.hasIPv6 {
  62. preparedSDP, metrics, err := prepareSDPAddresses(
  63. SDP,
  64. errorOnNoCandidates,
  65. "",
  66. disableIPv6Candidates,
  67. allowPrivateIPAddressCandidates)
  68. if err != nil {
  69. return errors.Trace(err)
  70. }
  71. found := false
  72. for _, reason := range metrics.filteredICECandidates {
  73. if strings.Contains(reason, "disabled") {
  74. found = true
  75. break
  76. }
  77. }
  78. if !found {
  79. return errors.TraceNew("unexpected filteredICECandidates")
  80. }
  81. if len(preparedSDP) >= len(SDP) {
  82. return errors.TraceNew("unexpected SDP length")
  83. }
  84. }
  85. disableIPv6Candidates = false
  86. // Test filter unexpected GeoIP
  87. // This IP must not be a bogon; this address is not dialed.
  88. testIP := "1.1.1.1"
  89. expectedGeoIP := common.GeoIPData{Country: "AA", ASN: "1"}
  90. lookupGeoIP := func(IP string) common.GeoIPData {
  91. if IP == testIP {
  92. return common.GeoIPData{Country: "BB", ASN: "2"}
  93. }
  94. return expectedGeoIP
  95. }
  96. // Add the testIP as a port mapping candidate.
  97. preparedSDP, metrics, err := prepareSDPAddresses(
  98. SDP,
  99. errorOnNoCandidates,
  100. net.JoinHostPort(testIP, "80"),
  101. disableIPv6Candidates,
  102. allowPrivateIPAddressCandidates)
  103. if err != nil {
  104. return errors.Trace(err)
  105. }
  106. filteredSDP, metrics, err := filterSDPAddresses(
  107. preparedSDP,
  108. errorOnNoCandidates,
  109. lookupGeoIP,
  110. expectedGeoIP,
  111. allowPrivateIPAddressCandidates,
  112. filterPrivateIPAddressCandidates)
  113. if err != nil {
  114. return errors.Trace(err)
  115. }
  116. found := false
  117. for _, reason := range metrics.filteredICECandidates {
  118. if strings.Contains(reason, "unexpected GeoIP") {
  119. found = true
  120. break
  121. }
  122. }
  123. if !found {
  124. return errors.TraceNew("unexpected filteredICECandidates")
  125. }
  126. if len(filteredSDP) >= len(preparedSDP) {
  127. return errors.TraceNew("unexpected SDP length")
  128. }
  129. // Test filter bogons
  130. SetAllowBogonWebRTCConnections(false)
  131. // Allow no candidates
  132. errorOnNoCandidates = false
  133. filteredSDP, metrics, err = filterSDPAddresses(
  134. SDP,
  135. errorOnNoCandidates,
  136. nil,
  137. common.GeoIPData{},
  138. allowPrivateIPAddressCandidates,
  139. filterPrivateIPAddressCandidates)
  140. if err != nil {
  141. return errors.Trace(err)
  142. }
  143. found = false
  144. for _, reason := range metrics.filteredICECandidates {
  145. if strings.Contains(reason, "bogon") {
  146. found = true
  147. break
  148. }
  149. }
  150. if !found {
  151. return errors.TraceNew("unexpected filteredICECandidates")
  152. }
  153. if len(filteredSDP) >= len(SDP) {
  154. return errors.TraceNew("unexpected SDP length")
  155. }
  156. errorOnNoCandidates = true
  157. // Test private IP addresses
  158. SetAllowBogonWebRTCConnections(false)
  159. hasPersonalCompartmentIDs = true
  160. allowPrivateIPAddressCandidates = true
  161. filterPrivateIPAddressCandidates = true
  162. conn, webRTCSDP, metrics, err = newWebRTCConnForOffer(
  163. context.Background(), config, hasPersonalCompartmentIDs)
  164. if err != nil {
  165. return errors.Trace(err)
  166. }
  167. defer conn.Close()
  168. SDP = []byte(webRTCSDP.SDP)
  169. hasPrivateIP := metrics.hasPrivateIP
  170. if !hasPrivateIP {
  171. // Test may run on host without RFC 1918/4193 private IP address
  172. fmt.Printf("No private IP address\n")
  173. }
  174. // Filter should retain any private IP address(es)
  175. filteredSDP, metrics, err = filterSDPAddresses(
  176. SDP,
  177. errorOnNoCandidates,
  178. nil,
  179. common.GeoIPData{},
  180. allowPrivateIPAddressCandidates,
  181. filterPrivateIPAddressCandidates)
  182. if err != nil {
  183. return errors.Trace(err)
  184. }
  185. if hasPrivateIP != metrics.hasPrivateIP {
  186. return errors.TraceNew("unexpected metrics.hasPrivateIP")
  187. }
  188. if len(filteredSDP) != len(SDP) {
  189. return errors.TraceNew("unexpected SDP length")
  190. }
  191. return nil
  192. }