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))
def bind(self, addr): """ :see: http://tools.ietf.org/html/rfc5389#section-7.1 """ request = Message.encode(stun.METHOD_BINDING, stun.CLASS_REQUEST) request.add_attr(attributes.Software, self.software) return self.request(request, addr)
def refresh(self, time_to_expiry): """ :see: http://tools.ietf.org/html/rfc5766#section-6 """ request = Message.encode(turn.METHOD_REFRESH, stun.CLASS_REQUEST) if time_to_expiry: request.add_attr(turn.ATTR_LIFETIME, time_to_expiry)
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())
def setUp(self): msg_data = ( '011300602112a442fedcb2d51f23946d' '9cc9754e0009001000000401556e6175' '74686f72697365640015001036303332' '3763313731343561373738380014000a' '7765627274632e6f72678e4f8022001a' '4369747269782d312e382e372e302027' '426c61636b20446f77270004' '802800045a4c0c70' # Fingerprint ).decode('hex') self.msg = Message.decode(msg_data)
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'))
def test_encode(self): msg = Message.encode(stun.METHOD_BINDING, stun.CLASS_REQUEST, transaction_id='fixedtransid') # Override padding generation to make the message data deterministic msg._padding = '\x00'.__mul__ # Pad with zero bytes msg.add_attr(type('Foo', (Unknown, ), {'type': 0x6666}), 'data') msg.add_attr(attributes.MappedAddress, Address.FAMILY_IPv4, 1337, '192.168.2.255') msg.add_attr(attributes.Username, "johndoe") msg.add_attr(attributes.MessageIntegrity, ha1('username', 'realm', 'password')) msg.add_attr(attributes.ErrorCode, *stun.ERR_SERVER_ERROR) msg.add_attr(attributes.UnknownAttributes, [0x1337, 0xb00b, 0xbeef]) msg.add_attr(attributes.Realm, "pexip.com") msg.add_attr(attributes.Nonce, '36303332376331373134356137373838'.decode('hex')) msg.add_attr(attributes.XorMappedAddress, Address.FAMILY_IPv4, 1337, '192.168.2.255') msg.add_attr(attributes.Software, u"\u8774\u8776 h\xfadi\xe9 'butterfly'") msg.add_attr(attributes.AlternateServer, Address.FAMILY_IPv4, 8008, '192.168.2.128') msg.add_attr(attributes.Fingerprint) msg_data = ('000100bc2112a4426669786564747261' '6e736964666600046461746100010008' '00010539c0a802ff000600076a6f686e' '646f6500000800144ad36bd8d0c242f6' 'a2b98ccbcfe0f21432261fb400090010' '00000500536572766572204572726f72' '000a00061337b00bbeef000000140009' '70657869702e636f6d00000000150010' '36303332376331373134356137373838' '002000080001242be1baa6bd8022001a' 'e89db4e89db62068c3ba6469c3a92027' '627574746572666c7927000080230008' '00011f48c0a8028080280004e43217b7').decode('hex') self.assertEqual(str(msg), msg_data)
def test_encode(self): msg = Message.encode(stun.METHOD_BINDING, stun.CLASS_REQUEST, transaction_id='fixedtransid') # Override padding generation to make the message data deterministic msg._padding = '\x00'.__mul__ # Pad with zero bytes msg.add_attr(type('Foo', (Unknown,), {'type': 0x6666}), 'data') msg.add_attr(attributes.MappedAddress, Address.FAMILY_IPv4, 1337, '192.168.2.255') msg.add_attr(attributes.Username, "johndoe") msg.add_attr(attributes.MessageIntegrity, ha1('username', 'realm', 'password')) msg.add_attr(attributes.ErrorCode, *stun.ERR_SERVER_ERROR) msg.add_attr(attributes.UnknownAttributes, [0x1337, 0xb00b, 0xbeef]) msg.add_attr(attributes.Realm, "pexip.com") msg.add_attr(attributes.Nonce, '36303332376331373134356137373838'.decode('hex')) msg.add_attr(attributes.XorMappedAddress, Address.FAMILY_IPv4, 1337, '192.168.2.255') msg.add_attr(attributes.Software, u"\u8774\u8776 h\xfadi\xe9 'butterfly'") msg.add_attr(attributes.AlternateServer, Address.FAMILY_IPv4, 8008, '192.168.2.128') msg.add_attr(attributes.Fingerprint) msg_data = ( '000100bc2112a4426669786564747261' '6e736964666600046461746100010008' '00010539c0a802ff000600076a6f686e' '646f6500000800144ad36bd8d0c242f6' 'a2b98ccbcfe0f21432261fb400090010' '00000500536572766572204572726f72' '000a00061337b00bbeef000000140009' '70657869702e636f6d00000000150010' '36303332376331373134356137373838' '002000080001242be1baa6bd8022001a' 'e89db4e89db62068c3ba6469c3a92027' '627574746572666c7927000080230008' '00011f48c0a8028080280004e43217b7' ).decode('hex') self.assertEqual(str(msg), msg_data)
def allocate(self, addr, transport=turn.TRANSPORT_UDP, time_to_expiry=None, dont_fragment=False, even_port=None, reservation_token=None): """ :param even_port: None | 0 | 1 (1==reserve next highest port number) :see: http://tools.ietf.org/html/rfc5766#section-6.1 """ request = Message.encode(turn.METHOD_ALLOCATE, stun.CLASS_REQUEST) request.add_attr(attributes.RequestedTransport, transport) if time_to_expiry: request.add_attr(turn.ATTR_LIFETIME, time_to_expiry) if dont_fragment: request.add_attr(turn.ATTR_DONT_FRAGMENT) if even_port is not None and not reservation_token: request.add_attr(turn.ATTR_EVEN_PORT, even_port) if reservation_token: request.add_attr(turn.ATTR_RESERVATION_TOKEN, even_port) transaction = self.request(request, addr) transaction.addErrback def retry(failure): nonce = failure.value.get_attr(stun.ATTR_NONCE) realm = str(failure.value.get_attr(stun.ATTR_REALM)) self.credential_mechanism = LongTermCredentialMechanism(nonce, realm, 'username', 'password') logger.debug("Retrying allocation with %s", self.credential_mechanism) transaction.addCallback(lambda result: self.allocate(addr))