test_peerConnection_gatherWithStun300IPv6.html (14097B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <script type="application/javascript" src="pc.js"></script> 5 <script type="application/javascript" src="iceTestUtils.js"></script> 6 </head> 7 <body> 8 <pre id="test"> 9 <script type="application/javascript"> 10 createHTML({ 11 bug: "857668", 12 title: "RTCPeerConnection check STUN gathering with STUN/300 responses (IPv6)" 13 }); 14 15 /* This is pretty hairy, so some background: 16 * Spec is here: https://datatracker.ietf.org/doc/html/rfc8489#section-10 17 * STUN/300 responses allow a server to redirect STUN requests to one or 18 more other servers, as ALTERNATE-SERVER attributes. 19 * The server specifies the IP address, IP version, and port for each 20 ALTERNATE-SERVER. 21 * The spec allows multiple rounds of redirects, and requires the client to 22 remember the servers it has already tried to avoid redirect loops. 23 * For TURNS, the TURN server can also supply an ALTERNATE-DOMAIN attribute, 24 which the client MUST use for the TLS handshake on the new target. The 25 client does _not_ use this as an FQDN; it always uses the address in the 26 ALTERNATE-SERVER. ALTERNATE-DOMAIN is meaningless in the non-TLS case. 27 * STUN/300 with ALTERNATE-SERVER is only defined for the TURN Allocate 28 message type (at least in the context of ICE). Clients are supposed to 29 treat STUN/300 as an unrecoverable error in all other cases. The TURN spec 30 does _not_ spell out how a client should handle multiple ALTERNATE-SERVERs. 31 We just take the first one that we have not already tried, and that is the 32 same IP version that we started with. This is because switching the IP 33 version is problematic for ICE. 34 * The test TURN server opens extra ports that will respond with redirects to 35 the _real_ ports, but the address remains the same. This is because we 36 cannot know ahead of time whether the machine we're running on has more 37 than one IP address of each version. This means the test TURN server is not 38 useful for testing cases where the address changes. Also, the test TURN 39 server does not currently know how to respond with multiple 40 ALTERNATE-SERVERs. 41 * To test cases where the _address_ changes, we instead use a feature in the 42 NAT simulator to respond with fake redirects when the destination address 43 matches an address that we configure with a pref. This feature can add 44 multiple ALTERNATE-SERVERs. 45 * The test TURN server's STUN/300 responses have a proper MESSAGE-INTEGRITY, 46 but the NAT simulator's do _not_. For now, we want both cases to work, 47 because some servers respond with STUN/300 without including 48 MESSAGE-INTEGRITY. This is a spec violation, even though the spec 49 contradicts itself in non-normative language elsewhere. 50 * Right now, neither the NAT simulator nor the test TURN server support 51 ALTERNATE-DOMAIN. 52 */ 53 54 // These are the ports the test TURN server will respond with redirects on. 55 // The test TURN server tells us what these are in the JSON it spits out when 56 // we start it. 57 let turnRedirectPort; 58 let turnsRedirectPort; 59 60 // These are the addresses that we will configure the NAT simulator to 61 // redirect to. We do DNS lookups of the host in iceServersArray (provided 62 // by the test TURN server), and put the results here. On some platforms this 63 // will be 127.0.0.1 and ::1, but on others we may use a real address. 64 let redirectTargetV6; 65 66 // Test TURN server tells us these in the JSON it spits out when we start it 67 let username; 68 let credential; 69 70 // This is the address we will configure the NAT simulator to respond with 71 // redirects for. We use an address from TEST-NET since it is really unlikely 72 // we'll see that on a real machine, and also because we do not have 73 // special-case code in nICEr for TEST-NET (like we do for link-local, for 74 // example). 75 const redirectAddressV6 = '::ffff:198.51.100.1'; 76 77 const tests = [ 78 async function baselineV6Cases() { 79 await checkSrflx([{urls:[`stun:[${redirectTargetV6}]`]}]); 80 await checkRelayUdp([{urls:[`turn:[${redirectTargetV6}]`], username, credential}]); 81 await checkRelayTcp([{urls:[`turn:[${redirectTargetV6}]?transport=tcp`], username, credential}]); 82 await checkRelayUdpTcp([{urls:[`turn:[${redirectTargetV6}]`, `turn:[${redirectTargetV6}]?transport=tcp`], username, credential}]); 83 }, 84 85 async function stunV6Redirect() { 86 // This test uses the test TURN server, because nICEr drops responses 87 // without MESSAGE-INTEGRITY on the floor _unless_ they are a STUN/300 to 88 // an Allocate request. If we tried to use the NAT simulator for this, we 89 // would have to wait for nICEr to time out, since the NAT simulator does 90 // not know how to do MESSAGE-INTEGRITY. 91 await checkNoSrflx( 92 [{urls:[`stun:[${redirectTargetV6}]:${turnRedirectPort}`]}]); 93 }, 94 95 async function turnV6UdpPortRedirect() { 96 await checkRelayUdp([{urls:[`turn:[${redirectTargetV6}]:${turnRedirectPort}`], username, credential}]); 97 }, 98 99 async function turnV6TcpPortRedirect() { 100 await checkRelayTcp([{urls:[`turn:[${redirectTargetV6}]:${turnRedirectPort}?transport=tcp`], username, credential}]); 101 }, 102 103 async function turnV6UdpTcpPortRedirect() { 104 await checkRelayUdpTcp([{urls:[`turn:[${redirectTargetV6}]:${turnRedirectPort}`, `turn:[${redirectTargetV6}]:${turnRedirectPort}?transport=tcp`], username, credential}]); 105 }, 106 107 async function turnV6UdpAddressRedirect() { 108 await pushPrefs( 109 ['media.peerconnection.nat_simulator.redirect_address', `${redirectAddressV6}`], 110 ['media.peerconnection.nat_simulator.redirect_targets', `${redirectTargetV6}`]); 111 await checkRelayUdp([{urls:[`turn:[${redirectAddressV6}]`], username, credential}]); 112 await SpecialPowers.popPrefEnv(); 113 }, 114 115 async function turnV6TcpAddressRedirect() { 116 await pushPrefs( 117 ['media.peerconnection.nat_simulator.redirect_address', `${redirectAddressV6}`], 118 ['media.peerconnection.nat_simulator.redirect_targets', `${redirectTargetV6}`]); 119 await checkRelayTcp([{urls:[`turn:[${redirectAddressV6}]?transport=tcp`], username, credential}]); 120 await SpecialPowers.popPrefEnv(); 121 }, 122 123 async function turnV6UdpTcpAddressRedirect() { 124 await pushPrefs( 125 ['media.peerconnection.nat_simulator.redirect_address', `${redirectAddressV6}`], 126 ['media.peerconnection.nat_simulator.redirect_targets', `${redirectTargetV6}`]); 127 await checkRelayUdpTcp([{urls:[`turn:[${redirectAddressV6}]`, `turn:[${redirectAddressV6}]?transport=tcp`], username, credential}]); 128 await SpecialPowers.popPrefEnv(); 129 }, 130 131 async function turnV6UdpEmptyRedirect() { 132 await pushPrefs( 133 ['media.peerconnection.nat_simulator.redirect_address', `${redirectAddressV6}`], 134 ['media.peerconnection.nat_simulator.redirect_targets', '']); 135 await checkNoRelay([{urls:[`turn:[${redirectAddressV6}]`], username, credential}]); 136 await SpecialPowers.popPrefEnv(); 137 }, 138 139 async function turnV6TcpEmptyRedirect() { 140 await pushPrefs( 141 ['media.peerconnection.nat_simulator.redirect_address', `${redirectAddressV6}`], 142 ['media.peerconnection.nat_simulator.redirect_targets', '']); 143 await checkNoRelay([{urls:[`turn:[${redirectAddressV6}]?transport=tcp`], username, credential}]); 144 await SpecialPowers.popPrefEnv(); 145 }, 146 147 async function turnV6UdpTcpEmptyRedirect() { 148 await pushPrefs( 149 ['media.peerconnection.nat_simulator.redirect_address', `${redirectAddressV6}`], 150 ['media.peerconnection.nat_simulator.redirect_targets', '']); 151 await checkNoRelay([{urls:[`turn:[${redirectAddressV6}]`, `turn:[${redirectAddressV6}]?transport=tcp`], username, credential}]); 152 await SpecialPowers.popPrefEnv(); 153 }, 154 155 async function turnV6UdpAddressAndPortRedirect() { 156 // This should result in two rounds of redirection; the first is by 157 // address, the second is by port. 158 await pushPrefs( 159 ['media.peerconnection.nat_simulator.redirect_address', `${redirectAddressV6}`], 160 ['media.peerconnection.nat_simulator.redirect_targets', `${redirectTargetV6}`]); 161 await checkRelayUdp([{urls:[`turn:[${redirectAddressV6}]:${turnRedirectPort}`], username, credential}]); 162 await SpecialPowers.popPrefEnv(); 163 }, 164 165 async function turnV6TcpAddressAndPortRedirect() { 166 // This should result in two rounds of redirection; the first is by 167 // address, the second is by port. 168 await pushPrefs( 169 ['media.peerconnection.nat_simulator.redirect_address', `${redirectAddressV6}`], 170 ['media.peerconnection.nat_simulator.redirect_targets', `${redirectTargetV6}`]); 171 await checkRelayTcp([{urls:[`turn:[${redirectAddressV6}]:${turnRedirectPort}?transport=tcp`], username, credential}]); 172 await SpecialPowers.popPrefEnv(); 173 }, 174 175 async function turnV6UdpTcpAddressAndPortRedirect() { 176 // This should result in two rounds of redirection; the first is by 177 // address, the second is by port. 178 await pushPrefs( 179 ['media.peerconnection.nat_simulator.redirect_address', `${redirectAddressV6}`], 180 ['media.peerconnection.nat_simulator.redirect_targets', `${redirectTargetV6}`]); 181 await checkRelayUdpTcp([{urls:[`turn:[${redirectAddressV6}]:${turnRedirectPort}`, `turn:[${redirectAddressV6}]:${turnRedirectPort}?transport=tcp`], username, credential}]); 182 await SpecialPowers.popPrefEnv(); 183 }, 184 185 async function turnV6UdpRedirectLoop() { 186 await pushPrefs( 187 ['media.peerconnection.nat_simulator.redirect_address', `${redirectAddressV6}`], 188 ['media.peerconnection.nat_simulator.redirect_targets', `${redirectAddressV6}`]); 189 // If we don't detect the loop, gathering will not finish 190 await checkNoRelay([{urls:[`turn:[${redirectAddressV6}]`], username, credential}]); 191 await SpecialPowers.popPrefEnv(); 192 }, 193 194 async function turnV6TcpRedirectLoop() { 195 await pushPrefs( 196 ['media.peerconnection.nat_simulator.redirect_address', `${redirectAddressV6}`], 197 ['media.peerconnection.nat_simulator.redirect_targets', `${redirectAddressV6}`]); 198 // If we don't detect the loop, gathering will not finish 199 await checkNoRelay([{urls:[`turn:[${redirectAddressV6}]?transport=tcp`], username, credential}]); 200 await SpecialPowers.popPrefEnv(); 201 }, 202 203 async function turnV6UdpTcpRedirectLoop() { 204 await pushPrefs( 205 ['media.peerconnection.nat_simulator.redirect_address', `${redirectAddressV6}`], 206 ['media.peerconnection.nat_simulator.redirect_targets', `${redirectAddressV6}`]); 207 // If we don't detect the loop, gathering will not finish 208 await checkNoRelay([{urls:[`turn:[${redirectAddressV6}]`, `turn:[${redirectAddressV6}]?transport=tcp`], username, credential}]); 209 await SpecialPowers.popPrefEnv(); 210 }, 211 212 async function turnV6UdpMultipleAddressRedirect() { 213 await pushPrefs( 214 ['media.peerconnection.nat_simulator.redirect_address', `${redirectAddressV6}`], 215 ['media.peerconnection.nat_simulator.redirect_targets', `${redirectAddressV6},${redirectTargetV6}`]); 216 await checkRelayUdp([{urls:[`turn:[${redirectAddressV6}]`], username, credential}]); 217 await SpecialPowers.popPrefEnv(); 218 }, 219 220 async function turnV6TcpMultipleAddressRedirect() { 221 await pushPrefs( 222 ['media.peerconnection.nat_simulator.redirect_address', `${redirectAddressV6}`], 223 ['media.peerconnection.nat_simulator.redirect_targets', `${redirectAddressV6},${redirectTargetV6}`]); 224 await checkRelayTcp([{urls:[`turn:[${redirectAddressV6}]?transport=tcp`], username, credential}]); 225 await SpecialPowers.popPrefEnv(); 226 }, 227 228 async function turnV6UdpTcpMultipleAddressRedirect() { 229 await pushPrefs( 230 ['media.peerconnection.nat_simulator.redirect_address', `${redirectAddressV6}`], 231 ['media.peerconnection.nat_simulator.redirect_targets', `${redirectAddressV6},${redirectTargetV6}`]); 232 await checkRelayUdpTcp([{urls:[`turn:[${redirectAddressV6}]`, `turn:[${redirectAddressV6}]?transport=tcp`], username, credential}]); 233 await SpecialPowers.popPrefEnv(); 234 }, 235 ]; 236 237 runNetworkTest(async () => { 238 const turnServer = iceServersArray.find(server => "username" in server); 239 username = turnServer.username; 240 credential = turnServer.credential; 241 // Special props, non-standard 242 turnRedirectPort = turnServer.turn_redirect_port; 243 turnsRedirectPort = turnServer.turns_redirect_port; 244 // Just use the first url. It might make sense to look for TURNS first, 245 // since that will always use a hostname, but on CI we don't have TURNS 246 // support anyway (see bug 1323439). 247 const turnHostname = getTurnHostname(turnServer.urls[0]); 248 249 await pushPrefs( 250 ['media.peerconnection.ice.obfuscate_host_addresses', false], 251 ['media.peerconnection.nat_simulator.filtering_type', 'ENDPOINT_INDEPENDENT'], 252 ['media.peerconnection.nat_simulator.mapping_type', 'ENDPOINT_INDEPENDENT'], 253 ['media.peerconnection.ice.loopback', true], 254 ['media.getusermedia.insecure.enabled', true]); 255 256 if (await ipv6Supported()) { 257 redirectTargetV6 = await dnsLookupV6(turnHostname); 258 if (redirectTargetV6 == '' && turnHostname == 'localhost') { 259 // Our testers don't seem to have IPv6 DNS resolution for localhost 260 // set up... 261 redirectTargetV6 = '::1'; 262 } 263 264 if (redirectTargetV6 != '') { 265 for (const test of tests) { 266 info(`Running test: ${test.name}`); 267 await test(); 268 info(`Done running test: ${test.name}`); 269 } 270 } else { 271 ok(false, `This machine has an IPv6 address, but ${turnHostname} does not resolve to an IPv6 address`); 272 } 273 } else { 274 ok(false, 'This machine appears to not have an IPv6 address'); 275 } 276 277 await SpecialPowers.popPrefEnv(); 278 }, { useIceServer: true }); 279 280 </script> 281 </pre> 282 </body> 283 </html>