source: branches/wsgi/packages/sipb-xen-python-pydhcplib/pydhcplib/dhcp_basic_packet.py @ 2477

Last change on this file since 2477 was 361, checked in by broder, 17 years ago

Splitting pydhcplib off into its own package

Hold onto your hats, folks - this could get messy

File size: 6.7 KB
Line 
1# Anemon Dhcp
2# Copyright (C) 2005 Mathieu Ignacio -- mignacio@april.org
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program; if not, write to the Free Software
16# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
17
18import operator
19from struct import unpack
20from struct import pack
21from dhcp_constants import *
22
23# DhcpPacket : base class to encode/decode dhcp packets.
24
25
26class DhcpBasicPacket:
27    def __init__(self):
28        self.packet_data = [0]*240
29        self.options_data = {}
30        self.packet_data[236:240] = MagicCookie
31
32    def IsDhcpPacket(self):
33        if self.packet_data[236:240] != MagicCookie : return False
34        return True
35
36    # Check if variable is a list with int between 0 and 255
37    def CheckType(self,variable):
38        if type(variable) == list :
39            for each in variable :
40                if (type(each) != int)  or (each < 0) or (each > 255) :
41                    return False
42            return True
43        else : return False
44       
45
46    def DeleteOption(self,name):
47        # if name is a standard dhcp field
48        # Set field to 0
49        if DhcpFields.has_key(name) :
50            begin = DhcpFields[name][0]
51            end = DhcpFields[name][0]+DhcpFields[name][1]
52            self.packet_data[begin:end] = [0]*DhcpFields[name][1]
53            return True
54
55        # if name is a dhcp option
56        # delete option from self.option_data
57        elif self.options_data.has_key(name) :
58            # forget how to remove a key... try delete
59            self.options_data.__delitem__(name)
60            return True
61
62        return False
63
64    def GetOption(self,name):
65        if DhcpFields.has_key(name) :
66            option_info = DhcpFields[name]
67            return self.packet_data[option_info[0]:option_info[0]+option_info[1]]
68
69        elif self.options_data.has_key(name) :
70            return self.options_data[name]
71
72        return []
73       
74
75    def SetOption(self,name,value):
76
77        # Basic vlue checking :
78        # has value list a correct length
79       
80        # if name is a standard dhcp field
81        if DhcpFields.has_key(name) :
82            if len(value) != DhcpFields[name][1] :
83                print "Error, bad option length (a): ", name
84                return False
85            begin = DhcpFields[name][0]
86            end = DhcpFields[name][0]+DhcpFields[name][1]
87            self.packet_data[begin:end] = value
88            return True
89
90        # if name is a dhcp option
91        elif DhcpOptions.has_key(name) :
92
93            # fields_specs : {'option_code',fixed_length,minimum_length,multiple}
94            # if fixed_length == 0 : minimum_length and multiple apply
95            # else : forget minimum_length and multiple
96            # multiple : length MUST be a multiple of 'multiple'
97            fields_specs = { "ipv4":[4,0,1], "ipv4+":[0,4,4],
98                             "string":[0,0,1], "bool":[1,0,1],
99                             "char":[1,0,1], "16-bits":[2,0,1],
100                             "32-bits":[4,0,1], "identifier":[0,2,1]}
101           
102            specs = fields_specs[DhcpOptionsTypes[DhcpOptions[name]]]
103            length = len(value)
104            if (specs[0]!=0 and specs==length) or (specs[1]<=length and length%specs[2]==0):
105                self.options_data[name] = value
106                return True
107            else :
108                return False
109
110        print "Error, unknown option : ", name, value
111        return False
112
113
114
115    def IsOption(self,name):
116        if self.options_data.has_key(name) : return True
117        elif DhcpFields.has_key(name) : return True
118        else : return False
119
120
121    # Encode Packet and return it
122    def EncodePacket(self):
123        options = []
124       
125       
126        for each in self.options_data.keys() :
127            options.append(DhcpOptions[each])
128            options.append(len(self.options_data[each]))
129            options += self.options_data[each]
130
131        packet = self.packet_data[:240] + options
132        packet.append(255) # add end option
133        pack_fmt = str(len(packet))+"c"
134
135        packet = map(chr,packet)
136       
137        return pack(pack_fmt,*packet)
138
139
140    # Insert packet in the object
141    def DecodePacket(self,data,debug=False):
142        self.packet_data = []
143        self.options_data = {}
144
145        if (not data) : return False
146        # we transform all data to int list
147        unpack_fmt = str(len(data)) + "c"
148        for i in unpack(unpack_fmt,data):
149            self.packet_data.append(ord(i))
150        if ( debug ) : print "Packet length : ",len(self.packet_data)
151
152
153        # Some servers or clients don't place magic cookie immediately
154        # after headers and begin options fields only after magic.
155        # These 4 lines search magic cookie and begin iterator after.
156        iterator = 236
157        end_iterator = len(self.packet_data)
158        while ( self.packet_data[iterator:iterator+4] != MagicCookie and iterator < end_iterator) :
159            iterator += 1
160        iterator += 4
161       
162        # parse extended options
163        if ( debug ) : print "Debug : ", self.packet_data[iterator:-1]
164
165
166        while iterator < end_iterator :
167            if ( debug ) :
168                print "Debug Option : ", iterator , self.packet_data[iterator]," : ",DhcpOptionsList[self.packet_data[iterator]]
169            if self.packet_data[iterator] == 0 : # pad option
170                opt_first = iterator+1
171                iterator += 1
172
173            elif self.packet_data[iterator] == 255 :
174                self.packet_data = self.packet_data[:240] # base packet length without magic cookie
175                return
176               
177            elif DhcpOptionsTypes.has_key(self.packet_data[iterator]) and self.packet_data[iterator]!= 255:
178                opt_len = self.packet_data[iterator+1]
179                opt_first = iterator+1
180                self.options_data[DhcpOptionsList[self.packet_data[iterator]]] = self.packet_data[opt_first+1:opt_len+opt_first+1]
181                iterator += self.packet_data[opt_first] + 2
182            else :
183                opt_first = iterator+1
184                iterator += self.packet_data[opt_first] + 2
185
186        # cut packet_data to remove options
187       
188        self.packet_data = self.packet_data[:240] # base packet length with magic cookie
Note: See TracBrowser for help on using the repository browser.