1# Copyright (c) 2003-2016 CORE Security Technologies
2#
3# This software is provided under under a slightly modified version
4# of the Apache Software License. See the accompanying LICENSE file
5# for more information.
6#
7# Description:
8#  Network packet codecs basic building blocks.
9#  Low-level packet codecs for various Internet protocols.
10#
11# Author:
12#  Javier Burroni (javier)
13#  Bruce Leidl (brl)
14#  Javier Kohen (jkohen)
15
16import array
17import struct
18import socket
19import string
20import sys
21from binascii import hexlify
22
23"""Classes to build network packets programmatically.
24
25Each protocol layer is represented by an object, and these objects are
26hierarchically structured to form a packet. This list is traversable
27in both directions: from parent to child and vice versa.
28
29All objects can be turned back into a raw buffer ready to be sent over
30the wire (see method get_packet).
31"""
32
33class ImpactPacketException(Exception):
34    def __init__(self, value):
35        self.value = value
36    def __str__(self):
37        return `self.value`
38
39class PacketBuffer(object):
40    """Implement the basic operations utilized to operate on a
41    packet's raw buffer. All the packet classes derive from this one.
42
43    The byte, word, long and ip_address getters and setters accept
44    negative indexes, having these the a similar effect as in a
45    regular Python sequence slice.
46    """
47
48    def __init__(self, length = None):
49        "If 'length' is specified the buffer is created with an initial size"
50        if length:
51            self.__bytes = array.array('B', '\0' * length)
52        else:
53            self.__bytes = array.array('B')
54
55    def set_bytes_from_string(self, data):
56        "Sets the value of the packet buffer from the string 'data'"
57        self.__bytes = array.array('B', data)
58
59    def get_buffer_as_string(self):
60        "Returns the packet buffer as a string object"
61        return self.__bytes.tostring()
62
63    def get_bytes(self):
64        "Returns the packet buffer as an array"
65        return self.__bytes
66
67    def set_bytes(self, bytes):
68        "Set the packet buffer from an array"
69        # Make a copy to be safe
70        self.__bytes = array.array('B', bytes.tolist())
71
72    def set_byte(self, index, value):
73        "Set byte at 'index' to 'value'"
74        index = self.__validate_index(index, 1)
75        self.__bytes[index] = value
76
77    def get_byte(self, index):
78        "Return byte at 'index'"
79        index = self.__validate_index(index, 1)
80        return self.__bytes[index]
81
82    def set_word(self, index, value, order = '!'):
83        "Set 2-byte word at 'index' to 'value'. See struct module's documentation to understand the meaning of 'order'."
84        index = self.__validate_index(index, 2)
85        ary = array.array("B", struct.pack(order + 'H', value))
86        if -2 == index:
87            self.__bytes[index:] = ary
88        else:
89            self.__bytes[index:index+2] = ary
90
91    def get_word(self, index, order = '!'):
92        "Return 2-byte word at 'index'. See struct module's documentation to understand the meaning of 'order'."
93        index = self.__validate_index(index, 2)
94        if -2 == index:
95            bytes = self.__bytes[index:]
96        else:
97            bytes = self.__bytes[index:index+2]
98        (value,) = struct.unpack(order + 'H', bytes.tostring())
99        return value
100
101    def set_long(self, index, value, order = '!'):
102        "Set 4-byte 'value' at 'index'. See struct module's documentation to understand the meaning of 'order'."
103        index = self.__validate_index(index, 4)
104        ary = array.array("B", struct.pack(order + 'L', value))
105        if -4 == index:
106            self.__bytes[index:] = ary
107        else:
108            self.__bytes[index:index+4] = ary
109
110    def get_long(self, index, order = '!'):
111        "Return 4-byte value at 'index'. See struct module's documentation to understand the meaning of 'order'."
112        index = self.__validate_index(index, 4)
113        if -4 == index:
114            bytes = self.__bytes[index:]
115        else:
116            bytes = self.__bytes[index:index+4]
117        (value,) = struct.unpack(order + 'L', bytes.tostring())
118        return value
119
120    def set_long_long(self, index, value, order = '!'):
121        "Set 8-byte 'value' at 'index'. See struct module's documentation to understand the meaning of 'order'."
122        index = self.__validate_index(index, 8)
123        ary = array.array("B", struct.pack(order + 'Q', value))
124        if -8 == index:
125            self.__bytes[index:] = ary
126        else:
127            self.__bytes[index:index+8] = ary
128
129    def get_long_long(self, index, order = '!'):
130        "Return 8-byte value at 'index'. See struct module's documentation to understand the meaning of 'order'."
131        index = self.__validate_index(index, 8)
132        if -8 == index:
133            bytes = self.__bytes[index:]
134        else:
135            bytes = self.__bytes[index:index+8]
136        (value,) = struct.unpack(order + 'Q', bytes.tostring())
137        return value
138
139
140    def get_ip_address(self, index):
141        "Return 4-byte value at 'index' as an IP string"
142        index = self.__validate_index(index, 4)
143        if -4 == index:
144            bytes = self.__bytes[index:]
145        else:
146            bytes = self.__bytes[index:index+4]
147        return socket.inet_ntoa(bytes.tostring())
148
149    def set_ip_address(self, index, ip_string):
150        "Set 4-byte value at 'index' from 'ip_string'"
151        index = self.__validate_index(index, 4)
152        raw = socket.inet_aton(ip_string)
153        (b1,b2,b3,b4) = struct.unpack("BBBB", raw)
154        self.set_byte(index, b1)
155        self.set_byte(index + 1, b2)
156        self.set_byte(index + 2, b3)
157        self.set_byte(index + 3, b4)
158
159    def set_checksum_from_data(self, index, data):
160        "Set 16-bit checksum at 'index' by calculating checksum of 'data'"
161        self.set_word(index, self.compute_checksum(data))
162
163    def compute_checksum(self, anArray):
164        "Return the one's complement of the one's complement sum of all the 16-bit words in 'anArray'"
165        nleft = len(anArray)
166        sum = 0
167        pos = 0
168        while nleft > 1:
169            sum = anArray[pos] * 256 + (anArray[pos + 1] + sum)
170            pos = pos + 2
171            nleft = nleft - 2
172        if nleft == 1:
173            sum = sum + anArray[pos] * 256
174        return self.normalize_checksum(sum)
175
176    def normalize_checksum(self, aValue):
177        sum = aValue
178        sum = (sum >> 16) + (sum & 0xFFFF)
179        sum += (sum >> 16)
180        sum = (~sum & 0xFFFF)
181        return sum
182
183    def __validate_index(self, index, size):
184        """This method performs two tasks: to allocate enough space to
185        fit the elements at positions index through index+size, and to
186        adjust negative indexes to their absolute equivalent.
187        """
188
189        orig_index = index
190
191        curlen = len(self.__bytes)
192        if index < 0:
193            index = curlen + index
194
195        diff = index + size - curlen
196        if diff > 0:
197            self.__bytes.fromstring('\0' * diff)
198            if orig_index < 0:
199                orig_index -= diff
200
201        return orig_index
202
203class ProtocolLayer():
204    "Protocol Layer Manager for insertion and removal of protocol layers."
205
206    __child = None
207    __parent = None
208
209    def contains(self, aHeader):
210        "Set 'aHeader' as the child of this protocol layer"
211        self.__child = aHeader
212        aHeader.set_parent(self)
213
214    def set_parent(self, my_parent):
215        "Set the header 'my_parent' as the parent of this protocol layer"
216        self.__parent = my_parent
217
218    def child(self):
219        "Return the child of this protocol layer"
220        return self.__child
221
222    def parent(self):
223        "Return the parent of this protocol layer"
224        return self.__parent
225
226    def unlink_child(self):
227        "Break the hierarchy parent/child child/parent"
228        if self.__child:
229            self.__child.set_parent(None)
230            self.__child = None
231
232class ProtocolPacket(ProtocolLayer):
233    __HEADER_SIZE = 0
234    __BODY_SIZE = 0
235    __TAIL_SIZE = 0
236
237    __header = None
238    __body = None
239    __tail = None
240
241    def __init__(self, header_size, tail_size):
242        self.__HEADER_SIZE = header_size
243        self.__TAIL_SIZE = tail_size
244        self.__header=PacketBuffer(self.__HEADER_SIZE)
245        self.__body=PacketBuffer()
246        self.__tail=PacketBuffer(self.__TAIL_SIZE)
247
248    def __update_body_from_child(self):
249        # Update child raw packet in my body
250        if self.child():
251            body=self.child().get_packet()
252            self.__BODY_SIZE=len(body)
253            self.__body.set_bytes_from_string(body)
254
255    def __get_header(self):
256        return self.__header
257
258    header = property(__get_header)
259
260    def __get_body(self):
261        self.__update_body_from_child()
262        return self.__body
263
264    body = property(__get_body)
265
266    def __get_tail(self):
267        return self.__tail
268
269    tail = property(__get_tail)
270
271    def get_header_size(self):
272        "Return frame header size"
273        return self.__HEADER_SIZE
274
275    def get_tail_size(self):
276        "Return frame tail size"
277        return self.__TAIL_SIZE
278
279    def get_body_size(self):
280        "Return frame body size"
281        self.__update_body_from_child()
282        return self.__BODY_SIZE
283
284    def get_size(self):
285        "Return frame total size"
286        return self.get_header_size()+self.get_body_size()+self.get_tail_size()
287
288    def load_header(self, aBuffer):
289        self.__HEADER_SIZE=len(aBuffer)
290        self.__header.set_bytes_from_string(aBuffer)
291
292    def load_body(self, aBuffer):
293        "Load the packet body from string. "\
294        "WARNING: Using this function will break the hierarchy of preceding protocol layer"
295        self.unlink_child()
296        self.__BODY_SIZE=len(aBuffer)
297        self.__body.set_bytes_from_string(aBuffer)
298
299    def load_tail(self, aBuffer):
300        self.__TAIL_SIZE=len(aBuffer)
301        self.__tail.set_bytes_from_string(aBuffer)
302
303    def __extract_header(self, aBuffer):
304        self.load_header(aBuffer[:self.__HEADER_SIZE])
305
306    def __extract_body(self, aBuffer):
307        if self.__TAIL_SIZE<=0:
308            end=None
309        else:
310            end=-self.__TAIL_SIZE
311        self.__BODY_SIZE=len(aBuffer[self.__HEADER_SIZE:end])
312        self.__body.set_bytes_from_string(aBuffer[self.__HEADER_SIZE:end])
313
314    def __extract_tail(self, aBuffer):
315        if self.__TAIL_SIZE<=0:
316            # leave the array empty
317            return
318        else:
319            start=-self.__TAIL_SIZE
320        self.__tail.set_bytes_from_string(aBuffer[start:])
321
322    def load_packet(self, aBuffer):
323        "Load the whole packet from a string" \
324        "WARNING: Using this function will break the hierarchy of preceding protocol layer"
325        self.unlink_child()
326
327        self.__extract_header(aBuffer)
328        self.__extract_body(aBuffer)
329        self.__extract_tail(aBuffer)
330
331    def get_header_as_string(self):
332        return self.__header.get_buffer_as_string()
333
334    def get_body_as_string(self):
335        self.__update_body_from_child()
336        return self.__body.get_buffer_as_string()
337    body_string = property(get_body_as_string)
338
339    def get_tail_as_string(self):
340        return self.__tail.get_buffer_as_string()
341    tail_string = property(get_tail_as_string)
342
343    def get_packet(self):
344        self.__update_body_from_child()
345
346        ret = ''
347
348        header = self.get_header_as_string()
349        if header:
350            ret += header
351
352        body = self.get_body_as_string()
353        if body:
354            ret += body
355
356        tail = self.get_tail_as_string()
357        if tail:
358            ret += tail
359
360        return ret
361
362class Header(PacketBuffer,ProtocolLayer):
363    "This is the base class from which all protocol definitions extend."
364
365    packet_printable = filter(lambda c: c not in string.whitespace, string.printable) + ' '
366
367    ethertype = None
368    protocol = None
369    def __init__(self, length = None):
370        PacketBuffer.__init__(self, length)
371        self.auto_checksum = 1
372
373    def get_data_as_string(self):
374        "Returns all data from children of this header as string"
375
376        if self.child():
377            return self.child().get_packet()
378        else:
379            return None
380
381    def get_packet(self):
382        """Returns the raw representation of this packet and its
383        children as a string. The output from this method is a packet
384        ready to be transmitted over the wire.
385        """
386        self.calculate_checksum()
387
388        data = self.get_data_as_string()
389        if data:
390            return self.get_buffer_as_string() + data
391        else:
392            return self.get_buffer_as_string()
393
394    def get_size(self):
395        "Return the size of this header and all of it's children"
396        tmp_value = self.get_header_size()
397        if self.child():
398            tmp_value = tmp_value + self.child().get_size()
399        return tmp_value
400
401    def calculate_checksum(self):
402        "Calculate and set the checksum for this header"
403        pass
404
405    def get_pseudo_header(self):
406        "Pseudo headers can be used to limit over what content will the checksums be calculated."
407        # default implementation returns empty array
408        return array.array('B')
409
410    def load_header(self, aBuffer):
411        "Properly set the state of this instance to reflect that of the raw packet passed as argument."
412        self.set_bytes_from_string(aBuffer)
413        hdr_len = self.get_header_size()
414        if(len(aBuffer) < hdr_len):         #we must do something like this
415            diff = hdr_len - len(aBuffer)
416            for i in range(0, diff):
417                aBuffer += '\x00'
418        self.set_bytes_from_string(aBuffer[:hdr_len])
419
420    def get_header_size(self):
421        "Return the size of this header, that is, not counting neither the size of the children nor of the parents."
422        raise RuntimeError("Method %s.get_header_size must be overridden." % self.__class__)
423
424    def list_as_hex(self, aList):
425        if len(aList):
426            ltmp = []
427            line = []
428            count = 0
429            for byte in aList:
430                if not (count % 2):
431                    if (count % 16):
432                        ltmp.append(' ')
433                    else:
434                        ltmp.append(' '*4)
435                        ltmp.append(string.join(line, ''))
436                        ltmp.append('\n')
437                        line = []
438                if chr(byte) in Header.packet_printable:
439                    line.append(chr(byte))
440                else:
441                    line.append('.')
442                ltmp.append('%.2x' % byte)
443                count += 1
444            if (count%16):
445                left = 16 - (count%16)
446                ltmp.append(' ' * (4+(left / 2) + (left*2)))
447                ltmp.append(string.join(line, ''))
448                ltmp.append('\n')
449            return ltmp
450        else:
451            return []
452
453    def __str__(self):
454        ltmp = self.list_as_hex(self.get_bytes().tolist())
455
456        if self.child():
457            ltmp.append(['\n', str(self.child())])
458
459        if len(ltmp)>0:
460            return string.join(ltmp, '')
461        else:
462            return ''
463
464
465
466class Data(Header):
467    """This packet type can hold raw data. It's normally employed to
468    hold a packet's innermost layer's contents in those cases for
469    which the protocol details are unknown, and there's a copy of a
470    valid packet available.
471
472    For instance, if all that's known about a certain protocol is that
473    a UDP packet with its contents set to "HELLO" initiate a new
474    session, creating such packet is as simple as in the following code
475    fragment:
476    packet = UDP()
477    packet.contains('HELLO')
478    """
479
480    def __init__(self, aBuffer = None):
481        Header.__init__(self)
482        if aBuffer:
483            self.set_data(aBuffer)
484
485    def set_data(self, data):
486        self.set_bytes_from_string(data)
487
488    def get_size(self):
489        return len(self.get_bytes())
490
491
492class EthernetTag(PacketBuffer):
493    """Represents a VLAN header specified in IEEE 802.1Q and 802.1ad.
494       Provides methods for convenient manipulation with header fields."""
495
496    def __init__(self, value=0x81000000):
497        PacketBuffer.__init__(self, 4)
498        self.set_long(0, value)
499
500    def get_tpid(self):
501        """Returns Tag Protocol Identifier"""
502        return self.get_word(0)
503
504    def set_tpid(self, value):
505        """Sets Tag Protocol Identifier"""
506        return self.set_word(0, value)
507
508    def get_pcp(self):
509        """Returns Priority Code Point"""
510        return (self.get_byte(2) & 0xE0) >> 5
511
512    def set_pcp(self, value):
513        """Sets Priority Code Point"""
514        orig_value = self.get_byte(2)
515        self.set_byte(2, (orig_value & 0x1F) | ((value & 0x07) << 5))
516
517    def get_dei(self):
518        """Returns Drop Eligible Indicator"""
519        return (self.get_byte(2) & 0x10) >> 4
520
521    def set_dei(self, value):
522        """Sets Drop Eligible Indicator"""
523        orig_value = self.get_byte(2)
524        self.set_byte(2, orig_value | 0x10 if value else orig_value & 0xEF)
525
526    def get_vid(self):
527        """Returns VLAN Identifier"""
528        return self.get_word(2) & 0x0FFF
529
530    def set_vid(self, value):
531        """Sets VLAN Identifier"""
532        orig_value = self.get_word(2)
533        self.set_word(2, (orig_value & 0xF000) | (value & 0x0FFF))
534
535    def __str__(self):
536        priorities = (
537            'Best Effort',
538            'Background',
539            'Excellent Effort',
540            'Critical Applications',
541            'Video, < 100 ms latency and jitter',
542            'Voice, < 10 ms latency and jitter',
543            'Internetwork Control',
544            'Network Control')
545
546        pcp = self.get_pcp()
547        return '\n'.join((
548            '802.1Q header: 0x{0:08X}'.format(self.get_long(0)),
549            'Priority Code Point: {0} ({1})'.format(pcp, priorities[pcp]),
550            'Drop Eligible Indicator: {0}'.format(self.get_dei()),
551            'VLAN Identifier: {0}'.format(self.get_vid())))
552
553
554class Ethernet(Header):
555    def __init__(self, aBuffer = None):
556        Header.__init__(self, 14)
557        self.tag_cnt = 0
558        if(aBuffer):
559            self.load_header(aBuffer)
560
561    def set_ether_type(self, aValue):
562        "Set ethernet data type field to 'aValue'"
563        self.set_word(12 + 4*self.tag_cnt, aValue)
564
565    def get_ether_type(self):
566        "Return ethernet data type field"
567        return self.get_word(12 + 4*self.tag_cnt)
568
569    def get_tag(self, index):
570        """Returns an EthernetTag initialized from index-th VLAN tag.
571           The tags are numbered from 0 to self.tag_cnt-1 as they appear in the frame.
572           It is possible to use negative indexes as well."""
573        index = self.__validate_tag_index(index)
574        return EthernetTag(self.get_long(12+4*index))
575
576    def set_tag(self, index, tag):
577        """Sets the index-th VLAN tag to contents of an EthernetTag object.
578           The tags are numbered from 0 to self.tag_cnt-1 as they appear in the frame.
579           It is possible to use negative indexes as well."""
580        index = self.__validate_tag_index(index)
581        pos = 12 + 4*index
582        for i,val in enumerate(tag.get_bytes()):
583            self.set_byte(pos+i, val)
584
585    def push_tag(self, tag, index=0):
586        """Inserts contents of an EthernetTag object before the index-th VLAN tag.
587           Index defaults to 0 (the top of the stack)."""
588        if index < 0:
589            index += self.tag_cnt
590        pos = 12 + 4*max(0, min(index, self.tag_cnt))
591        data = self.get_bytes()
592        data[pos:pos] = tag.get_bytes()
593        self.set_bytes(data)
594        self.tag_cnt += 1
595
596    def pop_tag(self, index=0):
597        """Removes the index-th VLAN tag and returns it as an EthernetTag object.
598           Index defaults to 0 (the top of the stack)."""
599        index = self.__validate_tag_index(index)
600        pos = 12 + 4*index
601        tag = self.get_long(pos)
602        data = self.get_bytes()
603        del data[pos:pos+4]
604        self.set_bytes(data)
605        self.tag_cnt -= 1
606        return EthernetTag(tag)
607
608    def load_header(self, aBuffer):
609        self.tag_cnt = 0
610        while aBuffer[12+4*self.tag_cnt:14+4*self.tag_cnt] in ('\x81\x00', '\x88\xa8', '\x91\x00'):
611            self.tag_cnt += 1
612
613        hdr_len = self.get_header_size()
614        diff = hdr_len - len(aBuffer)
615        if diff > 0:
616            aBuffer += '\x00'*diff
617        self.set_bytes_from_string(aBuffer[:hdr_len])
618
619    def get_header_size(self):
620        "Return size of Ethernet header"
621        return 14 + 4*self.tag_cnt
622
623    def get_packet(self):
624
625        if self.child():
626            try:
627                self.set_ether_type(self.child().ethertype)
628            except:
629                " an Ethernet packet may have a Data() "
630                pass
631        return Header.get_packet(self)
632
633    def get_ether_dhost(self):
634        "Return 48 bit destination ethernet address as a 6 byte array"
635        return self.get_bytes()[0:6]
636
637    def set_ether_dhost(self, aValue):
638        "Set destination ethernet address from 6 byte array 'aValue'"
639        for i in range(0, 6):
640            self.set_byte(i, aValue[i])
641
642    def get_ether_shost(self):
643        "Return 48 bit source ethernet address as a 6 byte array"
644        return self.get_bytes()[6:12]
645
646    def set_ether_shost(self, aValue):
647        "Set source ethernet address from 6 byte array 'aValue'"
648        for i in range(0, 6):
649            self.set_byte(i + 6, aValue[i])
650
651    @staticmethod
652    def as_eth_addr(anArray):
653        tmp_list = map(lambda x: x > 15 and '%x'%x or '0%x'%x, anArray)
654        return '' + reduce(lambda x, y: x+':'+y, tmp_list)
655
656    def __str__(self):
657        tmp_str = 'Ether: ' + self.as_eth_addr(self.get_ether_shost()) + ' -> '
658        tmp_str += self.as_eth_addr(self.get_ether_dhost())
659        if self.child():
660            tmp_str += '\n' + str( self.child())
661        return tmp_str
662
663    def __validate_tag_index(self, index):
664        """Adjusts negative indices to their absolute equivalents.
665           Raises IndexError when out of range <0, self.tag_cnt-1>."""
666        if index < 0:
667            index += self.tag_cnt
668        if index < 0 or index >= self.tag_cnt:
669            raise IndexError("Tag index out of range")
670        return index
671
672# Linux "cooked" capture encapsulation.
673# Used, for instance, for packets returned by the "any" interface.
674class LinuxSLL(Header):
675    type_descriptions = [
676        "sent to us by somebody else",
677        "broadcast by somebody else",
678        "multicast by somebody else",
679        "sent to somebody else to somebody else",
680        "sent by us",
681        ]
682
683    def __init__(self, aBuffer = None):
684        Header.__init__(self, 16)
685        if (aBuffer):
686            self.load_header(aBuffer)
687
688    def set_type(self, type):
689        "Sets the packet type field to type"
690        self.set_word(0, type)
691
692    def get_type(self):
693        "Returns the packet type field"
694        return self.get_word(0)
695
696    def set_arphdr(self, value):
697        "Sets the ARPHDR value for the link layer device type"
698        self.set_word(2, type)
699
700    def get_arphdr(self):
701        "Returns the ARPHDR value for the link layer device type"
702        return self.get_word(2)
703
704    def set_addr_len(self, len):
705        "Sets the length of the sender's address field to len"
706        self.set_word(4, len)
707
708    def get_addr_len(self):
709        "Returns the length of the sender's address field"
710        return self.get_word(4)
711
712    def set_addr(self, addr):
713        "Sets the sender's address field to addr. Addr must be at most 8-byte long."
714        if (len(addr) < 8):
715            addr += '\0' * (8 - len(addr))
716        self.get_bytes()[6:14] = addr
717
718    def get_addr(self):
719        "Returns the sender's address field"
720        return self.get_bytes()[6:14].tostring()
721
722    def set_ether_type(self, aValue):
723        "Set ethernet data type field to 'aValue'"
724        self.set_word(14, aValue)
725
726    def get_ether_type(self):
727        "Return ethernet data type field"
728        return self.get_word(14)
729
730    def get_header_size(self):
731        "Return size of packet header"
732        return 16
733
734    def get_packet(self):
735        if self.child():
736            self.set_ether_type(self.child().ethertype)
737        return Header.get_packet(self)
738
739    def get_type_desc(self):
740        type = self.get_type()
741        if type < len(LinuxSLL.type_descriptions):
742            return LinuxSLL.type_descriptions[type]
743        else:
744            return "Unknown"
745
746    def __str__(self):
747        ss = []
748        alen = self.get_addr_len()
749        addr = hexlify(self.get_addr()[0:alen])
750        ss.append("Linux SLL: addr=%s type=`%s'" % (addr, self.get_type_desc()))
751        if self.child():
752            ss.append(str(self.child()))
753
754        return '\n'.join(ss)
755
756
757class IP(Header):
758    ethertype = 0x800
759    def __init__(self, aBuffer = None):
760        Header.__init__(self, 20)
761        self.set_ip_v(4)
762        self.set_ip_hl(5)
763        self.set_ip_ttl(255)
764        self.__option_list = []
765        if(aBuffer):
766            # When decoding, checksum shouldn't be modified
767            self.auto_checksum = 0
768            self.load_header(aBuffer)
769
770        if sys.platform.count('bsd'):
771            self.is_BSD = True
772        else:
773            self.is_BSD = False
774
775
776    def get_packet(self):
777        # set protocol
778        if self.get_ip_p() == 0 and self.child():
779            self.set_ip_p(self.child().protocol)
780
781        # set total length
782        if self.get_ip_len() == 0:
783            self.set_ip_len(self.get_size())
784
785        child_data = self.get_data_as_string();
786
787        if self.auto_checksum:
788            self.reset_ip_sum()
789
790        my_bytes = self.get_bytes()
791
792        for op in self.__option_list:
793            my_bytes.extend(op.get_bytes())
794
795        # Pad to a multiple of 4 bytes
796        num_pad = (4 - (len(my_bytes) % 4)) % 4
797        if num_pad:
798            my_bytes.fromstring("\0"* num_pad)
799
800        # only change ip_hl value if options are present
801        if len(self.__option_list):
802            self.set_ip_hl(len(my_bytes) / 4)
803
804
805        # set the checksum if the user hasn't modified it
806        if self.auto_checksum:
807            self.set_ip_sum(self.compute_checksum(my_bytes))
808
809        if child_data == None:
810            return my_bytes.tostring()
811        else:
812            return my_bytes.tostring() + child_data
813
814
815
816    #  def calculate_checksum(self, buffer = None):
817    #      tmp_value = self.get_ip_sum()
818    #      if self.auto_checksum and (not tmp_value):
819    #          if buffer:
820    #              tmp_bytes = buffer
821    #          else:
822    #              tmp_bytes = self.bytes[0:self.get_header_size()]
823    #
824    #          self.set_ip_sum(self.compute_checksum(tmp_bytes))
825
826
827    def get_pseudo_header(self):
828        pseudo_buf = array.array("B")
829        pseudo_buf.extend(self.get_bytes()[12:20])
830        pseudo_buf.fromlist([0])
831        pseudo_buf.extend(self.get_bytes()[9:10])
832        tmp_size = self.child().get_size()
833
834        size_str = struct.pack("!H", tmp_size)
835
836        pseudo_buf.fromstring(size_str)
837        return pseudo_buf
838
839    def add_option(self, option):
840        self.__option_list.append(option)
841        sum = 0
842        for op in self.__option_list:
843            sum += op.get_len()
844        if sum > 40:
845            raise ImpactPacketException, "Options overflowed in IP packet with length: %d" % sum
846
847
848    def get_ip_v(self):
849        n = self.get_byte(0)
850        return (n >> 4)
851
852    def set_ip_v(self, value):
853        n = self.get_byte(0)
854        version = value & 0xF
855        n = n & 0xF
856        n = n | (version << 4)
857        self.set_byte(0, n)
858
859    def get_ip_hl(self):
860        n = self.get_byte(0)
861        return (n & 0xF)
862
863    def set_ip_hl(self, value):
864        n = self.get_byte(0)
865        len = value & 0xF
866        n = n & 0xF0
867        n = (n | len)
868        self.set_byte(0, n)
869
870    def get_ip_tos(self):
871        return self.get_byte(1)
872
873    def set_ip_tos(self,value):
874        self.set_byte(1, value)
875
876    def get_ip_len(self):
877        if self.is_BSD:
878            return self.get_word(2, order = '=')
879        else:
880            return self.get_word(2)
881
882    def set_ip_len(self, value):
883        if self.is_BSD:
884            self.set_word(2, value, order = '=')
885        else:
886            self.set_word(2, value)
887
888    def get_ip_id(self):
889        return self.get_word(4)
890    def set_ip_id(self, value):
891        return self.set_word(4, value)
892
893    def get_ip_off(self):
894        if self.is_BSD:
895            return self.get_word(6, order = '=')
896        else:
897            return self.get_word(6)
898
899    def set_ip_off(self, aValue):
900        if self.is_BSD:
901            self.set_word(6, aValue, order = '=')
902        else:
903            self.set_word(6, aValue)
904
905    def get_ip_offmask(self):
906        return self.get_ip_off() & 0x1FFF
907
908    def set_ip_offmask(self, aValue):
909        tmp_value = self.get_ip_off() & 0xD000
910        tmp_value |= aValue
911        self.set_ip_off(tmp_value)
912
913    def get_ip_rf(self):
914        return self.get_ip_off() & 0x8000
915
916    def set_ip_rf(self, aValue):
917        tmp_value = self.get_ip_off()
918        if aValue:
919            tmp_value |= 0x8000
920        else:
921            my_not = 0xFFFF ^ 0x8000
922            tmp_value &= my_not
923        self.set_ip_off(tmp_value)
924
925    def get_ip_df(self):
926        return self.get_ip_off() & 0x4000
927
928    def set_ip_df(self, aValue):
929        tmp_value = self.get_ip_off()
930        if aValue:
931            tmp_value |= 0x4000
932        else:
933            my_not = 0xFFFF ^ 0x4000
934            tmp_value &= my_not
935        self.set_ip_off(tmp_value)
936
937    def get_ip_mf(self):
938        return self.get_ip_off() & 0x2000
939
940    def set_ip_mf(self, aValue):
941        tmp_value = self.get_ip_off()
942        if aValue:
943            tmp_value |= 0x2000
944        else:
945            my_not = 0xFFFF ^ 0x2000
946            tmp_value &= my_not
947        self.set_ip_off(tmp_value)
948
949
950    def fragment_by_list(self, aList):
951        if self.child():
952            proto = self.child().protocol
953        else:
954            proto = 0
955
956        child_data = self.get_data_as_string()
957        if not child_data:
958            return [self]
959
960        ip_header_bytes = self.get_bytes()
961        current_offset = 0
962        fragment_list = []
963
964        for frag_size in aList:
965            ip = IP()
966            ip.set_bytes(ip_header_bytes) # copy of original header
967            ip.set_ip_p(proto)
968
969
970            if frag_size % 8:   # round this fragment size up to next multiple of 8
971                frag_size += 8 - (frag_size % 8)
972
973
974            ip.set_ip_offmask(current_offset / 8)
975            current_offset += frag_size
976
977            data = Data(child_data[:frag_size])
978            child_data = child_data[frag_size:]
979
980            ip.set_ip_len(20 + data.get_size())
981            ip.contains(data)
982
983
984            if child_data:
985
986                ip.set_ip_mf(1)
987
988                fragment_list.append(ip)
989            else: # no more data bytes left to add to fragments
990
991                ip.set_ip_mf(0)
992
993                fragment_list.append(ip)
994                return fragment_list
995
996        if child_data: # any remaining data?
997            # create a fragment containing all of the remaining child_data
998            ip = IP()
999            ip.set_bytes(ip_header_bytes)
1000            ip.set_ip_offmask(current_offset)
1001            ip.set_ip_len(20 + len(child_data))
1002            data = Data(child_data)
1003            ip.contains(data)
1004            fragment_list.append(ip)
1005
1006        return fragment_list
1007
1008
1009    def fragment_by_size(self, aSize):
1010        data_len = len(self.get_data_as_string())
1011        num_frags = data_len / aSize
1012
1013        if data_len % aSize:
1014            num_frags += 1
1015
1016        size_list = []
1017        for i in range(0, num_frags):
1018            size_list.append(aSize)
1019        return self.fragment_by_list(size_list)
1020
1021
1022    def get_ip_ttl(self):
1023        return self.get_byte(8)
1024    def set_ip_ttl(self, value):
1025        self.set_byte(8, value)
1026
1027    def get_ip_p(self):
1028        return self.get_byte(9)
1029
1030    def set_ip_p(self, value):
1031        self.set_byte(9, value)
1032
1033    def get_ip_sum(self):
1034        return self.get_word(10)
1035    def set_ip_sum(self, value):
1036        self.auto_checksum = 0
1037        self.set_word(10, value)
1038
1039    def reset_ip_sum(self):
1040        self.set_ip_sum(0x0000)
1041        self.auto_checksum = 1
1042
1043    def get_ip_src(self):
1044        return self.get_ip_address(12)
1045    def set_ip_src(self, value):
1046        self.set_ip_address(12, value)
1047
1048    def get_ip_dst(self):
1049        return self.get_ip_address(16)
1050
1051    def set_ip_dst(self, value):
1052        self.set_ip_address(16, value)
1053
1054    def get_header_size(self):
1055        op_len = 0
1056        for op in self.__option_list:
1057            op_len += op.get_len()
1058
1059        num_pad = (4 - (op_len % 4)) % 4
1060
1061        return 20 + op_len + num_pad
1062
1063    def load_header(self, aBuffer):
1064        self.set_bytes_from_string(aBuffer[:20])
1065        opt_left = (self.get_ip_hl() - 5) * 4
1066        opt_bytes = array.array('B', aBuffer[20:(20 + opt_left)])
1067        if len(opt_bytes) != opt_left:
1068            raise ImpactPacketException, "Cannot load options from truncated packet"
1069
1070
1071        while opt_left:
1072            op_type = opt_bytes[0]
1073            if op_type == IPOption.IPOPT_EOL or op_type == IPOption.IPOPT_NOP:
1074                new_option = IPOption(op_type)
1075                op_len = 1
1076            else:
1077                op_len = opt_bytes[1]
1078                if op_len > len(opt_bytes):
1079                    raise ImpactPacketException, "IP Option length is too high"
1080
1081                new_option = IPOption(op_type, op_len)
1082                new_option.set_bytes(opt_bytes[:op_len])
1083
1084            opt_bytes = opt_bytes[op_len:]
1085            opt_left -= op_len
1086            self.add_option(new_option)
1087            if op_type == IPOption.IPOPT_EOL:
1088                break
1089
1090
1091    def __str__(self):
1092        flags = ' '
1093        if self.get_ip_df(): flags += 'DF '
1094        if self.get_ip_mf(): flags += 'MF '
1095        if self.get_ip_rf(): flags += 'RF '
1096        tmp_str = 'IP%s%s -> %s ' % (flags, self.get_ip_src(),self.get_ip_dst())
1097        for op in self.__option_list:
1098            tmp_str += '\n' + str(op)
1099        if self.child():
1100            tmp_str += '\n' + str(self.child())
1101        return tmp_str
1102
1103
1104class IPOption(PacketBuffer):
1105    IPOPT_EOL = 0
1106    IPOPT_NOP = 1
1107    IPOPT_RR = 7
1108    IPOPT_TS = 68
1109    IPOPT_LSRR = 131
1110    IPOPT_SSRR = 137
1111
1112    def __init__(self, opcode = 0, size = None):
1113        if size and (size < 3 or size > 40):
1114            raise ImpactPacketException, "IP Options must have a size between 3 and 40 bytes"
1115
1116        if(opcode == IPOption.IPOPT_EOL):
1117            PacketBuffer.__init__(self, 1)
1118            self.set_code(IPOption.IPOPT_EOL)
1119        elif(opcode == IPOption.IPOPT_NOP):
1120            PacketBuffer.__init__(self, 1)
1121            self.set_code(IPOption.IPOPT_NOP)
1122        elif(opcode == IPOption.IPOPT_RR):
1123            if not size:
1124                size = 39
1125            PacketBuffer.__init__(self, size)
1126            self.set_code(IPOption.IPOPT_RR)
1127            self.set_len(size)
1128            self.set_ptr(4)
1129
1130        elif(opcode == IPOption.IPOPT_LSRR):
1131            if not size:
1132                size = 39
1133            PacketBuffer.__init__(self, size)
1134            self.set_code(IPOption.IPOPT_LSRR)
1135            self.set_len(size)
1136            self.set_ptr(4)
1137
1138        elif(opcode == IPOption.IPOPT_SSRR):
1139            if not size:
1140                size = 39
1141            PacketBuffer.__init__(self, size)
1142            self.set_code(IPOption.IPOPT_SSRR)
1143            self.set_len(size)
1144            self.set_ptr(4)
1145
1146        elif(opcode == IPOption.IPOPT_TS):
1147            if not size:
1148                size = 40
1149            PacketBuffer.__init__(self, size)
1150            self.set_code(IPOption.IPOPT_TS)
1151            self.set_len(size)
1152            self.set_ptr(5)
1153            self.set_flags(0)
1154        else:
1155            if not size:
1156                raise ImpactPacketException, "Size required for this type"
1157            PacketBuffer.__init__(self,size)
1158            self.set_code(opcode)
1159            self.set_len(size)
1160
1161
1162    def append_ip(self, ip):
1163        op = self.get_code()
1164        if not (op == IPOption.IPOPT_RR or op == IPOption.IPOPT_LSRR or op == IPOption.IPOPT_SSRR or op == IPOption.IPOPT_TS):
1165            raise ImpactPacketException, "append_ip() not support for option type %d" % self.opt_type
1166
1167        p = self.get_ptr()
1168        if not p:
1169            raise ImpactPacketException, "append_ip() failed, option ptr uninitialized"
1170
1171        if (p + 4) > self.get_len():
1172            raise ImpactPacketException, "append_ip() would overflow option"
1173
1174        self.set_ip_address(p - 1, ip)
1175        p += 4
1176        self.set_ptr(p)
1177
1178
1179    def set_code(self, value):
1180        self.set_byte(0, value)
1181
1182    def get_code(self):
1183        return self.get_byte(0)
1184
1185
1186    def set_flags(self, flags):
1187        if not (self.get_code() == IPOption.IPOPT_TS):
1188            raise ImpactPacketException, "Operation only supported on Timestamp option"
1189        self.set_byte(3, flags)
1190
1191    def get_flags(self, flags):
1192        if not (self.get_code() == IPOption.IPOPT_TS):
1193            raise ImpactPacketException, "Operation only supported on Timestamp option"
1194        return self.get_byte(3)
1195
1196
1197    def set_len(self, len):
1198        self.set_byte(1, len)
1199
1200
1201    def set_ptr(self, ptr):
1202        self.set_byte(2, ptr)
1203
1204    def get_ptr(self):
1205        return self.get_byte(2)
1206
1207    def get_len(self):
1208        return len(self.get_bytes())
1209
1210
1211    def __str__(self):
1212        map = {IPOption.IPOPT_EOL : "End of List ",
1213               IPOption.IPOPT_NOP : "No Operation ",
1214               IPOption.IPOPT_RR  : "Record Route ",
1215               IPOption.IPOPT_TS  : "Timestamp ",
1216               IPOption.IPOPT_LSRR : "Loose Source Route ",
1217               IPOption.IPOPT_SSRR : "Strict Source Route "}
1218
1219        tmp_str = "\tIP Option: "
1220        op = self.get_code()
1221        if map.has_key(op):
1222            tmp_str += map[op]
1223        else:
1224            tmp_str += "Code: %d " % op
1225
1226        if op == IPOption.IPOPT_RR or op == IPOption.IPOPT_LSRR or op ==IPOption.IPOPT_SSRR:
1227            tmp_str += self.print_addresses()
1228
1229
1230        return tmp_str
1231
1232
1233    def print_addresses(self):
1234        p = 3
1235        tmp_str = "["
1236        if self.get_len() >= 7: # at least one complete IP address
1237            while 1:
1238                if p + 1 == self.get_ptr():
1239                    tmp_str += "#"
1240                tmp_str += self.get_ip_address(p)
1241                p += 4
1242                if p >= self.get_len():
1243                    break
1244                else:
1245                    tmp_str += ", "
1246        tmp_str += "] "
1247        if self.get_ptr() % 4: # ptr field should be a multiple of 4
1248            tmp_str += "nonsense ptr field: %d " % self.get_ptr()
1249        return tmp_str
1250
1251
1252class UDP(Header):
1253    protocol = 17
1254    def __init__(self, aBuffer = None):
1255        Header.__init__(self, 8)
1256        if(aBuffer):
1257            self.load_header(aBuffer)
1258
1259    def get_uh_sport(self):
1260        return self.get_word(0)
1261    def set_uh_sport(self, value):
1262        self.set_word(0, value)
1263
1264    def get_uh_dport(self):
1265        return self.get_word(2)
1266    def set_uh_dport(self, value):
1267        self.set_word(2, value)
1268
1269    def get_uh_ulen(self):
1270        return self.get_word(4)
1271
1272    def set_uh_ulen(self, value):
1273        self.set_word(4, value)
1274
1275    def get_uh_sum(self):
1276        return self.get_word(6)
1277
1278    def set_uh_sum(self, value):
1279        self.set_word(6, value)
1280        self.auto_checksum = 0
1281
1282    def calculate_checksum(self):
1283        if self.auto_checksum and (not self.get_uh_sum()):
1284            # if there isn't a parent to grab a pseudo-header from we'll assume the user knows what they're doing
1285            # and won't meddle with the checksum or throw an exception
1286            if not self.parent():
1287                return
1288
1289            buffer = self.parent().get_pseudo_header()
1290
1291            buffer += self.get_bytes()
1292            data = self.get_data_as_string()
1293            if(data):
1294                buffer.fromstring(data)
1295            self.set_uh_sum(self.compute_checksum(buffer))
1296
1297    def get_header_size(self):
1298        return 8
1299
1300    def __str__(self):
1301        tmp_str = 'UDP %d -> %d' % (self.get_uh_sport(), self.get_uh_dport())
1302        if self.child():
1303            tmp_str += '\n' + str(self.child())
1304        return tmp_str
1305
1306    def get_packet(self):
1307        # set total length
1308        if(self.get_uh_ulen() == 0):
1309            self.set_uh_ulen(self.get_size())
1310        return Header.get_packet(self)
1311
1312class TCP(Header):
1313    protocol = 6
1314    TCP_FLAGS_MASK = 0x00FF # lowest 16 bits are the flags
1315    def __init__(self, aBuffer = None):
1316        Header.__init__(self, 20)
1317        self.set_th_off(5)
1318        self.__option_list = []
1319        if aBuffer:
1320            self.load_header(aBuffer)
1321
1322    def add_option(self, option):
1323        self.__option_list.append(option)
1324
1325        sum = 0
1326        for op in self.__option_list:
1327            sum += op.get_size()
1328
1329        if sum > 40:
1330            raise ImpactPacketException, "Cannot add TCP option, would overflow option space"
1331
1332    def get_options(self):
1333        return self.__option_list
1334
1335    def swapSourceAndDestination(self):
1336        oldSource = self.get_th_sport()
1337        self.set_th_sport(self.get_th_dport())
1338        self.set_th_dport(oldSource)
1339
1340    #
1341    # Header field accessors
1342    #
1343
1344    def set_th_sport(self, aValue):
1345        self.set_word(0, aValue)
1346
1347    def get_th_sport(self):
1348        return self.get_word(0)
1349
1350    def get_th_dport(self):
1351        return self.get_word(2)
1352
1353    def set_th_dport(self, aValue):
1354        self.set_word(2, aValue)
1355
1356    def get_th_seq(self):
1357        return self.get_long(4)
1358
1359    def set_th_seq(self, aValue):
1360        self.set_long(4, aValue)
1361
1362    def get_th_ack(self):
1363        return self.get_long(8)
1364
1365    def set_th_ack(self, aValue):
1366        self.set_long(8, aValue)
1367
1368    def get_th_flags(self):
1369        return self.get_word(12) & self.TCP_FLAGS_MASK
1370
1371    def set_th_flags(self, aValue):
1372        masked = self.get_word(12) & (~self.TCP_FLAGS_MASK)
1373        nb = masked | (aValue & self.TCP_FLAGS_MASK)
1374        return self.set_word(12, nb, ">")
1375
1376    def get_th_win(self):
1377        return self.get_word(14)
1378
1379    def set_th_win(self, aValue):
1380        self.set_word(14, aValue)
1381
1382    def set_th_sum(self, aValue):
1383        self.set_word(16, aValue)
1384        self.auto_checksum = 0
1385
1386    def get_th_sum(self):
1387        return self.get_word(16)
1388
1389    def get_th_urp(self):
1390        return self.get_word(18)
1391
1392    def set_th_urp(self, aValue):
1393        return self.set_word(18, aValue)
1394
1395    # Flag accessors
1396
1397    def get_th_reserved(self):
1398        tmp_value = self.get_byte(12) & 0x0f
1399        return tmp_value
1400
1401
1402    def get_th_off(self):
1403        tmp_value = self.get_byte(12) >> 4
1404        return tmp_value
1405
1406    def set_th_off(self, aValue):
1407        mask = 0xF0
1408        masked = self.get_byte(12) & (~mask)
1409        nb = masked | ( (aValue << 4) & mask)
1410        return self.set_byte(12, nb)
1411
1412    def get_CWR(self):
1413        return self.get_flag(128)
1414    def set_CWR(self):
1415        return self.set_flags(128)
1416    def reset_CWR(self):
1417        return self.reset_flags(128)
1418
1419    def get_ECE(self):
1420        return self.get_flag(64)
1421    def set_ECE(self):
1422        return self.set_flags(64)
1423    def reset_ECE(self):
1424        return self.reset_flags(64)
1425
1426    def get_URG(self):
1427        return self.get_flag(32)
1428    def set_URG(self):
1429        return self.set_flags(32)
1430    def reset_URG(self):
1431        return self.reset_flags(32)
1432
1433    def get_ACK(self):
1434        return self.get_flag(16)
1435    def set_ACK(self):
1436        return self.set_flags(16)
1437    def reset_ACK(self):
1438        return self.reset_flags(16)
1439
1440    def get_PSH(self):
1441        return self.get_flag(8)
1442    def set_PSH(self):
1443        return self.set_flags(8)
1444    def reset_PSH(self):
1445        return self.reset_flags(8)
1446
1447    def get_RST(self):
1448        return self.get_flag(4)
1449    def set_RST(self):
1450        return self.set_flags(4)
1451    def reset_RST(self):
1452        return self.reset_flags(4)
1453
1454    def get_SYN(self):
1455        return self.get_flag(2)
1456    def set_SYN(self):
1457        return self.set_flags(2)
1458    def reset_SYN(self):
1459        return self.reset_flags(2)
1460
1461    def get_FIN(self):
1462        return self.get_flag(1)
1463    def set_FIN(self):
1464        return self.set_flags(1)
1465    def reset_FIN(self):
1466        return self.reset_flags(1)
1467
1468    # Overridden Methods
1469
1470    def get_header_size(self):
1471        return 20 + len(self.get_padded_options())
1472
1473    def calculate_checksum(self):
1474        if not self.auto_checksum or not self.parent():
1475            return
1476
1477        self.set_th_sum(0)
1478        buffer = self.parent().get_pseudo_header()
1479        buffer += self.get_bytes()
1480        buffer += self.get_padded_options()
1481
1482        data = self.get_data_as_string()
1483        if(data):
1484            buffer.fromstring(data)
1485
1486        res = self.compute_checksum(buffer)
1487
1488        self.set_th_sum(self.compute_checksum(buffer))
1489
1490    def get_packet(self):
1491        "Returns entire packet including child data as a string.  This is the function used to extract the final packet"
1492
1493        # only change th_off value if options are present
1494        if len(self.__option_list):
1495            self.set_th_off(self.get_header_size() / 4)
1496
1497        self.calculate_checksum()
1498
1499        bytes = self.get_bytes() + self.get_padded_options()
1500        data = self.get_data_as_string()
1501
1502        if data:
1503            return bytes.tostring() + data
1504        else:
1505            return bytes.tostring()
1506
1507    def load_header(self, aBuffer):
1508        self.set_bytes_from_string(aBuffer[:20])
1509        opt_left = (self.get_th_off() - 5) * 4
1510        opt_bytes = array.array('B', aBuffer[20:(20 + opt_left)])
1511        if len(opt_bytes) != opt_left:
1512            raise ImpactPacketException, "Cannot load options from truncated packet"
1513
1514        while opt_left:
1515            op_kind = opt_bytes[0]
1516            if op_kind == TCPOption.TCPOPT_EOL or op_kind == TCPOption.TCPOPT_NOP:
1517                new_option = TCPOption(op_kind)
1518                op_len = 1
1519            else:
1520                op_len = opt_bytes[1]
1521                if op_len > len(opt_bytes):
1522                    raise ImpactPacketException, "TCP Option length is too high"
1523                if op_len < 2:
1524                    raise ImpactPacketException, "TCP Option length is too low"
1525
1526                new_option = TCPOption(op_kind)
1527                new_option.set_bytes(opt_bytes[:op_len])
1528
1529            opt_bytes = opt_bytes[op_len:]
1530            opt_left -= op_len
1531            self.add_option(new_option)
1532            if op_kind == TCPOption.TCPOPT_EOL:
1533                break
1534
1535    #
1536    # Private
1537    #
1538
1539    def get_flag(self, bit):
1540        if self.get_th_flags() & bit:
1541            return 1
1542        else:
1543            return 0
1544
1545    def reset_flags(self, aValue):
1546        tmp_value = self.get_th_flags() & (~aValue)
1547        return self.set_th_flags(tmp_value)
1548
1549    def set_flags(self, aValue):
1550        tmp_value =  self.get_th_flags() | aValue
1551        return self.set_th_flags(tmp_value)
1552
1553    def get_padded_options(self):
1554        "Return an array containing all options padded to a 4 byte boundary"
1555        op_buf = array.array('B')
1556        for op in self.__option_list:
1557            op_buf += op.get_bytes()
1558        num_pad = (4 - (len(op_buf) % 4)) % 4
1559        if num_pad:
1560            op_buf.fromstring("\0" * num_pad)
1561        return op_buf
1562
1563    def __str__(self):
1564        tmp_str = 'TCP '
1565        if self.get_ECE():
1566            tmp_str += 'ece '
1567        if self.get_CWR():
1568            tmp_str += 'cwr '
1569        if self.get_ACK():
1570            tmp_str += 'ack '
1571        if self.get_FIN():
1572            tmp_str += 'fin '
1573        if self.get_PSH():
1574            tmp_str += 'push '
1575        if self.get_RST():
1576            tmp_str += 'rst '
1577        if self.get_SYN():
1578            tmp_str += 'syn '
1579        if self.get_URG():
1580            tmp_str += 'urg '
1581        tmp_str += '%d -> %d' % (self.get_th_sport(), self.get_th_dport())
1582        for op in self.__option_list:
1583            tmp_str += '\n' + str(op)
1584
1585        if self.child():
1586            tmp_str += '\n' + str(self.child())
1587        return tmp_str
1588
1589
1590class TCPOption(PacketBuffer):
1591    TCPOPT_EOL =             0
1592    TCPOPT_NOP  =            1
1593    TCPOPT_MAXSEG =          2
1594    TCPOPT_WINDOW  =         3
1595    TCPOPT_SACK_PERMITTED =  4
1596    TCPOPT_SACK         =    5
1597    TCPOPT_TIMESTAMP    =    8
1598    TCPOPT_SIGNATURE    =    19
1599
1600
1601    def __init__(self, kind, data = None):
1602
1603        if kind == TCPOption.TCPOPT_EOL:
1604            PacketBuffer.__init__(self, 1)
1605            self.set_kind(TCPOption.TCPOPT_EOL)
1606        elif kind == TCPOption.TCPOPT_NOP:
1607            PacketBuffer.__init__(self, 1)
1608            self.set_kind(TCPOption.TCPOPT_NOP)
1609        elif kind == TCPOption.TCPOPT_MAXSEG:
1610            PacketBuffer.__init__(self, 4)
1611            self.set_kind(TCPOption.TCPOPT_MAXSEG)
1612            self.set_len(4)
1613            if data:
1614                self.set_mss(data)
1615            else:
1616                self.set_mss(512)
1617        elif kind == TCPOption.TCPOPT_WINDOW:
1618            PacketBuffer.__init__(self, 3)
1619            self.set_kind(TCPOption.TCPOPT_WINDOW)
1620            self.set_len(3)
1621            if data:
1622                self.set_shift_cnt(data)
1623            else:
1624                self.set_shift_cnt(0)
1625        elif kind == TCPOption.TCPOPT_TIMESTAMP:
1626            PacketBuffer.__init__(self, 10)
1627            self.set_kind(TCPOption.TCPOPT_TIMESTAMP)
1628            self.set_len(10)
1629            if data:
1630                self.set_ts(data)
1631            else:
1632                self.set_ts(0)
1633        elif kind == TCPOption.TCPOPT_SACK_PERMITTED:
1634            PacketBuffer.__init__(self, 2)
1635            self.set_kind(TCPOption.TCPOPT_SACK_PERMITTED)
1636            self.set_len(2)
1637
1638        elif kind == TCPOption.TCPOPT_SACK:
1639            PacketBuffer.__init__(self, 2)
1640            self.set_kind(TCPOption.TCPOPT_SACK)
1641
1642    def set_left_edge(self, aValue):
1643        self.set_long (2, aValue)
1644
1645    def set_right_edge(self, aValue):
1646        self.set_long (6, aValue)
1647
1648    def set_kind(self, kind):
1649        self.set_byte(0, kind)
1650
1651
1652    def get_kind(self):
1653        return self.get_byte(0)
1654
1655
1656    def set_len(self, len):
1657        if self.get_size() < 2:
1658            raise ImpactPacketException, "Cannot set length field on an option having a size smaller than 2 bytes"
1659        self.set_byte(1, len)
1660
1661    def get_len(self):
1662        if self.get_size() < 2:
1663            raise ImpactPacketException, "Cannot retrieve length field from an option having a size smaller than 2 bytes"
1664        return self.get_byte(1)
1665
1666    def get_size(self):
1667        return len(self.get_bytes())
1668
1669
1670    def set_mss(self, len):
1671        if self.get_kind() != TCPOption.TCPOPT_MAXSEG:
1672            raise ImpactPacketException, "Can only set MSS on TCPOPT_MAXSEG option"
1673        self.set_word(2, len)
1674
1675    def get_mss(self):
1676        if self.get_kind() != TCPOption.TCPOPT_MAXSEG:
1677            raise ImpactPacketException, "Can only retrieve MSS from TCPOPT_MAXSEG option"
1678        return self.get_word(2)
1679
1680    def set_shift_cnt(self, cnt):
1681        if self.get_kind() != TCPOption.TCPOPT_WINDOW:
1682            raise ImpactPacketException, "Can only set Shift Count on TCPOPT_WINDOW option"
1683        self.set_byte(2, cnt)
1684
1685    def get_shift_cnt(self):
1686        if self.get_kind() != TCPOption.TCPOPT_WINDOW:
1687            raise ImpactPacketException, "Can only retrieve Shift Count from TCPOPT_WINDOW option"
1688        return self.get_byte(2)
1689
1690    def get_ts(self):
1691        if self.get_kind() != TCPOption.TCPOPT_TIMESTAMP:
1692            raise ImpactPacketException, "Can only retrieve timestamp from TCPOPT_TIMESTAMP option"
1693        return self.get_long(2)
1694
1695    def set_ts(self, ts):
1696        if self.get_kind() != TCPOption.TCPOPT_TIMESTAMP:
1697            raise ImpactPacketException, "Can only set timestamp on TCPOPT_TIMESTAMP option"
1698        self.set_long(2, ts)
1699
1700    def get_ts_echo(self):
1701        if self.get_kind() != TCPOption.TCPOPT_TIMESTAMP:
1702            raise ImpactPacketException, "Can only retrieve timestamp from TCPOPT_TIMESTAMP option"
1703        return self.get_long(6)
1704
1705    def set_ts_echo(self, ts):
1706        if self.get_kind() != TCPOption.TCPOPT_TIMESTAMP:
1707            raise ImpactPacketException, "Can only set timestamp on TCPOPT_TIMESTAMP option"
1708        self.set_long(6, ts)
1709
1710    def __str__(self):
1711        map = { TCPOption.TCPOPT_EOL : "End of List ",
1712                TCPOption.TCPOPT_NOP : "No Operation ",
1713                TCPOption.TCPOPT_MAXSEG : "Maximum Segment Size ",
1714                TCPOption.TCPOPT_WINDOW : "Window Scale ",
1715                TCPOption.TCPOPT_TIMESTAMP : "Timestamp " }
1716
1717        tmp_str = "\tTCP Option: "
1718        op = self.get_kind()
1719        if map.has_key(op):
1720            tmp_str += map[op]
1721        else:
1722            tmp_str += " kind: %d " % op
1723        if op == TCPOption.TCPOPT_MAXSEG:
1724            tmp_str += " MSS : %d " % self.get_mss()
1725        elif op == TCPOption.TCPOPT_WINDOW:
1726            tmp_str += " Shift Count: %d " % self.get_shift_cnt()
1727        elif op == TCPOption.TCPOPT_TIMESTAMP:
1728            pass # TODO
1729        return tmp_str
1730
1731class ICMP(Header):
1732    protocol = 1
1733    ICMP_ECHOREPLY              = 0
1734    ICMP_UNREACH                = 3
1735    ICMP_UNREACH_NET            = 0
1736    ICMP_UNREACH_HOST           = 1
1737    ICMP_UNREACH_PROTOCOL       = 2
1738    ICMP_UNREACH_PORT           = 3
1739    ICMP_UNREACH_NEEDFRAG       = 4
1740    ICMP_UNREACH_SRCFAIL        = 5
1741    ICMP_UNREACH_NET_UNKNOWN    = 6
1742    ICMP_UNREACH_HOST_UNKNOWN   = 7
1743    ICMP_UNREACH_ISOLATED       = 8
1744    ICMP_UNREACH_NET_PROHIB     = 9
1745    ICMP_UNREACH_HOST_PROHIB    = 10
1746    ICMP_UNREACH_TOSNET         = 11
1747    ICMP_UNREACH_TOSHOST        = 12
1748    ICMP_UNREACH_FILTERPROHIB   = 13
1749    ICMP_UNREACH_HOST_PRECEDENCE = 14
1750    ICMP_UNREACH_PRECEDENCE_CUTOFF = 15
1751    ICMP_SOURCEQUENCH               = 4
1752    ICMP_REDIRECT                   = 5
1753    ICMP_REDIRECT_NET           = 0
1754    ICMP_REDIRECT_HOST          = 1
1755    ICMP_REDIRECT_TOSNET        = 2
1756    ICMP_REDIRECT_TOSHOST       = 3
1757    ICMP_ALTHOSTADDR                = 6
1758    ICMP_ECHO                       = 8
1759    ICMP_ROUTERADVERT               = 9
1760    ICMP_ROUTERSOLICIT              = 10
1761    ICMP_TIMXCEED                   = 11
1762    ICMP_TIMXCEED_INTRANS       = 0
1763    ICMP_TIMXCEED_REASS         = 1
1764    ICMP_PARAMPROB                  = 12
1765    ICMP_PARAMPROB_ERRATPTR     = 0
1766    ICMP_PARAMPROB_OPTABSENT    = 1
1767    ICMP_PARAMPROB_LENGTH       = 2
1768    ICMP_TSTAMP                     = 13
1769    ICMP_TSTAMPREPLY                = 14
1770    ICMP_IREQ                       = 15
1771    ICMP_IREQREPLY                  = 16
1772    ICMP_MASKREQ                    = 17
1773    ICMP_MASKREPLY                  = 18
1774
1775    def __init__(self, aBuffer = None):
1776        Header.__init__(self, 8)
1777        if aBuffer:
1778            self.load_header(aBuffer)
1779
1780    def get_header_size(self):
1781        anamolies = { ICMP.ICMP_TSTAMP : 20, ICMP.ICMP_TSTAMPREPLY : 20, ICMP.ICMP_MASKREQ : 12, ICMP.ICMP_MASKREPLY : 12 }
1782        if anamolies.has_key(self.get_icmp_type()):
1783            return anamolies[self.get_icmp_type()]
1784        else:
1785            return 8
1786
1787    def get_icmp_type(self):
1788        return self.get_byte(0)
1789
1790    def set_icmp_type(self, aValue):
1791        self.set_byte(0, aValue)
1792
1793    def get_icmp_code(self):
1794        return self.get_byte(1)
1795
1796    def set_icmp_code(self, aValue):
1797        self.set_byte(1, aValue)
1798
1799    def get_icmp_cksum(self):
1800        return self.get_word(2)
1801
1802    def set_icmp_cksum(self, aValue):
1803        self.set_word(2, aValue)
1804        self.auto_checksum = 0
1805
1806    def get_icmp_gwaddr(self):
1807        return self.get_ip_address(4)
1808
1809    def set_icmp_gwaddr(self, ip):
1810        self.set_ip_address(4, ip)
1811
1812    def get_icmp_id(self):
1813        return self.get_word(4)
1814
1815    def set_icmp_id(self, aValue):
1816        self.set_word(4, aValue)
1817
1818    def get_icmp_seq(self):
1819        return self.get_word(6)
1820
1821    def set_icmp_seq(self, aValue):
1822        self.set_word(6, aValue)
1823
1824    def get_icmp_void(self):
1825        return self.get_long(4)
1826
1827    def set_icmp_void(self, aValue):
1828        self.set_long(4, aValue)
1829
1830
1831    def get_icmp_nextmtu(self):
1832        return self.get_word(6)
1833
1834    def set_icmp_nextmtu(self, aValue):
1835        self.set_word(6, aValue)
1836
1837    def get_icmp_num_addrs(self):
1838        return self.get_byte(4)
1839
1840    def set_icmp_num_addrs(self, aValue):
1841        self.set_byte(4, aValue)
1842
1843    def get_icmp_wpa(self):
1844        return self.get_byte(5)
1845
1846    def set_icmp_wpa(self, aValue):
1847        self.set_byte(5, aValue)
1848
1849    def get_icmp_lifetime(self):
1850        return self.get_word(6)
1851
1852    def set_icmp_lifetime(self, aValue):
1853        self.set_word(6, aValue)
1854
1855    def get_icmp_otime(self):
1856        return self.get_long(8)
1857
1858    def set_icmp_otime(self, aValue):
1859        self.set_long(8, aValue)
1860
1861    def get_icmp_rtime(self):
1862        return self.get_long(12)
1863
1864    def set_icmp_rtime(self, aValue):
1865        self.set_long(12, aValue)
1866
1867    def get_icmp_ttime(self):
1868        return self.get_long(16)
1869
1870    def set_icmp_ttime(self, aValue):
1871        self.set_long(16, aValue)
1872
1873    def get_icmp_mask(self):
1874        return self.get_ip_address(8)
1875
1876    def set_icmp_mask(self, mask):
1877        self.set_ip_address(8, mask)
1878
1879
1880    def calculate_checksum(self):
1881        if self.auto_checksum and (not self.get_icmp_cksum()):
1882            buffer = self.get_buffer_as_string()
1883            data = self.get_data_as_string()
1884            if data:
1885                buffer += data
1886
1887            tmp_array = array.array('B', buffer)
1888            self.set_icmp_cksum(self.compute_checksum(tmp_array))
1889
1890    def get_type_name(self, aType):
1891        tmp_type = {0:'ECHOREPLY', 3:'UNREACH', 4:'SOURCEQUENCH',5:'REDIRECT', 6:'ALTHOSTADDR', 8:'ECHO', 9:'ROUTERADVERT', 10:'ROUTERSOLICIT', 11:'TIMXCEED', 12:'PARAMPROB', 13:'TSTAMP', 14:'TSTAMPREPLY', 15:'IREQ', 16:'IREQREPLY', 17:'MASKREQ', 18:'MASKREPLY', 30:'TRACEROUTE', 31:'DATACONVERR', 32:'MOBILE REDIRECT', 33:'IPV6 WHEREAREYOU', 34:'IPV6 IAMHERE', 35:'MOBILE REGREQUEST', 36:'MOBILE REGREPLY', 39:'SKIP', 40:'PHOTURIS'}
1892        answer = tmp_type.get(aType, 'UNKNOWN')
1893        return answer
1894
1895    def get_code_name(self, aType, aCode):
1896        tmp_code = {3:['UNREACH NET', 'UNREACH HOST', 'UNREACH PROTOCOL', 'UNREACH PORT', 'UNREACH NEEDFRAG', 'UNREACH SRCFAIL', 'UNREACH NET UNKNOWN', 'UNREACH HOST UNKNOWN', 'UNREACH ISOLATED', 'UNREACH NET PROHIB', 'UNREACH HOST PROHIB', 'UNREACH TOSNET', 'UNREACH TOSHOST', 'UNREACH FILTER PROHIB', 'UNREACH HOST PRECEDENCE', 'UNREACH PRECEDENCE CUTOFF', 'UNKNOWN ICMP UNREACH']}
1897        tmp_code[5] = ['REDIRECT NET', 'REDIRECT HOST', 'REDIRECT TOSNET', 'REDIRECT TOSHOST']
1898        tmp_code[9] = ['ROUTERADVERT NORMAL', None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,'ROUTERADVERT NOROUTE COMMON']
1899        tmp_code[11] = ['TIMXCEED INTRANS ', 'TIMXCEED REASS']
1900        tmp_code[12] = ['PARAMPROB ERRATPTR ', 'PARAMPROB OPTABSENT', 'PARAMPROB LENGTH']
1901        tmp_code[40] = [None, 'PHOTURIS UNKNOWN INDEX', 'PHOTURIS AUTH FAILED', 'PHOTURIS DECRYPT FAILED']
1902        if tmp_code.has_key(aType):
1903            tmp_list = tmp_code[aType]
1904            if ((aCode + 1) > len(tmp_list)) or (not tmp_list[aCode]):
1905                return 'UNKNOWN'
1906            else:
1907                return tmp_list[aCode]
1908        else:
1909            return 'UNKNOWN'
1910
1911    def __str__(self):
1912        tmp_type = self.get_icmp_type()
1913        tmp_code = self.get_icmp_code()
1914        tmp_str = 'ICMP type: ' + self.get_type_name(tmp_type)
1915        tmp_str+= ' code: ' + self.get_code_name(tmp_type, tmp_code)
1916        if self.child():
1917            tmp_str += '\n' + str( self.child() )
1918        return tmp_str
1919
1920    def isDestinationUnreachable(self):
1921        return self.get_icmp_type() == 3
1922
1923    def isError(self):
1924        return not self.isQuery()
1925
1926    def isHostUnreachable(self):
1927        return self.isDestinationUnreachable() and (self.get_icmp_code() == 1)
1928
1929    def isNetUnreachable(self):
1930        return self.isDestinationUnreachable() and (self.get_icmp_code() == 0)
1931
1932    def isPortUnreachable(self):
1933        return self.isDestinationUnreachable() and (self.get_icmp_code() == 3)
1934
1935    def isProtocolUnreachable(self):
1936        return self.isDestinationUnreachable() and (self.get_icmp_code() == 2)
1937
1938    def isQuery(self):
1939        tmp_dict = {8:'',  9:'',  10:'', 13:'', 14:'', 15:'', 16:'', 17:'', 18:''}
1940        return tmp_dict.has_key(self.get_icmp_type())
1941
1942class IGMP(Header):
1943    protocol = 2
1944    def __init__(self, aBuffer = None):
1945        Header.__init__(self, 8)
1946        if aBuffer:
1947            self.load_header(aBuffer)
1948
1949    def get_igmp_type(self):
1950        return self.get_byte(0)
1951
1952    def set_igmp_type(self, aValue):
1953        self.set_byte(0, aValue)
1954
1955    def get_igmp_code(self):
1956        return self.get_byte(1)
1957
1958    def set_igmp_code(self, aValue):
1959        self.set_byte(1, aValue)
1960
1961    def get_igmp_cksum(self):
1962        return self.get_word(2)
1963
1964    def set_igmp_cksum(self, aValue):
1965        self.set_word(2, aValue)
1966
1967    def get_igmp_group(self):
1968        return self.get_long(4)
1969
1970    def set_igmp_group(self, aValue):
1971        self.set_long(4, aValue)
1972
1973    def get_header_size(self):
1974        return 8
1975
1976    def get_type_name(self, aType):
1977        tmp_dict = {0x11:'HOST MEMBERSHIP QUERY ', 0x12:'v1 HOST MEMBERSHIP REPORT ', 0x13:'IGMP DVMRP ', 0x14:' PIM ', 0x16:'v2 HOST MEMBERSHIP REPORT ', 0x17:'HOST LEAVE MESSAGE ', 0x1e:'MTRACE REPLY ', 0X1f:'MTRACE QUERY '}
1978        answer = tmp_dict.get(aType, 'UNKNOWN TYPE OR VERSION ')
1979        return answer
1980
1981    def calculate_checksum(self):
1982        if self.auto_checksum and (not self.get_igmp_cksum()):
1983            self.set_igmp_cksum(self.compute_checksum(self.get_bytes()))
1984
1985    def __str__(self):
1986        tmp_str = 'IGMP: ' + self.get_type_name(self.get_igmp_type())
1987        tmp_str += 'Group: ' +  socket.inet_ntoa(struct.pack('!L',self.get_igmp_group()))
1988        if self.child():
1989            tmp_str += '\n' + str(self.child())
1990        return tmp_str
1991
1992
1993
1994class ARP(Header):
1995    ethertype = 0x806
1996    def __init__(self, aBuffer = None):
1997        Header.__init__(self, 7)
1998        if aBuffer:
1999            self.load_header(aBuffer)
2000
2001    def get_ar_hrd(self):
2002        return self.get_word(0)
2003
2004    def set_ar_hrd(self, aValue):
2005        self.set_word(0, aValue)
2006
2007    def get_ar_pro(self):
2008        return self.get_word(2)
2009
2010    def set_ar_pro(self, aValue):
2011        self.set_word(2, aValue)
2012
2013    def get_ar_hln(self):
2014        return self.get_byte(4)
2015
2016    def set_ar_hln(self, aValue):
2017        self.set_byte(4, aValue)
2018
2019    def get_ar_pln(self):
2020        return self.get_byte(5)
2021
2022    def set_ar_pln(self, aValue):
2023        self.set_byte(5, aValue)
2024
2025    def get_ar_op(self):
2026        return self.get_word(6)
2027
2028    def set_ar_op(self, aValue):
2029        self.set_word(6, aValue)
2030
2031    def get_ar_sha(self):
2032        tmp_size = self.get_ar_hln()
2033        return self.get_bytes().tolist()[8: 8 + tmp_size]
2034
2035    def set_ar_sha(self, aValue):
2036        for i in range(0, self.get_ar_hln()):
2037            self.set_byte(i + 8, aValue[i])
2038
2039    def get_ar_spa(self):
2040        tmp_size = self.get_ar_pln()
2041        return self.get_bytes().tolist()[8 + self.get_ar_hln(): 8 + self.get_ar_hln() + tmp_size]
2042
2043    def set_ar_spa(self, aValue):
2044        for i in range(0, self.get_ar_pln()):
2045            self.set_byte(i + 8 + self.get_ar_hln(), aValue[i])
2046
2047    def get_ar_tha(self):
2048        tmp_size = self.get_ar_hln()
2049        tmp_from = 8 + self.get_ar_hln() + self.get_ar_pln()
2050        return self.get_bytes().tolist()[tmp_from: tmp_from + tmp_size]
2051
2052    def set_ar_tha(self, aValue):
2053        tmp_from = 8 + self.get_ar_hln() + self.get_ar_pln()
2054        for i in range(0, self.get_ar_hln()):
2055            self.set_byte(i + tmp_from, aValue[i])
2056
2057    def get_ar_tpa(self):
2058        tmp_size = self.get_ar_pln()
2059        tmp_from = 8 + ( 2 * self.get_ar_hln()) + self.get_ar_pln()
2060        return self.get_bytes().tolist()[tmp_from: tmp_from + tmp_size]
2061
2062    def set_ar_tpa(self, aValue):
2063        tmp_from = 8 + (2 * self.get_ar_hln()) + self.get_ar_pln()
2064        for i in range(0, self.get_ar_pln()):
2065            self.set_byte(i + tmp_from, aValue[i])
2066
2067    def get_header_size(self):
2068        return 8 + (2 * self.get_ar_hln()) + (2 * self.get_ar_pln())
2069
2070    def get_op_name(self, ar_op):
2071        tmp_dict = {1:'REQUEST', 2:'REPLY', 3:'REVREQUEST', 4:'REVREPLY', 8:'INVREQUEST', 9:'INVREPLY'}
2072        answer = tmp_dict.get(ar_op, 'UNKNOWN')
2073        return answer
2074
2075    def get_hrd_name(self, ar_hrd):
2076        tmp_dict = { 1:'ARPHRD ETHER', 6:'ARPHRD IEEE802', 15:'ARPHRD FRELAY'}
2077        answer = tmp_dict.get(ar_hrd, 'UNKNOWN')
2078        return answer
2079
2080
2081    def as_hrd(self, anArray):
2082        if not anArray:
2083            return ''
2084        tmp_str = '%x' % anArray[0]
2085        for i in range(1, len(anArray)):
2086            tmp_str += ':%x' % anArray[i]
2087        return tmp_str
2088
2089    def as_pro(self, anArray):
2090        if not anArray:
2091            return ''
2092        tmp_str = '%d' % anArray[0]
2093        for i in range(1, len(anArray)):
2094            tmp_str += '.%d' % anArray[i]
2095        return tmp_str
2096
2097    def __str__(self):
2098        tmp_op = self.get_ar_op()
2099        tmp_str = 'ARP format: ' + self.get_hrd_name(self.get_ar_hrd()) + ' '
2100        tmp_str += 'opcode: ' + self.get_op_name(tmp_op)
2101        tmp_str += '\n' + self.as_hrd(self.get_ar_sha()) + ' -> '
2102        tmp_str += self.as_hrd(self.get_ar_tha())
2103        tmp_str += '\n' + self.as_pro(self.get_ar_spa()) + ' -> '
2104        tmp_str += self.as_pro(self.get_ar_tpa())
2105        if self.child():
2106            tmp_str += '\n' + str(self.child())
2107        return tmp_str
2108
2109def example(): #To execute an example, remove this line
2110    a = Ethernet()
2111    b = ARP()
2112    c = Data('Hola loco!!!')
2113    b.set_ar_hln(6)
2114    b.set_ar_pln(4)
2115    #a.set_ip_dst('192.168.22.6')
2116    #a.set_ip_src('1.1.1.2')
2117    a.contains(b)
2118    b.contains(c)
2119    b.set_ar_op(2)
2120    b.set_ar_hrd(1)
2121    b.set_ar_spa((192, 168, 22, 6))
2122    b.set_ar_tpa((192, 168, 66, 171))
2123    a.set_ether_shost((0x0, 0xe0, 0x7d, 0x8a, 0xef, 0x3d))
2124    a.set_ether_dhost((0x0, 0xc0, 0xdf, 0x6, 0x5, 0xe))
2125    print "beto %s" % a
2126
2127