root/branch/UMPA/umpa/protocols/TCP.py @ 3343

Revision 3343, 8.0 kB (checked in by getxsick, 5 years ago)

New util's function utils.bits.get_bits()

Return a chunk of the number, regarding on how many bits we need.
Also we can pass offset. It supports left and right side offset.
Right offset is recommended because we can skip some inner calculation.
But because of logic, left offset is default.

Also, updated code which use this function.

Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4# Copyright (C) 2008 Adriano Monteiro Marques.
5#
6# Author: Bartosz SKOWRON <getxsick at gmail dot com>
7#
8# This library is free software; you can redistribute it and/or modify
9# it under the terms of the GNU Lesser General Public License as published
10# by the Free Software Foundation; either version 2.1 of the License, or
11# (at your option) any later version.
12#
13# This library is distributed in the hope that it will be useful, but
14# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16# License for more details.
17#
18# You should have received a copy of the GNU Lesser General Public License
19# along with this library; if not, write to the Free Software Foundation,
20# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
22import umpa.protocols._consts as const
23
24from umpa.protocols import *
25from umpa.protocols._layer4 import *
26from umpa.utils import net
27from umpa.utils import bits
28
29class HSequenceNumber(IntField):
30    """The sequence number of the first data octet in this segment (except
31    when SYN is present).
32
33    See RFC 793 for more.
34    """
35    bits = 32
36    auto = True
37    def _generate_value(self):
38        # TODO: implemention real auto-filling here ;)
39        # otherwise we can simple return 0
40        return 0
41
42class HAcknowledgmentNumber(IntField):
43    """If the ACK control bit is set this field contains the value of the
44    next sequence number the sender of the segment is expecting to receive.
45
46    See RFC 793 for more.
47    """
48    bits = 32
49    auto = True
50    def _generate_value(self):
51        # TODO: implemention real auto-filling here ;)
52        # otherwise we can simple return 0
53        return 1
54
55class HDataOffset(SpecialIntField):
56    """The number of 32 bit words in the TCP Header. This indicates where
57    the data begins.
58
59    See RFC 793 for more.
60    """
61    bits = 4
62    auto = True
63    def _generate_value(self):
64        # returns in 32-bits units
65        return 5 + self._tmp_value / 32 # 5 is a minimum value
66
67class HReserved(IntField):
68    """Reserved for future use.
69
70    See RFC 793 for more.
71    """
72    bits = 6
73    auto = True
74    def _generate_value(self):
75        return 0
76
77class HWindow(IntField):
78    """The number of data octets beginning with the one indicated in the
79    acknowledgment field which the sender of this segment is willing to accept.
80
81    See RFC 793 for more.
82    """
83    bits = 16
84    auto = True
85    def _generate_value(self):
86        # TODO: implemention real auto-filling here ;)
87        # otherwise we can simple return 0
88        return 512
89
90class HUrgentPointer(IntField):
91    """This field communicates the current value of the urgent pointer as a
92    positive offset from the sequence number in this segment.
93
94    See RFC 793 for more.
95    """
96    bits = 16
97    auto = True
98    def _generate_value(self):
99        # TODO: implemention real auto-filling here ;)
100        # otherwise we can simple return 0
101        return 0
102
103class TCP(Protocol):
104    """This is Transmission Control Protocol.
105    It the most common protocol in the Internet on fourth layer
106    of the OSI model.
107    """
108    layer = 4       # layer of the OSI
109    protocol_id = const.PROTOCOL_TCP
110
111    _ordered_fields = ('source_port', 'destination_port', '_sequence_number',
112                    '_acknowledgment_number', '_data_offset', '_reserved',
113                    'control_bits', '_window', '_checksum', '_urgent_pointer',
114                    'options', '_padding',)
115
116    def __init__(self, **kw):
117        control_bits = ('urg', 'ack', 'psh', 'rst', 'syn', 'fin')
118        control_bits_predefined = dict.fromkeys(control_bits, 0)
119
120        fields_list = [ PortField("Source Port", 0),
121                        PortField("Destination Port", 0),
122                        HSequenceNumber("Sequence Number"),
123                        HAcknowledgmentNumber("Acknowledgment Number"),
124                        HDataOffset("DataOffset"), HReserved("Reserved", 0),
125                        Flags("Control Bits", control_bits,
126                        **control_bits_predefined),
127                        HWindow("Window"), Layer4ChecksumField("Checksum"),
128                        HUrgentPointer("Urgent Pointer"), Flags("Options", ()),
129                        PaddingField("Padding") ]
130
131        # we call super.__init__ after prepared necessary data
132        super(TCP, self).__init__(fields_list, **kw)
133
134        # set __doc__ for fields - it's important if you want to get hints
135        # in some frontends. E.g. Umit Project provides one...
136        self._get_field('source_port').set_doc("The source port number. \
137See RFC 793 for more.")
138        self._get_field('destination_port').set_doc("The destination port \
139number. See RFC 793 for more.")
140        self._get_field('control_bits').set_doc("URG, ACK, PSH, RST, SYN, FIN \
141flags. See RFC 793 for more.")
142        self._get_field('options').set_doc("Options may occupy space at the \
143end of the TCP header and are a multiple of 8 bits in length. See RFC 793 \
144for more.")
145        self._get_field('_padding').set_doc("The TCP header padding is used \
146to ensure that the TCP header ends and data begins on a 32 bit boundary. \
147See RFC 793 for more.")
148
149    def _raw(self, protocol_container, protocol_bits):
150        bit = 0
151        raw_value = 0
152
153        # Padding
154        self._get_field('_padding')._tmp_value = \
155                                                self._get_field('options').bits
156
157        # Data Offset
158        self._get_field('_data_offset')._tmp_value = \
159            self._get_field('options').bits + self._get_field('_padding').bits
160
161        # so we make a big number with bits of every fields of the protocol
162        for field in reversed(self._ordered_fields):
163            x = self._get_field(field).fillout()
164            raw_value |= x << bit
165            bit += self._get_field(field).bits
166
167        # rev_offset it the offset from the right side
168        cksum_rev_offset = bit - self.get_offset('_checksum') - \
169                                            self._get_field('_checksum').bits
170        # checking if user not defined his own value of checksum
171        if bits.get_bits(raw_value, self._get_field('_checksum').bits,
172                                    cksum_rev_offset, rev_offset=True) == 0:
173            cksum = 0
174            offset = 0
175            # TODO: payload is off. it should works but it's odd, we generate
176            # bits by calling get_raw for payload. completely but.
177            # also because of some new suggestions about look after of payload
178            # very very soon, should be reorgnized payload issue
179            # and this issue also
180            #
181            # Payload
182            #it = iter(protocol_container)
183            #for proto in it:
184            #    if proto is self:
185            #        break
186            #try:
187            #    proto = it.next()
188            #    payload = proto._get_raw(protocol_container, protocol_bits)
189            #except StopIteration:
190            #    payload = 0
191
192            #cksum = payload
193            #offset = protocol_bits
194
195            # TCP Header
196            cksum |= raw_value << offset
197            offset += bit
198
199            # Pseudo Header
200            #
201            # TCP header length...converted to bits unit
202            total_length = self._get_field('_data_offset').fillout()*32
203            # add payload
204            total_length += protocol_bits
205            # conversion to bytes unit
206            total_length /= 8
207
208            # create pseudo header object
209            pheader = PseudoHeader(self.protocol_id, total_length)
210            # generate raw value of it
211            pheader_bits = pheader._get_raw(protocol_container,
212                                                            protocol_bits)[0]
213            # added pseudo header bits to cksum value
214            cksum |= pheader_bits << offset
215
216            # finally, calcute and apply checksum
217            raw_cksum = net.in_cksum(cksum)
218            raw_value |= raw_cksum << cksum_rev_offset
219
220        return raw_value, bit
221
222protocols = [ TCP, ]
Note: See TracBrowser for help on using the browser.