Beispiel #1
0
class StunUdpServer(StunUdpProtocol):
    def __init__(self, reactor, interface, port, software):
        StunUdpProtocol.__init__(self, reactor, interface, port, software)

    def respond(self, response, addr):
        response.add_attr(attributes.Software, self.software)
        self.credential_mechanism.update(response)
        response.add_attr(attributes.Fingerprint)
        self.transport.write(response, addr)
        logger.info("%s Sending response", self)
        logger.debug(response.format())

    def _stun_binding_request(self, msg, (host, port)):
        if msg.msg_class == stun.CLASS_REQUEST:
            unknown_attributes = msg.unknown_comp_required_attrs()
            if unknown_attributes:
                response = Message.encode(stun.METHOD_BINDING,
                                               stun.CLASS_RESPONSE_ERROR,
                                               transaction_id=msg.transaction_id)
                response.add_attr(attributes.ErrorCode, *stun.ERR_UNKNOWN_ATTRIBUTE)
                response.add_attr(attributes.UnknownAttributes, unknown_attributes)
            else:
                response = Message.encode(stun.METHOD_BINDING,
                                               stun.CLASS_RESPONSE_SUCCESS,
                                               transaction_id=msg.transaction_id)
                family = Address.aftof(self.transport.addressFamily)
                response.add_attr(attributes.XorMappedAddress, family, port, host)
                response.add_attr(attributes.Software, self.software)
                response.add_attr(attributes.Fingerprint)
            self.respond(response, (host, port))
Beispiel #2
0
 def allocate(cls, server, client_addr, port=0):
     relay = cls(server, client_addr)
     port = server.reactor.listenUDP(port, relay, server.interface)
     family = Address.aftof(relay.transport.socket.family)
     relay_ip, port = relay.transport.socket.getsockname()
     relay.relay_addr = (family, port, relay_ip)
     logger.info("%s Allocated", relay)
     return relay
Beispiel #3
0
 def allocate(cls, server, client_addr, port=0):
     relay = cls(server, client_addr)
     port = server.reactor.listenUDP(port, relay, server.interface)
     family = Address.aftof(relay.transport.socket.family)
     relay_ip, port = relay.transport.socket.getsockname()[:2]
     relay.relay_addr = (family, port, relay_ip)
     logger.info("%s Allocated", relay)
     return relay
Beispiel #4
0
 def _stun_binding_request(self, msg, addr):
     if msg.msg_class == stun.CLASS_REQUEST:
         unknown_attributes = msg.unknown_comp_required_attrs()
         if unknown_attributes:
             response = Message.encode(stun.METHOD_BINDING,
                                            stun.CLASS_RESPONSE_ERROR,
                                            transaction_id=msg.transaction_id)
             response.add_attr(attributes.ErrorCode, *stun.ERR_UNKNOWN_ATTRIBUTE)
             response.add_attr(attributes.UnknownAttributes, unknown_attributes)
         else:
             response = Message.encode(stun.METHOD_BINDING,
                                            stun.CLASS_RESPONSE_SUCCESS,
                                            transaction_id=msg.transaction_id)
             family = Address.aftof(self.transport.addressFamily)
             host, port = self.overrides.get('mapped_address', addr)
             response.add_attr(attributes.XorMappedAddress, family, port, host)
             response.add_attr(attributes.Software, self.software)
     self.transport.write(response, addr)
     logger.info("%s Sending response", self)
     logger.debug(response.format())
Beispiel #5
0
 def datagramReceived(self, datagram, addr):
     """
     :see: http://tools.ietf.org/html/rfc5766#section-10.3
     """
     logger.info("%s <- %s:%d", self, *addr)
     host, port = addr
     if host in self.permissions:
         channel = self._channels.get(addr)
         if channel:
             # TODO: send channel message to client
             raise NotImplementedError("Send channel message")
         else:
             msg = Message.encode(turn.METHOD_DATA, stun.CLASS_INDICATION)
             family = Address.aftof(self.transport.addressFamily)
             msg.add_attr(attributes.XorPeerAddress, family, port, host)
             msg.add_attr(attributes.Data, datagram)
         self.server.transport.write(msg, self.client_addr)
     else:
         logger.warning("No permissions for %s: Dropping datagram", host)
         logger.debug(datagram.encode('hex'))
Beispiel #6
0
 def datagramReceived(self, datagram, addr):
     """
     :see: http://tools.ietf.org/html/rfc5766#section-10.3
     """
     logger.info("%s <- %s:%d", self, *addr)
     host, port = addr
     if host in self.permissions:
         channel = self._channels.get(addr)
         if channel:
             # TODO: send channel message to client
             raise NotImplementedError("Send channel message")
         else:
             msg = Message.encode(turn.METHOD_DATA,
                                  stun.CLASS_INDICATION)
             family = Address.aftof(self.transport.addressFamily)
             msg.add_attr(attributes.XorPeerAddress, family, port, host)
             msg.add_attr(attributes.Data, datagram)
         self.server.transport.write(msg, self.client_addr)
     else:
         logger.warning("No permissions for %s: Dropping datagram", host)
         logger.debug(datagram.encode('hex'))
Beispiel #7
0
 def _stun_binding_request(self, msg, addr):
     if msg.msg_class == stun.CLASS_REQUEST:
         unknown_attributes = msg.unknown_comp_required_attrs()
         if unknown_attributes:
             response = Message.encode(stun.METHOD_BINDING,
                                       stun.CLASS_RESPONSE_ERROR,
                                       transaction_id=msg.transaction_id)
             response.add_attr(attributes.ErrorCode,
                               *stun.ERR_UNKNOWN_ATTRIBUTE)
             response.add_attr(attributes.UnknownAttributes,
                               unknown_attributes)
         else:
             response = Message.encode(stun.METHOD_BINDING,
                                       stun.CLASS_RESPONSE_SUCCESS,
                                       transaction_id=msg.transaction_id)
             family = Address.aftof(self.transport.addressFamily)
             host, port = self.overrides.get('mapped_address', addr)
             response.add_attr(attributes.XorMappedAddress, family, port,
                               host)
             response.add_attr(attributes.Software, self.software)
     self.transport.write(response, addr)
     logger.info("%s Sending response", self)
     logger.debug(response.format())
Beispiel #8
0
    def _stun_allocate_request(self, msg, addr):
        """
        :see: http://tools.ietf.org/html/rfc5766#section-6.2
        """
        # Detect retransmission, resend success response
        relay_allocation = self._relays.get(addr)
        if relay_allocation and relay_allocation.transaction_id == msg.transaction_id:
            # TODO: handle allocate retransmission
            raise NotImplementedError("Allocation retransmission")

        # 1. require request to be authenticated
        message_integrity = msg.get_attr(stun.ATTR_MESSAGE_INTEGRITY)
        if not message_integrity:
            response = msg.create_response(stun.CLASS_RESPONSE_ERROR)
            response.add_attr(ErrorCode, *stun.ERR_UNAUTHORIZED)
            self.respond(response, addr)
            return

        # 2. Check if the 5-tuple is currently in use
        if relay_allocation:
            response = msg.create_response(stun.CLASS_RESPONSE_ERROR)
            response.add_attr(ErrorCode, *turn.ERR_ALLOCATION_MISMATCH)
            self.respond(response, addr)
            return

        # 3. Check REQUESTED-TRANSPORT attribute
        requested_transport = msg.get_attr(turn.ATTR_REQUESTED_TRANSPORT)
        if not requested_transport:
            response = msg.create_response(stun.CLASS_RESPONSE_ERROR)
            response.add_attr(ErrorCode, *stun.ERR_BAD_REQUEST)
            self.respond(response, addr)
            return
        elif requested_transport.protocol != turn.TRANSPORT_UDP:
            response = msg.create_response(stun.CLASS_RESPONSE_ERROR)
            response.add_attr(ErrorCode, *turn.ERR_UNSUPPORTED_TRANSPORT_PROTOCOL)
            self.respond(response, addr)
            return

        # 4. handle DONT-FRAGMENT attribute

        # 5. Check RESERVATION-TOKEN attribute
        reservation_token = msg.get_attr(turn.ATTR_RESERVATION_TOKEN)
        even_port = msg.get_attr(turn.ATTR_EVEN_PORT)
        if reservation_token:
            if even_port:
                pass # TODO: reject with 400
            relay_addr = self.get_reserved_transport_address(reservation_token)
            # TODO: check that token is in range and has not expired
            # and that corresponding relayed address is still available
            # if token not valid, reject with 508
        # 7. reject with 486 if username allocation quota reached
        # 8. reject with 300 if we want to redirect to another server RFC5389
        # 6. Check EVEN-PORT
        else:
            relay, token = self._allocate_relay_addr(even_port, addr)
            relay.transaction_id = msg.transaction_id
            relay_addr = relay.relay_addr

        # Determine initial time-to-expiry
        time_to_expiry = self._time_to_expiry(msg.get_attr(turn.ATTR_LIFETIME))

        response = msg.create_response(stun.CLASS_RESPONSE_SUCCESS)
        response.add_attr(XorRelayedAddress, *relay_addr)
        if token:
            response.add_attr(ReservationToken, token)
        response.add_attr(Lifetime, time_to_expiry)
        family = Address.aftof(self.transport.addressFamily)
        host, port = addr
        response.add_attr(XorMappedAddress, family, port, host)

        self.respond(response, addr)
Beispiel #9
0
    def _stun_allocate_request(self, msg, addr):
        """
        :see: http://tools.ietf.org/html/rfc5766#section-6.2
        """
        # Detect retransmission, resend success response
        relay_allocation = self._relays.get(addr)
        if relay_allocation and relay_allocation.transaction_id == msg.transaction_id:
            # TODO: handle allocate retransmission
            raise NotImplementedError("Allocation retransmission")

        # 1. require request to be authenticated
        message_integrity = msg.get_attr(stun.ATTR_MESSAGE_INTEGRITY)
        if not message_integrity:
            response = msg.create_response(stun.CLASS_RESPONSE_ERROR)
            response.add_attr(ErrorCode, *stun.ERR_UNAUTHORIZED)
            self.respond(response, addr)
            return

        # 2. Check if the 5-tuple is currently in use
        if relay_allocation:
            response = msg.create_response(stun.CLASS_RESPONSE_ERROR)
            response.add_attr(ErrorCode, *turn.ERR_ALLOCATION_MISMATCH)
            self.respond(response, addr)
            return

        # 3. Check REQUESTED-TRANSPORT attribute
        requested_transport = msg.get_attr(turn.ATTR_REQUESTED_TRANSPORT)
        if not requested_transport:
            response = msg.create_response(stun.CLASS_RESPONSE_ERROR)
            response.add_attr(ErrorCode, *stun.ERR_BAD_REQUEST)
            self.respond(response, addr)
            return
        elif requested_transport.protocol != turn.TRANSPORT_UDP:
            response = msg.create_response(stun.CLASS_RESPONSE_ERROR)
            response.add_attr(ErrorCode,
                              *turn.ERR_UNSUPPORTED_TRANSPORT_PROTOCOL)
            self.respond(response, addr)
            return

        # 4. handle DONT-FRAGMENT attribute

        # 5. Check RESERVATION-TOKEN attribute
        reservation_token = msg.get_attr(turn.ATTR_RESERVATION_TOKEN)
        even_port = msg.get_attr(turn.ATTR_EVEN_PORT)
        if reservation_token:
            if even_port:
                pass  # TODO: reject with 400
            relay_addr = self.get_reserved_transport_address(reservation_token)
            # TODO: check that token is in range and has not expired
            # and that corresponding relayed address is still available
            # if token not valid, reject with 508
        # 7. reject with 486 if username allocation quota reached
        # 8. reject with 300 if we want to redirect to another server RFC5389
        # 6. Check EVEN-PORT
        else:
            relay, token = self._allocate_relay_addr(even_port, addr)
            relay.transaction_id = msg.transaction_id
            relay_addr = relay.relay_addr

        # Determine initial time-to-expiry
        time_to_expiry = self._time_to_expiry(msg.get_attr(turn.ATTR_LIFETIME))

        response = msg.create_response(stun.CLASS_RESPONSE_SUCCESS)
        response.add_attr(XorRelayedAddress, *relay_addr)
        if token:
            response.add_attr(ReservationToken, token)
        response.add_attr(Lifetime, time_to_expiry)
        family = Address.aftof(self.transport.addressFamily)
        host, port = self.overrides.get('mapped_address', addr)
        response.add_attr(XorMappedAddress, family, port, host)

        self.respond(response, addr)