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; }
int TestNrSocket::sendto(const void *msg, size_t len, int flags, nr_transport_addr *to) { MOZ_ASSERT(internal_socket_->my_addr().protocol != IPPROTO_TCP); UCHAR *buf = static_cast<UCHAR*>(const_cast<void*>(msg)); if (nat_->block_stun_ && nr_is_stun_message(buf, len)) { return 0; } /* TODO: improve the functionality of this in bug 1253657 */ if (!nat_->enabled_ || nat_->is_an_internal_tuple(*to)) { if (nat_->delay_stun_resp_ms_ && nr_is_stun_response_message(buf, len)) { NR_ASYNC_TIMER_SET(nat_->delay_stun_resp_ms_, process_delayed_cb, new DeferredPacket(this, msg, len, flags, to, internal_socket_), &timer_handle_); return 0; } return internal_socket_->sendto(msg, len, flags, to); } destroy_stale_port_mappings(); if (to->protocol == IPPROTO_UDP && nat_->block_udp_) { // Silently eat the packet return 0; } // Choose our port mapping based on our most selective criteria PortMapping *port_mapping = get_port_mapping(*to, std::max(nat_->filtering_type_, nat_->mapping_type_)); if (!port_mapping) { // See if we have already made the external socket we need to use. PortMapping *similar_port_mapping = get_port_mapping(*to, nat_->mapping_type_); RefPtr<NrSocketBase> external_socket; if (similar_port_mapping) { external_socket = similar_port_mapping->external_socket_; } else { external_socket = create_external_socket(*to); if (!external_socket) { MOZ_ASSERT(false); return R_INTERNAL; } } port_mapping = create_port_mapping(*to, external_socket); port_mappings_.push_back(port_mapping); if (poll_flags() & PR_POLL_READ) { // Make sure the new port mapping is ready to receive traffic if the // TestNrSocket is already waiting. port_mapping->async_wait(NR_ASYNC_WAIT_READ, socket_readable_callback, this, (char*)__FUNCTION__, __LINE__); } } // We probably don't want to propagate the flags, since this is a simulated // external IP address. return port_mapping->sendto(msg, len, *to); }