root/branch/UMPA/umpa/protocols/IP.py @ 3289

Revision 3289, 8.3 kB (checked in by getxsick, 5 years ago)

New class SpecialIntField?.

This class is useful if the field handles with other fields in the protocol
or with other protocols in general.

There is new value _tmp_value to help generate the raw result.

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.utils import net
26
27class HVersion(IntField):
28    """The Version field indicates the format of the internet header.
29   
30    See RFC 791 for more.
31    """
32    bits = 4
33    auto = True
34    def _generate_value(self):
35        return const.IPVERSION_4
36
37class HIHL(SpecialIntField):
38    """Internet Header Length is the length of the internet header in 32 bit
39    words, and thus points to the beginning of the data.
40   
41    See RFC 791 for more.
42    """
43    bits = 4
44    auto = True
45    def _generate_value(self):
46        return 5 + self._tmp_value / 32 # 5 is a minimum value (see RFC 791)
47
48class HTotalLength(IntField):
49    """Total Length is the length of the datagram, measured in octets,
50    including internet header and data.
51
52    See RFC 791 for more.
53    """
54    bits = 16
55    auto = True
56    def _generate_value(self):
57        pass
58
59class HIdentification(IntField):
60    """An identifying value assigned by the sender to aid in assembling the
61    fragments of a datagram.
62
63    See RFC 791 for more.
64    """
65    bits = 16
66    auto = True
67    def _generate_value(self):
68        # TODO: implementation of fragmentation
69        # otherwise we can simple return 0 ;-)
70        return 0
71
72class HFragmentOffset(IntField):
73    """This field indicates where in the datagram this fragment belongs.
74   
75    See RFC 791 for more.
76    """
77    bits = 13
78    auto = True
79    def _generate_value(self):
80        # TODO: implementation of fragmentation
81        # otherwise we can simple return 0 ;-)
82        return 0
83
84class HTTL(IntField):
85    """This field indicates the maximum time the datagram is allowed to
86    remain in the internet system.
87   
88    See RFC 791 for more.
89    """
90    bits = 8
91    auto = True
92    def _generate_value(self):
93        # TODO: checking platform to get correct value of TTL
94        # unfortunately, there isn't any official document which described
95        # list of returns from sys.platform
96        # also, there is some changes in Python 2.6 about sys.platform
97        return const.TTL_LINUX
98
99    def ttl(self, name):
100        """To set correct value of TTL for following platforms:
101        AIX, DEC, FREEBSD, HPUX, IRIX, LINUX, MACOS, OS2, SOLARIS,
102        SUNOS, ULTRIX, WINDOWS.
103
104        name argument can be pass as shown above or as TTL_NAME
105        """
106
107        if not name.startswith("TTL_"):
108            name = "TTL_" + name
109        self._value = getattr(const, name)
110
111class HProtocol(SpecialIntField):
112    """This field indicates the next level protocol used in the data portion
113    of the internet datagram.
114   
115    See RFC 791 for more.
116    """
117    bits = 8
118    auto = True
119    def _generate_value(self):
120        return self._tmp_value
121
122class HHeaderChecksum(IntField):
123    """A checksum on the header only.
124   
125    See RFC 791 for more.
126    """
127    bits = 16
128    auto = True
129    def _generate_value(self):
130        return 0        # HeaderChecksum field should be initialized by 0
131
132class HPadding(PaddingField, SpecialIntField):
133    """The internet header padding is used to ensure that the internet header
134    ends on a 32 bit boundary.
135   
136    See RFC 791 for more.
137    """
138    bits = 0
139    auto = True
140    def _generate_value(self):
141        return (32 - (self._temp_value % 32)) % 32
142
143# main IP class
144
145class IP(Protocol):
146    """This is Internet Protocol.
147    The main protocol in third layer of OSI model.
148    """
149    layer = 3      # layer of OSI
150
151    _ordered_fields = ('_version', '_ihl', 'type_of_service', '_total_length',
152                    '_identification', 'flags', '_fragment_offset',
153                    'time_to_live', '_protocol', '_header_checksum',
154                    'source_address', 'destination_address', 'options',
155                    '_padding',)
156
157    def __init__(self, **kw):
158        tos = ('precedence0','precedence1', 'precedence2', 'delay',
159                'throughput', 'relibility', 'reserved0', 'reserved1')
160        tos_predefined = dict.fromkeys(tos, 0)
161
162        flags = ('reserved', 'df', 'mf')
163        flags_predefined = dict.fromkeys(flags, 0)
164
165        # TODO:
166        #   - support for fragmentation
167        #       defaulty we don't you fragmentation but we should support it
168        #       if user choose this option
169        #   - checking platform for TTL value
170        #       to be more reliable we should generate default value depends on
171        #       user platform. does anyone know every values of sys.platform? :)
172        fields_list = [ HVersion("Version", 4), HIHL("IHL"),
173                        Flags("TOS", tos, **tos_predefined),
174                        HTotalLength("Total Length"),
175                        HIdentification("Identification", 0),
176                        Flags("Flags", flags, **flags_predefined),
177                        HFragmentOffset("Fragment Offset", 0),
178                        HTTL("TTL", const.TTL_LINUX), HProtocol("Protocol"),
179                        HHeaderChecksum("Header Checksum", 0),
180                        IPv4AddrField("Source Address", "127.0.0.1", 16),
181                        IPv4AddrField("Destination Address", "127.0.0.1", 16),
182                        Flags("Options", ()), HPadding("Padding") ]
183
184        # we pack objects of header's fields to the dict
185        fields = dict(zip(self._ordered_fields, fields_list))
186        super(IP, self).__init__(fields, **kw)
187
188        # setting up passed fields
189        for field in kw:
190            self.__setattr__(field, kw[field])
191
192        # set __doc__ for fields - it's important if you want to get hints
193        # in some frontends. E.g. Umit Project provides one...
194        self._get_field('type_of_service').set_doc("The Type of Service provides \
195an indication of the abstract parameters of the quality of service desired. \
196See RFC 791 for more.")
197        self._get_field('flags').set_doc("Various Control Flags. See RFC 791 \
198for more.")
199        self._get_field('source_address').set_doc("The source address. \
200See RFC 791 for more.")
201        self._get_field('destination_address').set_doc("The destination address. \
202See RFC 791 for more.")
203        self._get_field('options').set_doc("The options may appear or not in \
204datagrams. See RFC 791 for more.")
205
206    def _is_valid(self, name):
207        """Check if attribute is allowed."""
208        return self._fields.has_key(name)
209
210    def _raw(self):
211        bit = 0
212        raw_value = 0
213
214        # Padding
215        self._get_field('_padding')._temp_value = \
216                                                self._get_field('options').bits
217
218        # IHL
219        # we store sum of option and padding bits in the _temp_value
220        # we can't overwrite _value because user might set his own value there
221        # later, generate_value() will return correct value
222        self._get_field('_ihl')._temp_value = \
223            self._get_field('options').bits + self._get_field('_padding').bits
224
225        # so we make a big number with bits of every fields of the protocol
226        for field in reversed(self._ordered_fields):
227            raw_value |= self._get_field(field).fillout() << bit
228            bit += self._get_field(field).bits
229
230        # Header Checksum
231        cksum_offset = bit - self.get_offset('_header_checksum') - \
232                       self._get_field('_header_checksum').bits
233        # check if user doesn't provide own values of bits
234        if (raw_value & (0xff << cksum_offset)) >> cksum_offset == 0:
235            # calculate and add checksum to the raw_value
236            cksum = net.in_cksum(raw_value)
237            raw_value |= cksum << cksum_offset
238
239        return bit, raw_value
240
241protocols = [ IP, ]
Note: See TracBrowser for help on using the browser.