summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMoonchild <moonchild@palemoon.org>2022-08-26 16:10:54 +0000
committerMoonchild <moonchild@palemoon.org>2022-08-26 16:10:54 +0000
commitce11609fe934e522fc207fa9ad657073e3653fa5 (patch)
treea7074378b44103b3d7e0b4ba6e24ec4f246ba885
parent29c1150eef769522cf4a17a1ce647ce43a19d6cf (diff)
parentaacd52f00f3fc0e466fbd56da3688607cd81377c (diff)
downloaduxp-ce11609fe934e522fc207fa9ad657073e3653fa5.tar.gz
Merge pull request 'Support TURN TLS in WebRTC' (#1993) from Basilisk-Dev/UXP:master into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/1993
-rw-r--r--dom/media/PeerConnection.js2
-rw-r--r--dom/media/tests/mochitest/addTurnsSelfsignedCert.js26
-rw-r--r--dom/media/tests/mochitest/mochitest.ini3
-rw-r--r--dom/media/tests/mochitest/pc.js30
-rw-r--r--dom/media/tests/mochitest/test_peerConnection_basicAudioNATRelayTLS.html38
-rw-r--r--dom/network/PTCPSocket.ipdl3
-rw-r--r--dom/network/TCPSocketChild.cpp5
-rw-r--r--dom/network/TCPSocketChild.h2
-rw-r--r--dom/network/TCPSocketParent.cpp20
-rw-r--r--dom/network/TCPSocketParent.h1
-rw-r--r--media/mtransport/nr_socket_prsock.cpp34
-rw-r--r--media/mtransport/nr_socket_prsock.h3
-rw-r--r--media/mtransport/nricectx.cpp9
-rw-r--r--media/mtransport/nricectx.h1
-rw-r--r--media/mtransport/test_nr_socket.cpp55
-rw-r--r--media/mtransport/test_nr_socket.h3
-rw-r--r--media/mtransport/third_party/nICEr/src/ice/ice_candidate.c8
-rw-r--r--media/mtransport/third_party/nICEr/src/ice/ice_ctx.h1
-rw-r--r--media/mtransport/third_party/nICEr/src/net/transport_addr.h1
-rw-r--r--media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp24
-rw-r--r--media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h1
-rw-r--r--media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp11
-rw-r--r--media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h3
-rw-r--r--netwerk/base/nsISocketTransport.idl5
-rw-r--r--netwerk/base/nsSocketTransport2.cpp34
-rw-r--r--netwerk/base/nsSocketTransport2.h1
-rw-r--r--netwerk/protocol/http/TunnelUtils.cpp6
-rw-r--r--testing/tools/iceserver/iceserver.py72
28 files changed, 368 insertions, 34 deletions
diff --git a/dom/media/PeerConnection.js b/dom/media/PeerConnection.js
index d2f098b1fa..77b7a58980 100644
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -588,7 +588,7 @@ RTCPeerConnection.prototype = {
throw new this._win.DOMException(msg + " - improper scheme: " + url.scheme,
"SyntaxError");
}
- if (url.scheme in { stuns:1, turns:1 }) {
+ if (url.scheme in { stuns:1 }) {
this.logWarning(url.scheme.toUpperCase() + " is not yet supported.");
}
});
diff --git a/dom/media/tests/mochitest/addTurnsSelfsignedCert.js b/dom/media/tests/mochitest/addTurnsSelfsignedCert.js
new file mode 100644
index 0000000000..cad3d04465
--- /dev/null
+++ b/dom/media/tests/mochitest/addTurnsSelfsignedCert.js
@@ -0,0 +1,26 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+// This is only usable from the parent process, even for doing simple stuff like
+// serializing a cert.
+var gCertMaker = Cc["@mozilla.org/security/x509certdb;1"].
+ getService(Ci.nsIX509CertDB);
+
+var gCertOverrides = Cc["@mozilla.org/security/certoverride;1"].
+ getService(Ci.nsICertOverrideService);
+
+
+addMessageListener('add-turns-certs', certs => {
+ var port = 5349;
+ certs.forEach(certDescription => {
+ var cert = gCertMaker.constructX509FromBase64(certDescription.cert);
+ gCertOverrides.rememberValidityOverride(certDescription.hostname, port,
+ cert, Ci.nsICertOverrideService.ERROR_UNTRUSTED, false);
+ });
+ sendAsyncMessage('certs-added');
+});
diff --git a/dom/media/tests/mochitest/mochitest.ini b/dom/media/tests/mochitest/mochitest.ini
index 22006ffa2f..948d938a30 100644
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -13,6 +13,7 @@ support-files =
blacksilence.js
turnConfig.js
sdpUtils.js
+ addTurnsSelfsignedCert.js
!/dom/canvas/test/captureStream_common.js
!/dom/canvas/test/webgl-mochitest/webgl-util.js
!/dom/media/test/manifest.js
@@ -98,6 +99,8 @@ skip-if = toolkit == 'android' # websockets don't work on android (bug 1266217)
skip-if = toolkit == 'android' # websockets don't work on android (bug 1266217)
[test_peerConnection_basicAudioNATRelayTCP.html]
skip-if = toolkit == 'android' # websockets don't work on android (bug 1266217)
+[test_peerConnection_basicAudioNATRelayTLS.html]
+skip-if = true # need pyopenssl on builders, see bug 1323439
[test_peerConnection_basicAudioRequireEOC.html]
skip-if = (android_version == '18' && debug) # android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_basicAudioPcmaPcmuOnly.html]
diff --git a/dom/media/tests/mochitest/pc.js b/dom/media/tests/mochitest/pc.js
index a9383358f9..2e9c7c63f1 100644
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -1822,6 +1822,33 @@ function createHTML(options) {
var iceServerWebsocket;
var iceServersArray = [];
+var addTurnsSelfsignedCerts = () => {
+ var gUrl = SimpleTest.getTestFileURL('addTurnsSelfsignedCert.js');
+ var gScript = SpecialPowers.loadChromeScript(gUrl);
+ var certs = [];
+ // If the ICE server is running TURNS, and includes a "cert" attribute in
+ // its JSON, we set up an override that will forgive things like
+ // self-signed for it.
+ iceServersArray.forEach(iceServer => {
+ if (iceServer.hasOwnProperty("cert")) {
+ iceServer.urls.forEach(url => {
+ if (url.startsWith("turns:")) {
+ // Assumes no port or params!
+ certs.push({"cert": iceServer.cert, "hostname": url.substr(6)});
+ }
+ });
+ }
+ });
+
+ return new Promise((resolve, reject) => {
+ gScript.addMessageListener('certs-added', () => {
+ resolve();
+ });
+
+ gScript.sendAsyncMessage('add-turns-certs', certs);
+ });
+};
+
var setupIceServerConfig = useIceServer => {
// We disable ICE support for HTTP proxy when using a TURN server, because
// mochitest uses a fake HTTP proxy to serve content, which will eat our STUN
@@ -1863,7 +1890,8 @@ var setupIceServerConfig = useIceServer => {
return enableHttpProxy(false)
.then(spawnIceServer)
- .then(iceServersStr => { iceServersArray = JSON.parse(iceServersStr); });
+ .then(iceServersStr => { iceServersArray = JSON.parse(iceServersStr); })
+ .then(addTurnsSelfsignedCerts);
};
function runNetworkTest(testFunction, fixtureOptions) {
diff --git a/dom/media/tests/mochitest/test_peerConnection_basicAudioNATRelayTLS.html b/dom/media/tests/mochitest/test_peerConnection_basicAudioNATRelayTLS.html
new file mode 100644
index 0000000000..c295955d81
--- /dev/null
+++ b/dom/media/tests/mochitest/test_peerConnection_basicAudioNATRelayTLS.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <script type="application/javascript" src="pc.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+ createHTML({
+ bug: "1231975",
+ title: "Basic audio-only peer connection with port dependent NAT that blocks STUN"
+ });
+
+ var test;
+ runNetworkTest(options => {
+ SpecialPowers.pushPrefEnv(
+ {
+ 'set': [
+ ['media.peerconnection.nat_simulator.filtering_type', 'PORT_DEPENDENT'],
+ ['media.peerconnection.nat_simulator.mapping_type', 'PORT_DEPENDENT'],
+ ['media.peerconnection.nat_simulator.block_udp', true],
+ ['media.peerconnection.nat_simulator.block_tcp', true]
+ ]
+ }, function (options) {
+ options = options || {};
+ options.expectedLocalCandidateType = "relayed-tcp";
+ options.expectedRemoteCandidateType = "relayed-tcp";
+ // No reason to wait for gathering to complete like the other NAT tests,
+ // since relayed-tcp is the only thing that can work.
+ test = new PeerConnectionTest(options);
+ test.setMediaConstraints([{audio: true}], [{audio: true}]);
+ test.run();
+ })
+ }, { useIceServer: true });
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/network/PTCPSocket.ipdl b/dom/network/PTCPSocket.ipdl
index aa7c51e45f..ea00856029 100644
--- a/dom/network/PTCPSocket.ipdl
+++ b/dom/network/PTCPSocket.ipdl
@@ -44,7 +44,8 @@ parent:
// address specified in |localAddr| and |localPort|.
async OpenBind(nsCString host, uint16_t port,
nsCString localAddr, uint16_t localPort,
- bool useSSL, bool aUseArrayBuffers, nsCString aFilter);
+ bool useSSL, bool reuseAddrPort,
+ bool aUseArrayBuffers, nsCString aFilter);
// When child's send() is called, this message requrests parent to send
// data and update it's trackingNumber.
diff --git a/dom/network/TCPSocketChild.cpp b/dom/network/TCPSocketChild.cpp
index 9e1dce2769..b2b8db78a3 100644
--- a/dom/network/TCPSocketChild.cpp
+++ b/dom/network/TCPSocketChild.cpp
@@ -108,7 +108,7 @@ void
TCPSocketChild::SendWindowlessOpenBind(nsITCPSocketCallback* aSocket,
const nsACString& aRemoteHost, uint16_t aRemotePort,
const nsACString& aLocalHost, uint16_t aLocalPort,
- bool aUseSSL)
+ bool aUseSSL, bool aReuseAddrPort)
{
mSocket = aSocket;
AddIPDLReference();
@@ -117,7 +117,8 @@ TCPSocketChild::SendWindowlessOpenBind(nsITCPSocketCallback* aSocket,
aRemotePort);
PTCPSocketChild::SendOpenBind(nsCString(aRemoteHost), aRemotePort,
nsCString(aLocalHost), aLocalPort,
- aUseSSL, true, mFilterName);
+ aUseSSL, aReuseAddrPort,
+ true, mFilterName);
}
void
diff --git a/dom/network/TCPSocketChild.h b/dom/network/TCPSocketChild.h
index 7e9b59e8b5..46e9b0a90f 100644
--- a/dom/network/TCPSocketChild.h
+++ b/dom/network/TCPSocketChild.h
@@ -55,7 +55,7 @@ public:
void SendWindowlessOpenBind(nsITCPSocketCallback* aSocket,
const nsACString& aRemoteHost, uint16_t aRemotePort,
const nsACString& aLocalHost, uint16_t aLocalPort,
- bool aUseSSL);
+ bool aUseSSL, bool aUseRealtimeOptions);
NS_IMETHOD SendSendArray(nsTArray<uint8_t>& aArray,
uint32_t aTrackingNumber);
void SendSend(const nsACString& aData, uint32_t aTrackingNumber);
diff --git a/dom/network/TCPSocketParent.cpp b/dom/network/TCPSocketParent.cpp
index 313d13f759..96eab44510 100644
--- a/dom/network/TCPSocketParent.cpp
+++ b/dom/network/TCPSocketParent.cpp
@@ -149,6 +149,7 @@ TCPSocketParent::RecvOpenBind(const nsCString& aRemoteHost,
const nsCString& aLocalAddr,
const uint16_t& aLocalPort,
const bool& aUseSSL,
+ const bool& aReuseAddrPort,
const bool& aUseArrayBuffers,
const nsCString& aFilter)
{
@@ -167,14 +168,27 @@ TCPSocketParent::RecvOpenBind(const nsCString& aRemoteHost,
}
nsCOMPtr<nsISocketTransport> socketTransport;
- rv = sts->CreateTransport(nullptr, 0,
- aRemoteHost, aRemotePort,
- nullptr, getter_AddRefs(socketTransport));
+ if (aUseSSL) {
+ const char* socketTypes[1];
+ socketTypes[0] = "ssl";
+ rv = sts->CreateTransport(socketTypes, 1,
+ aRemoteHost, aRemotePort,
+ nullptr, getter_AddRefs(socketTransport));
+ } else {
+ rv = sts->CreateTransport(nullptr, 0,
+ aRemoteHost, aRemotePort,
+ nullptr, getter_AddRefs(socketTransport));
+ }
+
if (NS_FAILED(rv)) {
FireInteralError(this, __LINE__);
return true;
}
+ // in most cases aReuseAddrPort is false, but ICE TCP needs
+ // sockets options set that allow addr/port reuse
+ socketTransport->SetReuseAddrPort(aReuseAddrPort);
+
PRNetAddr prAddr;
if (PR_SUCCESS != PR_InitializeNetAddr(PR_IpAddrAny, aLocalPort, &prAddr)) {
FireInteralError(this, __LINE__);
diff --git a/dom/network/TCPSocketParent.h b/dom/network/TCPSocketParent.h
index 07112f1e2d..e0f987b17f 100644
--- a/dom/network/TCPSocketParent.h
+++ b/dom/network/TCPSocketParent.h
@@ -54,6 +54,7 @@ public:
const nsCString& aLocalAddr,
const uint16_t& aLocalPort,
const bool& aUseSSL,
+ const bool& aReuseAddrPort,
const bool& aUseArrayBuffers,
const nsCString& aFilter) override;
diff --git a/media/mtransport/nr_socket_prsock.cpp b/media/mtransport/nr_socket_prsock.cpp
index 80e5ef51e4..3fd223349c 100644
--- a/media/mtransport/nr_socket_prsock.cpp
+++ b/media/mtransport/nr_socket_prsock.cpp
@@ -858,6 +858,10 @@ int NrSocket::connect(nr_transport_addr *addr) {
PRNetAddr naddr;
int32_t connect_status, getsockname_status;
+ // TODO: Add TLS layer with nsISocketProviderService?
+ if (addr->tls_host[0] != '\0')
+ ABORT(R_INTERNAL);
+
if ((r=nr_transport_addr_to_praddr(addr, &naddr)))
ABORT(r);
@@ -1840,7 +1844,7 @@ void NrTcpSocketIpc::close() {
}
int NrTcpSocketIpc::connect(nr_transport_addr *addr) {
- nsCString remote_addr, local_addr;
+ nsCString remote_addr, local_addr, tls_host;
int32_t remote_port, local_port;
int r, _status;
if ((r=nr_transport_addr_get_addrstring_and_port(addr,
@@ -1856,6 +1860,8 @@ int NrTcpSocketIpc::connect(nr_transport_addr *addr) {
ABORT(r);
}
+ tls_host = addr->tls_host;
+
state_ = mirror_state_ = NR_CONNECTING;
RUN_ON_THREAD(io_thread_,
mozilla::WrapRunnable(RefPtr<NrTcpSocketIpc>(this),
@@ -1863,7 +1869,8 @@ int NrTcpSocketIpc::connect(nr_transport_addr *addr) {
remote_addr,
static_cast<uint16_t>(remote_port),
local_addr,
- static_cast<uint16_t>(local_port)),
+ static_cast<uint16_t>(local_port),
+ tls_host),
NS_DISPATCH_NORMAL);
// Make caller wait for ready to write.
@@ -1939,7 +1946,8 @@ int NrTcpSocketIpc::accept(nr_transport_addr *addrp, nr_socket **sockp) {
void NrTcpSocketIpc::connect_i(const nsACString &remote_addr,
uint16_t remote_port,
const nsACString &local_addr,
- uint16_t local_port) {
+ uint16_t local_port,
+ const nsACString &tls_host) {
ASSERT_ON_THREAD(io_thread_);
mirror_state_ = NR_CONNECTING;
@@ -1948,11 +1956,21 @@ void NrTcpSocketIpc::connect_i(const nsACString &remote_addr,
// Bug 1285330: put filtering back in here
- // XXX remove remote!
- socket_child_->SendWindowlessOpenBind(this,
- remote_addr, remote_port,
- local_addr, local_port,
- /* use ssl */ false);
+ if (tls_host.IsEmpty()) {
+ // XXX remove remote!
+ socket_child_->SendWindowlessOpenBind(this,
+ remote_addr, remote_port,
+ local_addr, local_port,
+ /* use ssl */ false,
+ /* reuse addr port */ true);
+ } else {
+ // XXX remove remote!
+ socket_child_->SendWindowlessOpenBind(this,
+ tls_host, remote_port,
+ local_addr, local_port,
+ /* use ssl */ true,
+ /* reuse addr port */ true);
+ }
}
void NrTcpSocketIpc::write_i(nsAutoPtr<InfallibleTArray<uint8_t>> arr,
diff --git a/media/mtransport/nr_socket_prsock.h b/media/mtransport/nr_socket_prsock.h
index 5ed9a6a219..7d372ccb16 100644
--- a/media/mtransport/nr_socket_prsock.h
+++ b/media/mtransport/nr_socket_prsock.h
@@ -369,7 +369,8 @@ private:
void connect_i(const nsACString &remote_addr,
uint16_t remote_port,
const nsACString &local_addr,
- uint16_t local_port);
+ uint16_t local_port,
+ const nsACString &tls_host);
void write_i(nsAutoPtr<InfallibleTArray<uint8_t>> buf,
uint32_t tracking_number);
void close_i();
diff --git a/media/mtransport/nricectx.cpp b/media/mtransport/nricectx.cpp
index be50f50169..75d3d2519d 100644
--- a/media/mtransport/nricectx.cpp
+++ b/media/mtransport/nricectx.cpp
@@ -108,6 +108,7 @@ MOZ_MTLOG_MODULE("mtransport")
const char kNrIceTransportUdp[] = "udp";
const char kNrIceTransportTcp[] = "tcp";
+const char kNrIceTransportTls[] = "tls";
static bool initialized = false;
@@ -210,6 +211,9 @@ nsresult NrIceStunServer::ToNicerStunStruct(nr_ice_stun_server *server) const {
server->transport = IPPROTO_UDP;
} else if (transport_ == kNrIceTransportTcp) {
server->transport = IPPROTO_TCP;
+ } else if (transport_ == kNrIceTransportTls) {
+ server->transport = IPPROTO_TCP;
+ server->tls = 1;
} else {
MOZ_MTLOG(ML_ERROR, "Unsupported STUN server transport: " << transport_);
return NS_ERROR_FAILURE;
@@ -586,6 +590,7 @@ NrIceCtx::Initialize(const std::string& ufrag,
nsCString mapping_type;
nsCString filtering_type;
bool block_udp = false;
+ bool block_tcp = false;
nsresult rv;
nsCOMPtr<nsIPrefService> pref_service =
@@ -604,6 +609,9 @@ NrIceCtx::Initialize(const std::string& ufrag,
rv = pref_branch->GetBoolPref(
"media.peerconnection.nat_simulator.block_udp",
&block_udp);
+ rv = pref_branch->GetBoolPref(
+ "media.peerconnection.nat_simulator.block_tcp",
+ &block_tcp);
}
}
@@ -614,6 +622,7 @@ NrIceCtx::Initialize(const std::string& ufrag,
test_nat->filtering_type_ = TestNat::ToNatBehavior(filtering_type.get());
test_nat->mapping_type_ = TestNat::ToNatBehavior(mapping_type.get());
test_nat->block_udp_ = block_udp;
+ test_nat->block_tcp_ = block_tcp;
test_nat->enabled_ = true;
SetNat(test_nat);
}
diff --git a/media/mtransport/nricectx.h b/media/mtransport/nricectx.h
index ce104ac317..87122121e5 100644
--- a/media/mtransport/nricectx.h
+++ b/media/mtransport/nricectx.h
@@ -90,6 +90,7 @@ class NrIceMediaStream;
extern const char kNrIceTransportUdp[];
extern const char kNrIceTransportTcp[];
+extern const char kNrIceTransportTls[];
class NrIceStunServer {
public:
diff --git a/media/mtransport/test_nr_socket.cpp b/media/mtransport/test_nr_socket.cpp
index e7dad79cd1..fb2de3096e 100644
--- a/media/mtransport/test_nr_socket.cpp
+++ b/media/mtransport/test_nr_socket.cpp
@@ -200,6 +200,7 @@ int TestNat::create_socket_factory(nr_socket_factory **factorypp) {
TestNrSocket::TestNrSocket(TestNat *nat)
: nat_(nat),
+ tls_(false),
timer_handle_(nullptr) {
nat_->insert_socket(this);
}
@@ -473,6 +474,10 @@ int TestNrSocket::connect(nr_transport_addr *addr) {
return R_INTERNAL;
}
+ if (addr->tls_host[0] != '\0') {
+ tls_ = true;
+ }
+
if (!nat_->enabled_
|| addr->protocol==IPPROTO_UDP // Horrible hack to allow default address
// discovery to work. Only works because
@@ -508,6 +513,24 @@ int TestNrSocket::connect(nr_transport_addr *addr) {
}
int TestNrSocket::write(const void *msg, size_t len, size_t *written) {
+ UCHAR *buf = static_cast<UCHAR*>(const_cast<void*>(msg));
+ if (nat_->block_stun_ && nr_is_stun_message(buf, len)) {
+ // Should cause this socket to be abandoned
+ r_log(LOG_GENERIC, LOG_DEBUG,
+ "TestNrSocket %s dropping outgoing TCP "
+ "because it is configured to drop STUN",
+ my_addr().as_string);
+ return R_INTERNAL;
+ }
+
+ if (nat_->block_tcp_ && !tls_) {
+ // Should cause this socket to be abandoned
+ r_log(LOG_GENERIC, LOG_DEBUG,
+ "TestNrSocket %s dropping outgoing TCP "
+ "because it is configured to drop TCP",
+ my_addr().as_string);
+ return R_INTERNAL;
+ }
if (port_mappings_.empty()) {
// The no-nat case, just pass call through.
@@ -518,7 +541,11 @@ int TestNrSocket::write(const void *msg, size_t len, size_t *written) {
} else {
destroy_stale_port_mappings();
if (port_mappings_.empty()) {
- return -1;
+ r_log(LOG_GENERIC, LOG_DEBUG,
+ "TestNrSocket %s dropping outgoing TCP "
+ "because the port mapping was stale",
+ my_addr().as_string);
+ return R_INTERNAL;
}
// This is TCP only
MOZ_ASSERT(port_mappings_.size() == 1);
@@ -533,18 +560,34 @@ int TestNrSocket::write(const void *msg, size_t len, size_t *written) {
}
int TestNrSocket::read(void *buf, size_t maxlen, size_t *len) {
+ int r;
if (port_mappings_.empty()) {
- return internal_socket_->read(buf, maxlen, len);
+ r = internal_socket_->read(buf, maxlen, len);
} else {
MOZ_ASSERT(port_mappings_.size() == 1);
- int bytesRead =
- port_mappings_.front()->external_socket_->read(buf, maxlen, len);
- if (bytesRead > 0 && nat_->refresh_on_ingress_) {
+ r = port_mappings_.front()->external_socket_->read(buf, maxlen, len);
+ if (!r && nat_->refresh_on_ingress_) {
port_mappings_.front()->last_used_ = PR_IntervalNow();
}
- return bytesRead;
}
+
+ if (r) {
+ return r;
+ }
+
+ if (nat_->block_tcp_ && !tls_) {
+ // Should cause this socket to be abandoned
+ return R_INTERNAL;
+ }
+
+ UCHAR *cbuf = static_cast<UCHAR*>(const_cast<void*>(buf));
+ if (nat_->block_stun_ && nr_is_stun_message(cbuf, *len)) {
+ // Should cause this socket to be abandoned
+ return R_INTERNAL;
+ }
+
+ return r;
}
int TestNrSocket::async_wait(int how, NR_async_cb cb, void *cb_arg,
diff --git a/media/mtransport/test_nr_socket.h b/media/mtransport/test_nr_socket.h
index 91c9030f17..a47a88beb9 100644
--- a/media/mtransport/test_nr_socket.h
+++ b/media/mtransport/test_nr_socket.h
@@ -137,6 +137,7 @@ class TestNat {
refresh_on_ingress_(false),
block_udp_(false),
block_stun_(false),
+ block_tcp_(false),
delay_stun_resp_ms_(0),
sockets_() {}
@@ -168,6 +169,7 @@ class TestNat {
bool refresh_on_ingress_;
bool block_udp_;
bool block_stun_;
+ bool block_tcp_;
/* Note: this can only delay a single response so far (bug 1253657) */
uint32_t delay_stun_resp_ms_;
@@ -319,6 +321,7 @@ class TestNrSocket : public NrSocketBase {
// same nat.
RefPtr<NrSocketBase> internal_socket_;
RefPtr<TestNat> nat_;
+ bool tls_;
// Since our comparison logic is different depending on what kind of NAT
// we simulate, and the STL does not make it very easy to switch out the
// comparison function at runtime, and these lists are going to be very
diff --git a/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c b/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
index e48b7b5e1a..879b77933e 100644
--- a/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
@@ -666,6 +666,14 @@ static int nr_ice_candidate_resolved_cb(void *cb_arg, nr_transport_addr *addr)
if(r=nr_transport_addr_copy(&cand->stun_server_addr,addr))
ABORT(r);
+ if (cand->stun_server->tls) {
+ /* Copy over the DNS name; needed for TLS. There is already a null at the
+ * end of the buffer, leave it there. */
+ strncpy(cand->stun_server_addr.tls_host,
+ cand->stun_server->u.dnsname.host,
+ sizeof(cand->stun_server_addr.tls_host) - 1);
+ }
+
if (cand->tcp_type == TCP_TYPE_PASSIVE || cand->tcp_type == TCP_TYPE_SO){
if (r=nr_socket_multi_tcp_stun_server_connect(cand->osock, addr))
ABORT(r);
diff --git a/media/mtransport/third_party/nICEr/src/ice/ice_ctx.h b/media/mtransport/third_party/nICEr/src/ice/ice_ctx.h
index cc79304f08..1e815ac2ac 100644
--- a/media/mtransport/third_party/nICEr/src/ice/ice_ctx.h
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_ctx.h
@@ -63,6 +63,7 @@ typedef struct nr_ice_stun_server_ {
} u;
int id;
int transport;
+ int tls; /* Whether to use TLS or not */
} nr_ice_stun_server;
typedef struct nr_ice_turn_server_ {
diff --git a/media/mtransport/third_party/nICEr/src/net/transport_addr.h b/media/mtransport/third_party/nICEr/src/net/transport_addr.h
index dfec633291..06c8b8c9c5 100644
--- a/media/mtransport/third_party/nICEr/src/net/transport_addr.h
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr.h
@@ -66,6 +66,7 @@ typedef struct nr_transport_addr_ {
/* A string version.
56 = 5 ("IP6:[") + 39 (ipv6 address) + 2 ("]:") + 5 (port) + 4 (/UDP) + 1 (null) */
char as_string[56];
+ char tls_host[256];
} nr_transport_addr;
typedef struct nr_transport_addr_mask_ {
diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
index 3b4363a13c..ad87fa1f91 100644
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -335,6 +335,7 @@ PeerConnectionImpl::PeerConnectionImpl(const GlobalObject* aGlobal)
, mSTSThread(nullptr)
, mAllowIceLoopback(false)
, mAllowIceLinkLocal(false)
+ , mForceIceTcp(false)
, mMedia(nullptr)
, mUuidGen(MakeUnique<PCUuidGenerator>())
, mNumAudioStreams(0)
@@ -365,6 +366,8 @@ PeerConnectionImpl::PeerConnectionImpl(const GlobalObject* aGlobal)
"media.peerconnection.ice.loopback", false);
mAllowIceLinkLocal = Preferences::GetBool(
"media.peerconnection.ice.link_local", false);
+ mForceIceTcp = Preferences::GetBool(
+ "media.peerconnection.ice.force_ice_tcp", false);
#endif
memset(mMaxReceiving, 0, sizeof(mMaxReceiving));
memset(mMaxSending, 0, sizeof(mMaxSending));
@@ -526,8 +529,8 @@ PeerConnectionConfiguration::AddIceServer(const RTCIceServer &aServer)
if (!(isStun || isStuns || isTurn || isTurns)) {
return NS_ERROR_FAILURE;
}
- if (isTurns || isStuns) {
- continue; // TODO: Support TURNS and STUNS (Bug 1056934)
+ if (isStuns) {
+ continue; // TODO: Support STUNS (Bug 1056934)
}
nsAutoCString spec;
rv = url->GetSpec(spec);
@@ -576,6 +579,11 @@ PeerConnectionConfiguration::AddIceServer(const RTCIceServer &aServer)
if (port == -1)
port = (isStuns || isTurns)? 5349 : 3478;
+ if (isStuns || isTurns) {
+ // Should we barf if transport is set to udp or something?
+ transport = "tls";
+ }
+
// First check the known good ports for webrtc
bool knownGoodPort = false;
for (int i = 0; !knownGoodPort && gGoodWebrtcPortList[i]; i++) {
@@ -2255,6 +2263,11 @@ NS_IMETHODIMP
PeerConnectionImpl::AddIceCandidate(const char* aCandidate, const char* aMid, unsigned short aLevel) {
PC_AUTO_ENTER_API_CALL(true);
+ if (mForceIceTcp && std::string::npos != std::string(aCandidate).find(" UDP ")) {
+ CSFLogError(logTag, "Blocking remote UDP candidate: %s", aCandidate);
+ return NS_OK;
+ }
+
JSErrorResult rv;
RefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
if (!pco) {
@@ -3106,7 +3119,7 @@ PeerConnectionImpl::SetSignalingState_m(PCImplSignalingState aSignalingState,
mNegotiationNeeded = false;
// If we're rolling back a local offer, we might need to remove some
// transports, but nothing further needs to be done.
- mMedia->ActivateOrRemoveTransports(*mJsepSession);
+ mMedia->ActivateOrRemoveTransports(*mJsepSession, mForceIceTcp);
if (!rollback) {
mMedia->UpdateMediaPipelines(*mJsepSession);
InitializeDataChannel();
@@ -3268,6 +3281,11 @@ PeerConnectionImpl::CandidateReady(const std::string& candidate,
uint16_t level) {
PC_AUTO_ENTER_API_CALL_VOID_RETURN(false);
+ if (mForceIceTcp && std::string::npos != candidate.find(" UDP ")) {
+ CSFLogError(logTag, "Blocking local UDP candidate: %s", candidate.c_str());
+ return;
+ }
+
std::string mid;
bool skipped = false;
nsresult res = mJsepSession->AddLocalIceCandidate(candidate,
diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
index 7b53ea1160..098b34249a 100644
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -803,6 +803,7 @@ private:
bool mAllowIceLoopback;
bool mAllowIceLinkLocal;
+ bool mForceIceTcp;
RefPtr<PeerConnectionMedia> mMedia;
// The JSEP negotiation session.
diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
index 0d388a8f49..0306b57904 100644
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -457,7 +457,8 @@ PeerConnectionMedia::EnsureTransport_s(size_t aLevel, size_t aComponentCount)
}
void
-PeerConnectionMedia::ActivateOrRemoveTransports(const JsepSession& aSession)
+PeerConnectionMedia::ActivateOrRemoveTransports(const JsepSession& aSession,
+ const bool forceIceTcp)
{
auto transports = aSession.GetTransports();
for (size_t i = 0; i < transports.size(); ++i) {
@@ -480,6 +481,14 @@ PeerConnectionMedia::ActivateOrRemoveTransports(const JsepSession& aSession)
RemoveTransportFlow(i, true);
}
+ if (forceIceTcp) {
+ candidates.erase(std::remove_if(candidates.begin(),
+ candidates.end(),
+ [](const std::string & s) {
+ return s.find(" UDP "); }),
+ candidates.end());
+ }
+
RUN_ON_THREAD(
GetSTSThread(),
WrapRunnable(RefPtr<PeerConnectionMedia>(this),
diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
index c0001a5e54..8908e51546 100644
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
@@ -270,7 +270,8 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
// Activate or remove ICE transports at the conclusion of offer/answer,
// or when rollback occurs.
- void ActivateOrRemoveTransports(const JsepSession& aSession);
+ void ActivateOrRemoveTransports(const JsepSession& aSession,
+ const bool forceIceTcp);
// Start ICE checks.
void StartIceChecks(const JsepSession& session);
diff --git a/netwerk/base/nsISocketTransport.idl b/netwerk/base/nsISocketTransport.idl
index 9b5bc23fb7..3525aad5d9 100644
--- a/netwerk/base/nsISocketTransport.idl
+++ b/netwerk/base/nsISocketTransport.idl
@@ -130,6 +130,11 @@ interface nsISocketTransport : nsITransport
void setTimeout(in unsigned long aType, in unsigned long aValue);
/**
+ * True to set addr and port reuse socket options.
+ */
+ void setReuseAddrPort(in bool reuseAddrPort);
+
+ /**
* Values for the aType parameter passed to get/setTimeout.
*/
const unsigned long TIMEOUT_CONNECT = 0;
diff --git a/netwerk/base/nsSocketTransport2.cpp b/netwerk/base/nsSocketTransport2.cpp
index ff5fc3070d..ab20737443 100644
--- a/netwerk/base/nsSocketTransport2.cpp
+++ b/netwerk/base/nsSocketTransport2.cpp
@@ -737,6 +737,7 @@ nsSocketTransport::nsSocketTransport()
, mProxyTransparentResolvesHost(false)
, mHttpsProxy(false)
, mConnectionFlags(0)
+ , mReuseAddrPort(false)
, mState(STATE_CLOSED)
, mAttached(false)
, mInputClosed(true)
@@ -1354,6 +1355,32 @@ nsSocketTransport::InitiateSocket()
status = PR_SetSocketOption(fd, &opt);
NS_ASSERTION(status == PR_SUCCESS, "unable to make socket non-blocking");
+ if (mReuseAddrPort) {
+ SOCKET_LOG((" Setting port/addr reuse socket options\n"));
+
+ // Set ReuseAddr for TCP sockets to enable having several
+ // sockets bound to same local IP and port
+ PRSocketOptionData opt_reuseaddr;
+ opt_reuseaddr.option = PR_SockOpt_Reuseaddr;
+ opt_reuseaddr.value.reuse_addr = PR_TRUE;
+ status = PR_SetSocketOption(fd, &opt_reuseaddr);
+ if (status != PR_SUCCESS) {
+ SOCKET_LOG((" Couldn't set reuse addr socket option: %d\n",
+ status));
+ }
+
+ // And also set ReusePort for platforms supporting this socket option
+ PRSocketOptionData opt_reuseport;
+ opt_reuseport.option = PR_SockOpt_Reuseport;
+ opt_reuseport.value.reuse_port = PR_TRUE;
+ status = PR_SetSocketOption(fd, &opt_reuseport);
+ if (status != PR_SUCCESS
+ && PR_GetError() != PR_OPERATION_NOT_SUPPORTED_ERROR) {
+ SOCKET_LOG((" Couldn't set reuse port socket option: %d\n",
+ status));
+ }
+ }
+
// disable the nagle algorithm - if we rely on it to coalesce writes into
// full packets the final packet of a multi segment POST/PUT or pipeline
// sequence is delayed a full rtt
@@ -2469,6 +2496,13 @@ nsSocketTransport::SetTimeout(uint32_t type, uint32_t value)
}
NS_IMETHODIMP
+nsSocketTransport::SetReuseAddrPort(bool reuseAddrPort)
+{
+ mReuseAddrPort = reuseAddrPort;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
nsSocketTransport::SetQoSBits(uint8_t aQoSBits)
{
// Don't do any checking here of bits. Why? Because as of RFC-4594
diff --git a/netwerk/base/nsSocketTransport2.h b/netwerk/base/nsSocketTransport2.h
index 89b75efa57..a61e432b48 100644
--- a/netwerk/base/nsSocketTransport2.h
+++ b/netwerk/base/nsSocketTransport2.h
@@ -295,6 +295,7 @@ private:
bool mProxyTransparentResolvesHost;
bool mHttpsProxy;
uint32_t mConnectionFlags;
+ bool mReuseAddrPort;
// The origin attributes are used to create sockets. The first party domain
// will eventually be used to isolate OCSP cache and is only non-empty when
diff --git a/netwerk/protocol/http/TunnelUtils.cpp b/netwerk/protocol/http/TunnelUtils.cpp
index eeaf57f55c..01075d2c0c 100644
--- a/netwerk/protocol/http/TunnelUtils.cpp
+++ b/netwerk/protocol/http/TunnelUtils.cpp
@@ -1686,6 +1686,12 @@ SocketTransportShim::SetTimeout(uint32_t aType, uint32_t aValue)
}
NS_IMETHODIMP
+SocketTransportShim::SetReuseAddrPort(bool aReuseAddrPort)
+{
+ return mWrapped->SetReuseAddrPort(aReuseAddrPort);
+}
+
+NS_IMETHODIMP
SocketTransportShim::GetQoSBits(uint8_t *aQoSBits)
{
return mWrapped->GetQoSBits(aQoSBits);
diff --git a/testing/tools/iceserver/iceserver.py b/testing/tools/iceserver/iceserver.py
index 2089301af8..85d0f3ee54 100644
--- a/testing/tools/iceserver/iceserver.py
+++ b/testing/tools/iceserver/iceserver.py
@@ -10,7 +10,9 @@ import passlib.utils # for saslprep
import copy
import random
import operator
+import os
import platform
+import string
import time
from string import Template
from twisted.internet import reactor, protocol
@@ -715,6 +717,38 @@ def prune_allocations():
del allocations[key]
allocation.close()
+CERT_FILE = "selfsigned.crt"
+KEY_FILE = "private.key"
+
+def create_self_signed_cert(name):
+ from OpenSSL import crypto
+ if os.path.isfile(CERT_FILE) and os.path.isfile(KEY_FILE):
+ return
+
+ # create a key pair
+ k = crypto.PKey()
+ k.generate_key(crypto.TYPE_RSA, 1024)
+
+ # create a self-signed cert
+ cert = crypto.X509()
+ cert.get_subject().C = "US"
+ cert.get_subject().ST = "TX"
+ cert.get_subject().L = "Dallas"
+ cert.get_subject().O = "Mozilla test iceserver"
+ cert.get_subject().OU = "Mozilla test iceserver"
+ cert.get_subject().CN = name
+ cert.set_serial_number(1000)
+ cert.gmtime_adj_notBefore(0)
+ cert.gmtime_adj_notAfter(10*365*24*60*60)
+ cert.set_issuer(cert.get_subject())
+ cert.set_pubkey(k)
+ cert.sign(k, 'sha1')
+
+ open(CERT_FILE, "wt").write(
+ crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
+ open(KEY_FILE, "wt").write(
+ crypto.dump_privatekey(crypto.FILETYPE_PEM, k))
+
if __name__ == "__main__":
random.seed()
@@ -739,20 +773,48 @@ if __name__ == "__main__":
except:
pass
+ try:
+ from twisted.internet import ssl
+ from OpenSSL import SSL
+ create_self_signed_cert(hostname)
+ tls_context_factory = ssl.DefaultOpenSSLContextFactory(KEY_FILE, CERT_FILE, SSL.TLSv1_2_METHOD)
+ reactor.listenSSL(5349, TcpStunHandlerFactory(), tls_context_factory, interface=interface_4)
+
+ try:
+ reactor.listenSSL(5349, TcpStunHandlerFactory(), tls_context_factory, interface=interface_6)
+ except:
+ pass
+
+ f = open(CERT_FILE, 'r');
+ lines = f.readlines();
+ lines.pop(0); # Remove BEGIN CERTIFICATE
+ lines.pop(); # Remove END CERTIFICATE
+ lines = map(string.strip, lines);
+ certbase64 = string.join(lines, '');
+
+ turns_url = ', "turns:' + hostname + '"'
+ cert_prop = ', "cert":"' + certbase64 + '"'
+ except:
+ turns_url = ''
+ cert_prop = ''
+ pass
+
allocation_pruner = LoopingCall(prune_allocations)
allocation_pruner.start(1)
template = Template(
'[\
-{"url":"stun:$hostname"}, \
-{"url":"stun:$hostname?transport=tcp"}, \
-{"username":"$user","credential":"$pwd","url":"turn:$hostname"}, \
-{"username":"$user","credential":"$pwd","url":"turn:$hostname?transport=tcp"}]'
+{"urls":["stun:$hostname", "stun:$hostname?transport=tcp"]}, \
+{"username":"$user","credential":"$pwd","urls": \
+["turn:$hostname", "turn:$hostname?transport=tcp" $turns_url] \
+$cert_prop}]' # Hack to make it easier to override cert checks
)
print(template.substitute(user=turn_user,
pwd=turn_pass,
- hostname=hostname))
+ hostname=hostname,
+ turns_url=turns_url,
+ cert_prop=cert_prop))
reactor.run()