mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 870660: Part 2: Implement socket filter for STUN. r=ekr
This commit is contained in:
parent
8e057af1da
commit
b5e6c1349b
@ -16,6 +16,13 @@
|
||||
|
||||
#define PEERCONNECTION_CONTRACTID "@mozilla.org/peerconnection;1"
|
||||
|
||||
#include "stun_udp_socket_filter.h"
|
||||
|
||||
NS_DEFINE_NAMED_CID(NS_STUN_UDP_SOCKET_FILTER_HANDLER_CID)
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsStunUDPSocketFilterHandler)
|
||||
|
||||
|
||||
namespace sipcc
|
||||
{
|
||||
// Factory defined in sipcc::, defines sipcc::PeerConnectionImplConstructor
|
||||
@ -27,11 +34,13 @@ NS_DEFINE_NAMED_CID(PEERCONNECTION_CID);
|
||||
|
||||
static const mozilla::Module::CIDEntry kCIDs[] = {
|
||||
{ &kPEERCONNECTION_CID, false, nullptr, sipcc::PeerConnectionImplConstructor },
|
||||
{ &kNS_STUN_UDP_SOCKET_FILTER_HANDLER_CID, false, nullptr, nsStunUDPSocketFilterHandlerConstructor },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module::ContractIDEntry kContracts[] = {
|
||||
{ PEERCONNECTION_CONTRACTID, &kPEERCONNECTION_CID },
|
||||
{ NS_STUN_UDP_SOCKET_FILTER_HANDLER_CONTRACTID, &kNS_STUN_UDP_SOCKET_FILTER_HANDLER_CID },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
|
@ -15,6 +15,7 @@ EXPORTS.mtransport += [
|
||||
'../runnable_utils_generated.h',
|
||||
'../sigslot.h',
|
||||
'../simpletokenbucket.h',
|
||||
'../stun_udp_socket_filter.h',
|
||||
'../transportflow.h',
|
||||
'../transportlayer.h',
|
||||
'../transportlayerdtls.h',
|
||||
|
@ -896,6 +896,8 @@ void NrSocketIpc::create_m(const nsACString &host, const uint16_t port) {
|
||||
MOZ_ASSERT(false, "Failed to create UDPSocketChild");
|
||||
}
|
||||
|
||||
socket_child_->SetFilterName(nsCString("stun"));
|
||||
|
||||
if (NS_FAILED(socket_child_->Bind(this, host, port))) {
|
||||
err_ = true;
|
||||
MOZ_ASSERT(false, "Failed to create UDP socket");
|
||||
|
@ -15,6 +15,7 @@ mtransport_lcppsrcs = [
|
||||
'nrinterfaceprioritizer.cpp',
|
||||
'rlogringbuffer.cpp',
|
||||
'simpletokenbucket.cpp',
|
||||
'stun_udp_socket_filter.cpp',
|
||||
'transportflow.cpp',
|
||||
'transportlayer.cpp',
|
||||
'transportlayerdtls.cpp',
|
||||
|
207
media/mtransport/stun_udp_socket_filter.cpp
Normal file
207
media/mtransport/stun_udp_socket_filter.cpp
Normal file
@ -0,0 +1,207 @@
|
||||
/* 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/. */
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
extern "C" {
|
||||
#include "nr_api.h"
|
||||
#include "transport_addr.h"
|
||||
#include "stun.h"
|
||||
}
|
||||
|
||||
#include "mozilla/net/DNS.h"
|
||||
#include "stun_udp_socket_filter.h"
|
||||
#include "nr_socket_prsock.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class NetAddressAdapter {
|
||||
public:
|
||||
NetAddressAdapter(const mozilla::net::NetAddr& netaddr)
|
||||
: addr_(ntohl(netaddr.inet.ip)),
|
||||
port_(ntohs(netaddr.inet.port)) {
|
||||
MOZ_ASSERT(netaddr.raw.family == AF_INET);
|
||||
}
|
||||
|
||||
bool operator<(const NetAddressAdapter& rhs) const {
|
||||
return addr_ != rhs.addr_ ? (addr_ < rhs.addr_) : (port_ < rhs.port_);
|
||||
}
|
||||
|
||||
bool operator!=(const NetAddressAdapter& rhs) const {
|
||||
return (*this < rhs) || (rhs < *this);
|
||||
}
|
||||
|
||||
private:
|
||||
const uint32_t addr_;
|
||||
const uint16_t port_;
|
||||
};
|
||||
|
||||
class PendingSTUNRequest {
|
||||
public:
|
||||
PendingSTUNRequest(const NetAddressAdapter& netaddr, const UINT12 &id)
|
||||
: id_(id),
|
||||
net_addr_(netaddr),
|
||||
is_id_set_(true) {}
|
||||
|
||||
PendingSTUNRequest(const NetAddressAdapter& netaddr)
|
||||
: id_(),
|
||||
net_addr_(netaddr),
|
||||
is_id_set_(false) {}
|
||||
|
||||
bool operator<(const PendingSTUNRequest& rhs) const {
|
||||
if (net_addr_ != rhs.net_addr_) {
|
||||
return net_addr_ < rhs.net_addr_;
|
||||
}
|
||||
|
||||
if (!is_id_set_ && !rhs.is_id_set_) {
|
||||
// PendingSTUNRequest can be stored to set only when it has id,
|
||||
// so comparing two PendingSTUNRequst without id is not going
|
||||
// to happen.
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
if (!(is_id_set_ && rhs.is_id_set_)) {
|
||||
// one of operands doesn't have id, ignore the difference.
|
||||
return false;
|
||||
}
|
||||
|
||||
return memcmp(id_.octet, rhs.id_.octet, sizeof(id_.octet)) < 0;
|
||||
}
|
||||
|
||||
private:
|
||||
const UINT12 id_;
|
||||
const NetAddressAdapter net_addr_;
|
||||
const bool is_id_set_;
|
||||
};
|
||||
|
||||
class STUNUDPSocketFilter : public nsIUDPSocketFilter {
|
||||
public:
|
||||
STUNUDPSocketFilter()
|
||||
: white_list_(),
|
||||
pending_requests_() {}
|
||||
|
||||
virtual ~STUNUDPSocketFilter() {}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIUDPSOCKETFILTER
|
||||
|
||||
private:
|
||||
bool filter_incoming_packet(const mozilla::net::NetAddr *remote_addr,
|
||||
const uint8_t *data,
|
||||
uint32_t len);
|
||||
|
||||
bool filter_outgoing_packet(const mozilla::net::NetAddr *remote_addr,
|
||||
const uint8_t *data,
|
||||
uint32_t len);
|
||||
|
||||
std::set<NetAddressAdapter> white_list_;
|
||||
std::set<PendingSTUNRequest> pending_requests_;
|
||||
std::set<PendingSTUNRequest> response_allowed_;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(STUNUDPSocketFilter, nsIUDPSocketFilter)
|
||||
|
||||
NS_IMETHODIMP
|
||||
STUNUDPSocketFilter::FilterPacket(const mozilla::net::NetAddr *remote_addr,
|
||||
const uint8_t *data,
|
||||
uint32_t len,
|
||||
int32_t direction,
|
||||
bool *result) {
|
||||
// Allowing IPv4 address only.
|
||||
if (remote_addr->raw.family != AF_INET) {
|
||||
*result = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
switch (direction) {
|
||||
case nsIUDPSocketFilter::SF_INCOMING:
|
||||
*result = filter_incoming_packet(remote_addr, data, len);
|
||||
break;
|
||||
case nsIUDPSocketFilter::SF_OUTGOING:
|
||||
*result = filter_outgoing_packet(remote_addr, data, len);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unknown packet direction");
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool STUNUDPSocketFilter::filter_incoming_packet(const mozilla::net::NetAddr *remote_addr,
|
||||
const uint8_t *data, uint32_t len) {
|
||||
// Check white list
|
||||
if (white_list_.find(*remote_addr) != white_list_.end()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if we had sent any stun request to this destination. If we had sent a request
|
||||
// to this host, we check the transaction id, and we can add this address to whitelist.
|
||||
std::set<PendingSTUNRequest>::iterator it =
|
||||
pending_requests_.find(PendingSTUNRequest(*remote_addr));
|
||||
if (it != pending_requests_.end()) {
|
||||
if (nr_is_stun_message(reinterpret_cast<UCHAR*>(const_cast<uint8_t*>(data)), len)) {
|
||||
const nr_stun_message_header *msg = reinterpret_cast<const nr_stun_message_header*>(data);
|
||||
// If it is a STUN response message and we can match its id with one of the pending
|
||||
// requests, we can add this address into whitelist.
|
||||
if (nr_is_stun_response_message(reinterpret_cast<UCHAR*>(const_cast<uint8_t*>(data)), len)) {
|
||||
PendingSTUNRequest pending_req(*remote_addr, msg->id);
|
||||
std::set<PendingSTUNRequest>::iterator it = pending_requests_.find(pending_req);
|
||||
if (it != pending_requests_.end()) {
|
||||
pending_requests_.erase(it);
|
||||
response_allowed_.erase(pending_req);
|
||||
white_list_.insert(*remote_addr);
|
||||
}
|
||||
} else {
|
||||
// If it is a STUN message, but not a response message, we add it into response
|
||||
// allowed list and allow outgoing filter to send a response back.
|
||||
response_allowed_.insert(PendingSTUNRequest(*remote_addr, msg->id));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool STUNUDPSocketFilter::filter_outgoing_packet(const mozilla::net::NetAddr *remote_addr,
|
||||
const uint8_t *data, uint32_t len) {
|
||||
// Check white list
|
||||
if (white_list_.find(*remote_addr) != white_list_.end()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if it is a stun packet. If yes, we put it into a pending list and wait for
|
||||
// response packet.
|
||||
if (nr_is_stun_request_message(reinterpret_cast<UCHAR*>(const_cast<uint8_t*>(data)), len)) {
|
||||
const nr_stun_message_header *msg = reinterpret_cast<const nr_stun_message_header*>(data);
|
||||
pending_requests_.insert(PendingSTUNRequest(*remote_addr, msg->id));
|
||||
return true;
|
||||
}
|
||||
|
||||
// If it is a stun response packet, and we had received the request before, we can
|
||||
// allow it packet to pass filter.
|
||||
if (nr_is_stun_response_message(reinterpret_cast<UCHAR*>(const_cast<uint8_t*>(data)), len)) {
|
||||
const nr_stun_message_header *msg = reinterpret_cast<const nr_stun_message_header*>(data);
|
||||
std::set<PendingSTUNRequest>::iterator it =
|
||||
response_allowed_.find(PendingSTUNRequest(*remote_addr, msg->id));
|
||||
if (it != response_allowed_.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsStunUDPSocketFilterHandler, nsIUDPSocketFilterHandler)
|
||||
|
||||
NS_IMETHODIMP nsStunUDPSocketFilterHandler::NewFilter(nsIUDPSocketFilter **result)
|
||||
{
|
||||
nsIUDPSocketFilter *ret = new STUNUDPSocketFilter();
|
||||
if (!ret) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
NS_ADDREF(*result = ret);
|
||||
return NS_OK;
|
||||
}
|
21
media/mtransport/stun_udp_socket_filter.h
Normal file
21
media/mtransport/stun_udp_socket_filter.h
Normal file
@ -0,0 +1,21 @@
|
||||
/* 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/. */
|
||||
#ifndef stun_udp_socket_filter_h__
|
||||
#define stun_udp_socket_filter_h__
|
||||
|
||||
#include "nsIUDPSocketFilter.h"
|
||||
|
||||
#define NS_STUN_UDP_SOCKET_FILTER_HANDLER_CONTRACTID NS_NETWORK_UDP_SOCKET_FILTER_HANDLER_PREFIX "stun"
|
||||
#define NS_STUN_UDP_SOCKET_FILTER_HANDLER_CID { 0x3e43ee93, 0x829e, 0x4ea6, \
|
||||
{ 0xa3, 0x4e, 0x62, 0xd9, 0xe4, 0xc9, 0xf9, 0x93 } };
|
||||
|
||||
class nsStunUDPSocketFilterHandler : public nsIUDPSocketFilterHandler {
|
||||
public:
|
||||
virtual ~nsStunUDPSocketFilterHandler() {}
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIUDPSOCKETFILTERHANDLER
|
||||
};
|
||||
|
||||
|
||||
#endif // stun_udp_socket_filter_h__
|
Loading…
Reference in New Issue
Block a user