Issue #1991 - Support TURN TLS Support in WebRTC Backport of Mozilla bug 1056934

This commit is contained in:
Basilisk-Dev 2022-08-20 14:21:43 -04:00 • committed by roytam1
commit 2dc4713d14
16 changed files with 282 additions and 26 deletions

View file

@ -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');
});

View file

@ -13,6 +13,7 @@ support-files =
blacksilence.js blacksilence.js
turnConfig.js turnConfig.js
sdpUtils.js sdpUtils.js
addTurnsSelfsignedCert.js
!/dom/canvas/test/captureStream_common.js !/dom/canvas/test/captureStream_common.js
!/dom/canvas/test/webgl-mochitest/webgl-util.js !/dom/canvas/test/webgl-mochitest/webgl-util.js
!/dom/media/test/manifest.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) skip-if = toolkit == 'android' # websockets don't work on android (bug 1266217)
[test_peerConnection_basicAudioNATRelayTCP.html] [test_peerConnection_basicAudioNATRelayTCP.html]
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_basicAudioNATRelayTLS.html]
skip-if = true # need pyopenssl on builders, see bug 1323439
[test_peerConnection_basicAudioRequireEOC.html] [test_peerConnection_basicAudioRequireEOC.html]
skip-if = (android_version == '18' && debug) # android(Bug 1189784, timeouts on 4.3 emulator) skip-if = (android_version == '18' && debug) # android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_basicAudioPcmaPcmuOnly.html] [test_peerConnection_basicAudioPcmaPcmuOnly.html]

View file

@ -1822,6 +1822,33 @@ function createHTML(options) {
var iceServerWebsocket; var iceServerWebsocket;
var iceServersArray = []; 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 => { var setupIceServerConfig = useIceServer => {
// We disable ICE support for HTTP proxy when using a TURN server, because // 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 // mochitest uses a fake HTTP proxy to serve content, which will eat our STUN
@ -1863,7 +1890,8 @@ var setupIceServerConfig = useIceServer => {
return enableHttpProxy(false) return enableHttpProxy(false)
.then(spawnIceServer) .then(spawnIceServer)
.then(iceServersStr => { iceServersArray = JSON.parse(iceServersStr); }); .then(iceServersStr => { iceServersArray = JSON.parse(iceServersStr); })
.then(addTurnsSelfsignedCerts);
}; };
function runNetworkTest(testFunction, fixtureOptions) { function runNetworkTest(testFunction, fixtureOptions) {

View file

@ -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>

View file

@ -167,9 +167,18 @@ TCPSocketParent::RecvOpenBind(const nsCString& aRemoteHost,
} }
nsCOMPtr<nsISocketTransport> socketTransport; nsCOMPtr<nsISocketTransport> 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, rv = sts->CreateTransport(nullptr, 0,
aRemoteHost, aRemotePort, aRemoteHost, aRemotePort,
nullptr, getter_AddRefs(socketTransport)); nullptr, getter_AddRefs(socketTransport));
}
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
FireInteralError(this, __LINE__); FireInteralError(this, __LINE__);
return true; return true;

View file

@ -858,6 +858,10 @@ int NrSocket::connect(nr_transport_addr *addr) {
PRNetAddr naddr; PRNetAddr naddr;
int32_t connect_status, getsockname_status; 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))) if ((r=nr_transport_addr_to_praddr(addr, &naddr)))
ABORT(r); ABORT(r);
@ -1840,7 +1844,7 @@ void NrTcpSocketIpc::close() {
} }
int NrTcpSocketIpc::connect(nr_transport_addr *addr) { 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; int32_t remote_port, local_port;
int r, _status; int r, _status;
if ((r=nr_transport_addr_get_addrstring_and_port(addr, if ((r=nr_transport_addr_get_addrstring_and_port(addr,
@ -1856,6 +1860,8 @@ int NrTcpSocketIpc::connect(nr_transport_addr *addr) {
ABORT(r); ABORT(r);
} }
tls_host = addr->tls_host;
state_ = mirror_state_ = NR_CONNECTING; state_ = mirror_state_ = NR_CONNECTING;
RUN_ON_THREAD(io_thread_, RUN_ON_THREAD(io_thread_,
mozilla::WrapRunnable(RefPtr<NrTcpSocketIpc>(this), mozilla::WrapRunnable(RefPtr<NrTcpSocketIpc>(this),
@ -1863,7 +1869,8 @@ int NrTcpSocketIpc::connect(nr_transport_addr *addr) {
remote_addr, remote_addr,
static_cast<uint16_t>(remote_port), static_cast<uint16_t>(remote_port),
local_addr, local_addr,
static_cast<uint16_t>(local_port)), static_cast<uint16_t>(local_port),
tls_host),
NS_DISPATCH_NORMAL); NS_DISPATCH_NORMAL);
// Make caller wait for ready to write. // 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, void NrTcpSocketIpc::connect_i(const nsACString &remote_addr,
uint16_t remote_port, uint16_t remote_port,
const nsACString &local_addr, const nsACString &local_addr,
uint16_t local_port) { uint16_t local_port,
const nsACString &tls_host) {
ASSERT_ON_THREAD(io_thread_); ASSERT_ON_THREAD(io_thread_);
mirror_state_ = NR_CONNECTING; mirror_state_ = NR_CONNECTING;
@ -1948,11 +1956,21 @@ void NrTcpSocketIpc::connect_i(const nsACString &remote_addr,
// Bug 1285330: put filtering back in here // Bug 1285330: put filtering back in here
if (tls_host.IsEmpty()) {
// XXX remove remote! // XXX remove remote!
socket_child_->SendWindowlessOpenBind(this, socket_child_->SendWindowlessOpenBind(this,
remote_addr, remote_port, remote_addr, remote_port,
local_addr, local_port, local_addr, local_port,
/* use ssl */ false); /* 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, void NrTcpSocketIpc::write_i(nsAutoPtr<InfallibleTArray<uint8_t>> arr,

View file

@ -369,7 +369,8 @@ private:
void connect_i(const nsACString &remote_addr, void connect_i(const nsACString &remote_addr,
uint16_t remote_port, uint16_t remote_port,
const nsACString &local_addr, const nsACString &local_addr,
uint16_t local_port); uint16_t local_port,
const nsACString &tls_host);
void write_i(nsAutoPtr<InfallibleTArray<uint8_t>> buf, void write_i(nsAutoPtr<InfallibleTArray<uint8_t>> buf,
uint32_t tracking_number); uint32_t tracking_number);
void close_i(); void close_i();

View file

@ -108,6 +108,7 @@ MOZ_MTLOG_MODULE("mtransport")
const char kNrIceTransportUdp[] = "udp"; const char kNrIceTransportUdp[] = "udp";
const char kNrIceTransportTcp[] = "tcp"; const char kNrIceTransportTcp[] = "tcp";
const char kNrIceTransportTls[] = "tls";
static bool initialized = false; static bool initialized = false;
@ -210,6 +211,9 @@ nsresult NrIceStunServer::ToNicerStunStruct(nr_ice_stun_server *server) const {
server->transport = IPPROTO_UDP; server->transport = IPPROTO_UDP;
} else if (transport_ == kNrIceTransportTcp) { } else if (transport_ == kNrIceTransportTcp) {
server->transport = IPPROTO_TCP; server->transport = IPPROTO_TCP;
} else if (transport_ == kNrIceTransportTls) {
server->transport = IPPROTO_TCP;
server->tls = 1;
} else { } else {
MOZ_MTLOG(ML_ERROR, "Unsupported STUN server transport: " << transport_); MOZ_MTLOG(ML_ERROR, "Unsupported STUN server transport: " << transport_);
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
@ -586,6 +590,7 @@ NrIceCtx::Initialize(const std::string& ufrag,
nsCString mapping_type; nsCString mapping_type;
nsCString filtering_type; nsCString filtering_type;
bool block_udp = false; bool block_udp = false;
bool block_tcp = false;
nsresult rv; nsresult rv;
nsCOMPtr<nsIPrefService> pref_service = nsCOMPtr<nsIPrefService> pref_service =
@ -604,6 +609,9 @@ NrIceCtx::Initialize(const std::string& ufrag,
rv = pref_branch->GetBoolPref( rv = pref_branch->GetBoolPref(
"media.peerconnection.nat_simulator.block_udp", "media.peerconnection.nat_simulator.block_udp",
&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->filtering_type_ = TestNat::ToNatBehavior(filtering_type.get());
test_nat->mapping_type_ = TestNat::ToNatBehavior(mapping_type.get()); test_nat->mapping_type_ = TestNat::ToNatBehavior(mapping_type.get());
test_nat->block_udp_ = block_udp; test_nat->block_udp_ = block_udp;
test_nat->block_tcp_ = block_tcp;
test_nat->enabled_ = true; test_nat->enabled_ = true;
SetNat(test_nat); SetNat(test_nat);
} }

View file

@ -90,6 +90,7 @@ class NrIceMediaStream;
extern const char kNrIceTransportUdp[]; extern const char kNrIceTransportUdp[];
extern const char kNrIceTransportTcp[]; extern const char kNrIceTransportTcp[];
extern const char kNrIceTransportTls[];
class NrIceStunServer { class NrIceStunServer {
public: public:

View file

@ -200,6 +200,7 @@ int TestNat::create_socket_factory(nr_socket_factory **factorypp) {
TestNrSocket::TestNrSocket(TestNat *nat) TestNrSocket::TestNrSocket(TestNat *nat)
: nat_(nat), : nat_(nat),
tls_(false),
timer_handle_(nullptr) { timer_handle_(nullptr) {
nat_->insert_socket(this); nat_->insert_socket(this);
} }
@ -473,6 +474,10 @@ int TestNrSocket::connect(nr_transport_addr *addr) {
return R_INTERNAL; return R_INTERNAL;
} }
if (addr->tls_host[0] != '\0') {
tls_ = true;
}
if (!nat_->enabled_ if (!nat_->enabled_
|| addr->protocol==IPPROTO_UDP // Horrible hack to allow default address || addr->protocol==IPPROTO_UDP // Horrible hack to allow default address
// discovery to work. Only works because // 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) { 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()) { if (port_mappings_.empty()) {
// The no-nat case, just pass call through. // 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 { } else {
destroy_stale_port_mappings(); destroy_stale_port_mappings();
if (port_mappings_.empty()) { 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 // This is TCP only
MOZ_ASSERT(port_mappings_.size() == 1); 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 TestNrSocket::read(void *buf, size_t maxlen, size_t *len) {
int r;
if (port_mappings_.empty()) { if (port_mappings_.empty()) {
return internal_socket_->read(buf, maxlen, len); r = internal_socket_->read(buf, maxlen, len);
} else { } else {
MOZ_ASSERT(port_mappings_.size() == 1); MOZ_ASSERT(port_mappings_.size() == 1);
int bytesRead = r = port_mappings_.front()->external_socket_->read(buf, maxlen, len);
port_mappings_.front()->external_socket_->read(buf, maxlen, len); if (!r && nat_->refresh_on_ingress_) {
if (bytesRead > 0 && nat_->refresh_on_ingress_) {
port_mappings_.front()->last_used_ = PR_IntervalNow(); 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, int TestNrSocket::async_wait(int how, NR_async_cb cb, void *cb_arg,

View file

@ -137,6 +137,7 @@ class TestNat {
refresh_on_ingress_(false), refresh_on_ingress_(false),
block_udp_(false), block_udp_(false),
block_stun_(false), block_stun_(false),
block_tcp_(false),
delay_stun_resp_ms_(0), delay_stun_resp_ms_(0),
sockets_() {} sockets_() {}
@ -168,6 +169,7 @@ class TestNat {
bool refresh_on_ingress_; bool refresh_on_ingress_;
bool block_udp_; bool block_udp_;
bool block_stun_; bool block_stun_;
bool block_tcp_;
/* Note: this can only delay a single response so far (bug 1253657) */ /* Note: this can only delay a single response so far (bug 1253657) */
uint32_t delay_stun_resp_ms_; uint32_t delay_stun_resp_ms_;
@ -319,6 +321,7 @@ class TestNrSocket : public NrSocketBase {
// same nat. // same nat.
RefPtr<NrSocketBase> internal_socket_; RefPtr<NrSocketBase> internal_socket_;
RefPtr<TestNat> nat_; RefPtr<TestNat> nat_;
bool tls_;
// Since our comparison logic is different depending on what kind of NAT // 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 // 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 // comparison function at runtime, and these lists are going to be very

View file

@ -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)) if(r=nr_transport_addr_copy(&cand->stun_server_addr,addr))
ABORT(r); 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 (cand->tcp_type == TCP_TYPE_PASSIVE || cand->tcp_type == TCP_TYPE_SO){
if (r=nr_socket_multi_tcp_stun_server_connect(cand->osock, addr)) if (r=nr_socket_multi_tcp_stun_server_connect(cand->osock, addr))
ABORT(r); ABORT(r);

View file

@ -63,6 +63,7 @@ typedef struct nr_ice_stun_server_ {
} u; } u;
int id; int id;
int transport; int transport;
int tls; /* Whether to use TLS or not */
} nr_ice_stun_server; } nr_ice_stun_server;
typedef struct nr_ice_turn_server_ { typedef struct nr_ice_turn_server_ {

View file

@ -66,6 +66,7 @@ typedef struct nr_transport_addr_ {
/* A string version. /* A string version.
56 = 5 ("IP6:[") + 39 (ipv6 address) + 2 ("]:") + 5 (port) + 4 (/UDP) + 1 (null) */ 56 = 5 ("IP6:[") + 39 (ipv6 address) + 2 ("]:") + 5 (port) + 4 (/UDP) + 1 (null) */
char as_string[56]; char as_string[56];
char tls_host[256];
} nr_transport_addr; } nr_transport_addr;
typedef struct nr_transport_addr_mask_ { typedef struct nr_transport_addr_mask_ {

View file

@ -526,8 +526,8 @@ PeerConnectionConfiguration::AddIceServer(const RTCIceServer &aServer)
if (!(isStun || isStuns || isTurn || isTurns)) { if (!(isStun || isStuns || isTurn || isTurns)) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
if (isTurns || isStuns) { if (isStuns) {
continue; // TODO: Support TURNS and STUNS (Bug 1056934) continue; // TODO: Support STUNS (Bug 1056934)
} }
nsAutoCString spec; nsAutoCString spec;
rv = url->GetSpec(spec); rv = url->GetSpec(spec);
@ -576,6 +576,11 @@ PeerConnectionConfiguration::AddIceServer(const RTCIceServer &aServer)
if (port == -1) if (port == -1)
port = (isStuns || isTurns)? 5349 : 3478; 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 // First check the known good ports for webrtc
bool knownGoodPort = false; bool knownGoodPort = false;
for (int i = 0; !knownGoodPort && gGoodWebrtcPortList[i]; i++) { for (int i = 0; !knownGoodPort && gGoodWebrtcPortList[i]; i++) {

View file

@ -10,7 +10,9 @@ import passlib.utils # for saslprep
import copy import copy
import random import random
import operator import operator
import os
import platform import platform
import string
import time import time
from string import Template from string import Template
from twisted.internet import reactor, protocol from twisted.internet import reactor, protocol
@ -715,6 +717,38 @@ def prune_allocations():
del allocations[key] del allocations[key]
allocation.close() 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__": if __name__ == "__main__":
random.seed() random.seed()
@ -739,20 +773,48 @@ if __name__ == "__main__":
except: except:
pass 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 = LoopingCall(prune_allocations)
allocation_pruner.start(1) allocation_pruner.start(1)
template = Template( template = Template(
'[\ '[\
{"url":"stun:$hostname"}, \ {"urls":["stun:$hostname", "stun:$hostname?transport=tcp"]}, \
{"url":"stun:$hostname?transport=tcp"}, \ {"username":"$user","credential":"$pwd","urls": \
{"username":"$user","credential":"$pwd","url":"turn:$hostname"}, \ ["turn:$hostname", "turn:$hostname?transport=tcp" $turns_url] \
{"username":"$user","credential":"$pwd","url":"turn:$hostname?transport=tcp"}]' $cert_prop}]' # Hack to make it easier to override cert checks
) )
print(template.substitute(user=turn_user, print(template.substitute(user=turn_user,
pwd=turn_pass, pwd=turn_pass,
hostname=hostname)) hostname=hostname,
turns_url=turns_url,
cert_prop=cert_prop))
reactor.run() reactor.run()