Bumping manifests a=b2g-bump
[gecko.git] / media / mtransport / stun_udp_socket_filter.cpp
blob9b530e1e014440f70f88a878500d0dcd5f482247
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 #include <string>
5 #include <set>
7 extern "C" {
8 #include "nr_api.h"
9 #include "transport_addr.h"
10 #include "stun.h"
13 #include "mozilla/Attributes.h"
14 #include "mozilla/net/DNS.h"
15 #include "stun_udp_socket_filter.h"
16 #include "nr_socket_prsock.h"
18 namespace {
20 class NetAddressAdapter {
21 public:
22 MOZ_IMPLICIT NetAddressAdapter(const mozilla::net::NetAddr& netaddr)
23 : addr_(ntohl(netaddr.inet.ip)),
24 port_(ntohs(netaddr.inet.port)) {
25 MOZ_ASSERT(netaddr.raw.family == AF_INET);
28 bool operator<(const NetAddressAdapter& rhs) const {
29 return addr_ != rhs.addr_ ? (addr_ < rhs.addr_) : (port_ < rhs.port_);
32 bool operator!=(const NetAddressAdapter& rhs) const {
33 return (*this < rhs) || (rhs < *this);
36 private:
37 const uint32_t addr_;
38 const uint16_t port_;
41 class PendingSTUNRequest {
42 public:
43 PendingSTUNRequest(const NetAddressAdapter& netaddr, const UINT12 &id)
44 : id_(id),
45 net_addr_(netaddr),
46 is_id_set_(true) {}
48 MOZ_IMPLICIT PendingSTUNRequest(const NetAddressAdapter& netaddr)
49 : id_(),
50 net_addr_(netaddr),
51 is_id_set_(false) {}
53 bool operator<(const PendingSTUNRequest& rhs) const {
54 if (net_addr_ != rhs.net_addr_) {
55 return net_addr_ < rhs.net_addr_;
58 if (!is_id_set_ && !rhs.is_id_set_) {
59 // PendingSTUNRequest can be stored to set only when it has id,
60 // so comparing two PendingSTUNRequst without id is not going
61 // to happen.
62 MOZ_CRASH();
65 if (!(is_id_set_ && rhs.is_id_set_)) {
66 // one of operands doesn't have id, ignore the difference.
67 return false;
70 return memcmp(id_.octet, rhs.id_.octet, sizeof(id_.octet)) < 0;
73 private:
74 const UINT12 id_;
75 const NetAddressAdapter net_addr_;
76 const bool is_id_set_;
79 class STUNUDPSocketFilter : public nsIUDPSocketFilter {
80 public:
81 STUNUDPSocketFilter()
82 : white_list_(),
83 pending_requests_() {}
85 NS_DECL_ISUPPORTS
86 NS_DECL_NSIUDPSOCKETFILTER
88 private:
89 virtual ~STUNUDPSocketFilter() {}
91 bool filter_incoming_packet(const mozilla::net::NetAddr *remote_addr,
92 const uint8_t *data,
93 uint32_t len);
95 bool filter_outgoing_packet(const mozilla::net::NetAddr *remote_addr,
96 const uint8_t *data,
97 uint32_t len);
99 std::set<NetAddressAdapter> white_list_;
100 std::set<PendingSTUNRequest> pending_requests_;
101 std::set<PendingSTUNRequest> response_allowed_;
104 NS_IMPL_ISUPPORTS(STUNUDPSocketFilter, nsIUDPSocketFilter)
106 NS_IMETHODIMP
107 STUNUDPSocketFilter::FilterPacket(const mozilla::net::NetAddr *remote_addr,
108 const uint8_t *data,
109 uint32_t len,
110 int32_t direction,
111 bool *result) {
112 // Allowing IPv4 address only.
113 if (remote_addr->raw.family != AF_INET) {
114 *result = false;
115 return NS_OK;
118 switch (direction) {
119 case nsIUDPSocketFilter::SF_INCOMING:
120 *result = filter_incoming_packet(remote_addr, data, len);
121 break;
122 case nsIUDPSocketFilter::SF_OUTGOING:
123 *result = filter_outgoing_packet(remote_addr, data, len);
124 break;
125 default:
126 MOZ_CRASH("Unknown packet direction");
128 return NS_OK;
131 bool STUNUDPSocketFilter::filter_incoming_packet(const mozilla::net::NetAddr *remote_addr,
132 const uint8_t *data, uint32_t len) {
133 // Check white list
134 if (white_list_.find(*remote_addr) != white_list_.end()) {
135 return true;
138 // Check if we had sent any stun request to this destination. If we had sent a request
139 // to this host, we check the transaction id, and we can add this address to whitelist.
140 std::set<PendingSTUNRequest>::iterator it =
141 pending_requests_.find(PendingSTUNRequest(*remote_addr));
142 if (it != pending_requests_.end()) {
143 if (nr_is_stun_message(reinterpret_cast<UCHAR*>(const_cast<uint8_t*>(data)), len)) {
144 const nr_stun_message_header *msg = reinterpret_cast<const nr_stun_message_header*>(data);
145 // If it is a STUN response message and we can match its id with one of the pending
146 // requests, we can add this address into whitelist.
147 if (nr_is_stun_response_message(reinterpret_cast<UCHAR*>(const_cast<uint8_t*>(data)), len)) {
148 PendingSTUNRequest pending_req(*remote_addr, msg->id);
149 std::set<PendingSTUNRequest>::iterator it = pending_requests_.find(pending_req);
150 if (it != pending_requests_.end()) {
151 pending_requests_.erase(it);
152 response_allowed_.erase(pending_req);
153 white_list_.insert(*remote_addr);
155 } else {
156 // If it is a STUN message, but not a response message, we add it into response
157 // allowed list and allow outgoing filter to send a response back.
158 response_allowed_.insert(PendingSTUNRequest(*remote_addr, msg->id));
161 return true;
164 return false;
167 bool STUNUDPSocketFilter::filter_outgoing_packet(const mozilla::net::NetAddr *remote_addr,
168 const uint8_t *data, uint32_t len) {
169 // Check white list
170 if (white_list_.find(*remote_addr) != white_list_.end()) {
171 return true;
174 // Check if it is a stun packet. If yes, we put it into a pending list and wait for
175 // response packet.
176 if (nr_is_stun_request_message(reinterpret_cast<UCHAR*>(const_cast<uint8_t*>(data)), len)) {
177 const nr_stun_message_header *msg = reinterpret_cast<const nr_stun_message_header*>(data);
178 pending_requests_.insert(PendingSTUNRequest(*remote_addr, msg->id));
179 return true;
182 // If it is a stun response packet, and we had received the request before, we can
183 // allow it packet to pass filter.
184 if (nr_is_stun_response_message(reinterpret_cast<UCHAR*>(const_cast<uint8_t*>(data)), len)) {
185 const nr_stun_message_header *msg = reinterpret_cast<const nr_stun_message_header*>(data);
186 std::set<PendingSTUNRequest>::iterator it =
187 response_allowed_.find(PendingSTUNRequest(*remote_addr, msg->id));
188 if (it != response_allowed_.end()) {
189 return true;
193 return false;
196 } // anonymous namespace
198 NS_IMPL_ISUPPORTS(nsStunUDPSocketFilterHandler, nsIUDPSocketFilterHandler)
200 NS_IMETHODIMP nsStunUDPSocketFilterHandler::NewFilter(nsIUDPSocketFilter **result)
202 nsIUDPSocketFilter *ret = new STUNUDPSocketFilter();
203 if (!ret) {
204 return NS_ERROR_OUT_OF_MEMORY;
206 NS_ADDREF(*result = ret);
207 return NS_OK;