1
2 '''
3 [BETA] STUN protocol generator
4
5 @author: Michael Eddington
6 @version: $Id: Peach.Generators.stun-pysrc.html 1138 2008-08-16 19:39:03Z meddingt $
7 '''
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 import re, struct, os
37 from Peach.generator import Generator
38 from Peach.Generators import *
39 from Peach.Generators.dictionary import *
40 from Peach.Generators.static import *
41 from Peach.Generators.static import Int8, Int16, Int32
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
61 '''
62 This generator creates a STUN payload. A payload
63 is a group of attributes
64 '''
65
66 pass
67
68
70 '''
71 This generator creats a STUN packet
72 '''
73
74 _header = None
75 _payload = None
76
77 - def __init__(self, group, header, payload):
78 '''
79 @type group: Group
80 @param group: Group to use
81 @type header: StunHeader
82 @param header: Header generator
83 @type payload: StunPayload
84 @param payload: Payload generator
85 '''
86 self.setGroup(group)
87 self._header = header
88 self._payload = payload
89
107
110
113
116
119
122
123
179
180
182 '''
183 MAPPED-ADDRESS
184
185 The MAPPED-ADDRESS attribute indicates the mapped IP address and
186 port. It consists of an eight bit address family, and a sixteen bit
187 port, followed by a fixed length value representing the IP address.
188
189 0 1 2 3
190 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
191 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
192 |x x x x x x x x| Family | Port |
193 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
194 | Address |
195 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
196
197 The port is a network byte ordered representation of the mapped port.
198 The address family is always 0x01, corresponding to IPv4. The first
199 8 bits of the MAPPED-ADDRESS are ignored, for the purposes of
200 aligning parameters on natural boundaries. The IPv4 address is 32
201 bits.
202 '''
203
204 _empty = 0
205 _family = 0x01
206 _port = None
207 _address = None
208
210 '''
211 @type group: Group
212 @param group: Group to use
213 @type family: Generator
214 @param family: Family (defaults to 0x01 IPV4)
215 @type port: Generator
216 @param port: Port number
217 @type address: Generator
218 @param address: 32bit IPv4 address
219 '''
220 self.setGroup(group)
221 if port != None:
222 self._port = port
223 if address != None:
224 self._address = address
225 if family != None:
226 self._family = family
227 self._type = StunAttribute.MAPPED_ADDRESS
228
233
238
262
263
265 '''
266 RESPONSE-ADDRESS
267
268 The RESPONSE-ADDRESS attribute indicates where the response to a
269 Binding Request should be sent. Its syntax is identical to MAPPED-
270 ADDRESS.
271 '''
272
273 - def __init__(self, group, port, address, family = 0x01):
274 '''
275 @type group: Group
276 @param group: Group to use
277 @type family: Generator
278 @param family: Family (defaults to 0x01 IPV4)
279 @type port: Generator
280 @param port: Port number
281 @type address: Generator
282 @param address: 32bit IPv4 address
283 '''
284 StunMappedAddressAttribute.__init__(self, group, port, address, family)
285 self._type = StunAttribute.RESPONSE_ADDRESS
286
287
289 '''
290 CHANGED-ADDRESS
291
292 The CHANGED-ADDRESS attribute indicates the IP address and port where
293 responses would have been sent from if the "change IP" and "change
294 port" flags had been set in the CHANGE-REQUEST attribute of the
295 Binding Request. The attribute is always present in a Binding
296 Response, independent of the value of the flags. Its syntax is
297 identical to MAPPED-ADDRESS.
298 '''
299
300 - def __init__(self, group, port, address, family = 0x01):
301 '''
302 @type group: Group
303 @param group: Group to use
304 @type family: Generator
305 @param family: Family (defaults to 0x01 IPV4)
306 @type port: Generator
307 @param port: Port number
308 @type address: Generator
309 @param address: 32bit IPv4 address
310 '''
311 StunMappedAddressAttribute.__init__(self, group, port, address, family)
312 self._type = StunAttribute.CHANGED_ADDRESS
313
314
316 '''
317 CHANGE-REQUEST
318
319 The CHANGE-REQUEST attribute is used by the client to request that
320 the server use a different address and/or port when sending the
321 response. The attribute is 32 bits long, although only two bits (A
322 and B) are used:
323
324 0 1 2 3
325 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
326 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
327 |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 A B 0|
328 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
329
330 The meaning of the flags is:
331
332 A: This is the "change IP" flag. If true, it requests the server
333 to send the Binding Response with a different IP address than the
334 one the Binding Request was received on.
335
336 B: This is the "change port" flag. If true, it requests the
337 server to send the Binding Response with a different port than the
338 one the Binding Request was received on.
339 '''
340
341 CHANGE_IP = 4
342 CHANGE_PORT = 2
343
344 _value = None
345 _changeIp = None
346 _changePort = None
347
348 - def __init__(self, group, changeIp, changePort, value = None):
349 '''
350 @type group: Group
351 @param group: Group to use
352 @type changeIp: Generator
353 @param changeIp: changeIp value (0 or 4)
354 @type changePort: Generator
355 @param changePort: changePort value (0 or 2)
356 @type value: Generator
357 @param value: 32bit value (optional)
358 '''
359 self.setGroup(group)
360 if changeIp != None:
361 self._changeIp = changeIp
362 if changePort != None:
363 self._changePort = changePort
364 if value != None:
365 self._value = value
366 self._type = StunAttribute.CHANGE_REQUEST
367
373
398
399
401 '''
402 SOURCE-ADDRESS
403
404 The SOURCE-ADDRESS attribute is present in Binding Responses. It
405 indicates the source IP address and port that the server is sending
406 the response from. Its syntax is identical to that of MAPPED-
407 ADDRESS.
408 '''
409
410 - def __init__(self, group, port, address, family = 0x01):
411 '''
412 @type group: Group
413 @param group: Group to use
414 @type family: Generator
415 @param family: Family (defaults to 0x01 IPV4)
416 @type port: Generator
417 @param port: Port number
418 @type address: Generator
419 @param address: 32bit IPv4 address
420 '''
421 StunMappedAddressAttribute.__init__(self, group, port, address, family)
422 self._type = StunAttribute.SOURCE_ADDRESS
423
424
426 '''
427 USERNAME
428
429 The USERNAME attribute is used for message integrity. It serves as a
430 means to identify the shared secret used in the message integrity
431 check. The USERNAME is always present in a Shared Secret Response,
432 along with the PASSWORD. It is optionally present in a Binding
433 Request when message integrity is used.
434
435 The value of USERNAME is a variable length opaque value. Its length
436 MUST be a multiple of 4 (measured in bytes) in order to guarantee
437 alignment of attributes on word boundaries.
438 '''
439
451
452
454 '''
455 PASSWORD
456
457 The PASSWORD attribute is used in Shared Secret Responses. It is
458 always present in a Shared Secret Response, along with the USERNAME.
459
460 The value of PASSWORD is a variable length value that is to be used
461 as a shared secret. Its length MUST be a multiple of 4 (measured in
462 bytes) in order to guarantee alignment of attributes on word
463 boundaries.
464 '''
465
477
478
480 '''
481 MESSAGE-INTEGRITY
482
483 The MESSAGE-INTEGRITY attribute contains an HMAC-SHA1 [13] of the
484 STUN message. It can be present in Binding Requests or Binding
485 Responses. Since it uses the SHA1 hash, the HMAC will be 20 bytes.
486 The text used as input to HMAC is the STUN message, including the
487 header, up to and including the attribute preceding the MESSAGE-
488 INTEGRITY attribute. That text is then padded with zeroes so as to be
489 a multiple of 64 bytes. As a result, the MESSAGE-INTEGRITY attribute
490 MUST be the last attribute in any STUN message. The key used as
491 input to HMAC depends on the context.
492 '''
493
505
506
508 '''
509 ERROR-CODE
510
511 The ERROR-CODE attribute is present in the Binding Error Response and
512 Shared Secret Error Response. It is a numeric value in the range of
513 100 to 699 plus a textual reason phrase encoded in UTF-8, and is
514 consistent in its code assignments and semantics with SIP [10] and
515 HTTP [15]. The reason phrase is meant for user consumption, and can
516 be anything appropriate for the response code. The lengths of the
517 reason phrases MUST be a multiple of 4 (measured in bytes). This can
518 be accomplished by added spaces to the end of the text, if necessary.
519 Recommended reason phrases for the defined response codes are
520 presented below.
521
522 To facilitate processing, the class of the error code (the hundreds
523 digit) is encoded separately from the rest of the code.
524
525 0 1 2 3
526 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
527 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
528 | 0 |Class| Number |
529 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
530 | Reason Phrase (variable) ..
531 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
532
533 The class represents the hundreds digit of the response code. The
534 value MUST be between 1 and 6. The number represents the response
535 code modulo 100, and its value MUST be between 0 and 99.
536
537 The following response codes, along with their recommended reason
538 phrases (in brackets) are defined at this time:
539
540 400 (Bad Request): The request was malformed. The client should not
541 retry the request without modification from the previous
542 attempt.
543
544 401 (Unauthorized): The Binding Request did not contain a MESSAGE-
545 INTEGRITY attribute.
546
547 420 (Unknown Attribute): The server did not understand a mandatory
548 attribute in the request.
549
550 430 (Stale Credentials): The Binding Request did contain a MESSAGE-
551 INTEGRITY attribute, but it used a shared secret that has
552 expired. The client should obtain a new shared secret and try
553 again.
554
555 431 (Integrity Check Failure): The Binding Request contained a
556 MESSAGE-INTEGRITY attribute, but the HMAC failed verification.
557 This could be a sign of a potential attack, or client
558 implementation error.
559
560 432 (Missing Username): The Binding Request contained a MESSAGE-
561 INTEGRITY attribute, but not a USERNAME attribute. Both must be
562 present for integrity checks.
563
564 433 (Use TLS): The Shared Secret request has to be sent over TLS, but
565 was not received over TLS.
566
567 500 (Server Error): The server has suffered a temporary error. The
568 client should try again.
569
570 600 (Global Failure:) The server is refusing to fulfill the request.
571 The client should not retry.
572 '''
573
574 pass
575
578
580 '''
581 REFLECTED-FROM
582
583 The REFLECTED-FROM attribute is present only in Binding Responses,
584 when the Binding Request contained a RESPONSE-ADDRESS attribute. The
585 attribute contains the identity (in terms of IP address) of the
586 source where the request came from. Its purpose is to provide
587 traceability, so that a STUN server cannot be used as a reflector for
588 denial-of-service attacks.
589
590 Its syntax is identical to the MAPPED-ADDRESS attribute
591 '''
592
593 - def __init__(self, group, port, address, family = 0x01):
594 '''
595 @type group: Group
596 @param group: Group to use
597 @type family: Generator
598 @param family: Family (defaults to 0x01 IPV4)
599 @type port: Generator
600 @param port: Port number
601 @type address: Generator
602 @param address: 32bit IPv4 address
603 '''
604 StunMappedAddressAttribute.__init__(self, group, port, address, family)
605 self._type = StunAttribute.REFLECTED_FROM
606
607
609 '''
610 Generate a valid transaction id
611 '''
612
613 _tid = None
614
618
620 return os.urandom(16)
621
624
627
674
675
676
677
678