1
2
3 """Simple Traversal of UDP through NAT."""
4 from __future__ import print_function
5 from __future__ import absolute_import
6
7 import struct
8
9 from . import dpkt
10
11
12
13
14
15
16 BINDING_REQUEST = 0x0001
17 BINDING_RESPONSE = 0x0101
18 BINDING_ERROR_RESPONSE = 0x0111
19 SHARED_SECRET_REQUEST = 0x0002
20 SHARED_SECRET_RESPONSE = 0x0102
21 SHARED_SECRET_ERROR_RESPONSE = 0x0112
22
23
24 MAPPED_ADDRESS = 0x0001
25 RESPONSE_ADDRESS = 0x0002
26 CHANGE_REQUEST = 0x0003
27 SOURCE_ADDRESS = 0x0004
28 CHANGED_ADDRESS = 0x0005
29 USERNAME = 0x0006
30 PASSWORD = 0x0007
31 MESSAGE_INTEGRITY = 0x0008
32 ERROR_CODE = 0x0009
33 UNKNOWN_ATTRIBUTES = 0x000a
34 REFLECTED_FROM = 0x000b
35
36
37 -class STUN(dpkt.Packet):
38 """Simple Traversal of UDP through NAT.
39
40 STUN - RFC 3489
41 http://tools.ietf.org/html/rfc3489
42 Each packet has a 20 byte header followed by 0 or more attribute TLVs.
43
44 Attributes:
45 __hdr__: Header fields of STUN.
46 TODO.
47 """
48
49 __hdr__ = (
50 ('type', 'H', 0),
51 ('len', 'H', 0),
52 ('xid', '16s', 0)
53 )
54
55
57 n = 4
58 t, l = struct.unpack('>HH', buf[:n])
59 v = buf[n:n + l]
60 pad = (n - l % n) % n
61 buf = buf[n + l + pad:]
62 return t, l, v, buf
63
64
66 """Parse STUN.data buffer into a list of (attribute, data) tuples."""
67 attrs = []
68 while buf:
69 t, _, v, buf = tlv(buf)
70 attrs.append((t, v))
71 return attrs
72
73
82
83
85 s = (b'\x00\x01\x00\x54\x21\x12\xa4\x42\x35\x59\x53\x6e\x42\x71\x70\x56\x77\x61\x39\x4f\x00\x06'
86 b'\x00\x17\x70\x4c\x79\x5a\x48\x52\x3a\x47\x77\x4c\x33\x41\x48\x42\x6f\x76\x75\x62\x4c\x76'
87 b'\x43\x71\x6e\x00\x80\x2a\x00\x08\x18\x8b\x10\x4c\x69\x7b\xf6\x5b\x00\x25\x00\x00\x00\x24'
88 b'\x00\x04\x6e\x00\x1e\xff\x00\x08\x00\x14\x60\x2b\xc7\xfc\x0d\x10\x63\xaa\xc5\x38\x1c\xcb'
89 b'\x96\xa9\x73\x08\x73\x9a\x96\x0c\x80\x28\x00\x04\xd1\x62\xea\x65')
90 m = STUN(s)
91 assert m.type == BINDING_REQUEST
92 assert m.len == 84
93
94 attrs = parse_attrs(m.data)
95 assert len(attrs) == 6
96 assert attrs[0] == (USERNAME, b'pLyZHR:GwL3AHBovubLvCqn')
97 assert attrs[4][0] == MESSAGE_INTEGRITY
98
99
100 if __name__ == '__main__':
101 test_stun_response()
102 test_stun_padded()
103
104 print('Tests Successful...')
105