Browse Source

init

master
Robin Thoni 9 years ago
commit
bb442b9171
7 changed files with 1290 additions and 0 deletions
  1. 192
    0
      dhcp_basic_packet.py
  2. 54
    0
      dhcp_client.py
  3. 414
    0
      dhcp_constants.py
  4. 368
    0
      dhcp_packet.py
  5. 85
    0
      type_hwmac.py
  6. 112
    0
      type_ipv4.py
  7. 65
    0
      type_strlist.py

+ 192
- 0
dhcp_basic_packet.py View File

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

+ 54
- 0
dhcp_client.py View File

@@ -0,0 +1,54 @@
1
+#! /usr/bin/env python
2
+from dhcp_packet import *
3
+import socket
4
+import random
5
+from type_hwmac import *
6
+import pcap
7
+import dpkt
8
+import binascii
9
+import time
10
+
11
+class DhcpClient:
12
+  def send_packet(self, mac, iface, xid):
13
+    dhcp = DhcpPacket()
14
+    dhcp.SetOption('op', [1]);
15
+    dhcp.SetOption('htype', [1]);
16
+    dhcp.SetOption('hlen', [6]);
17
+    dhcp.SetOption('xid', xid);
18
+    dhcp.SetOption('chaddr', hwmac(mac).list());
19
+    dhcp.SetOption('dhcp_message_type', [1]);
20
+    dhcp.SetOption('parameter_request_list', [12]);
21
+
22
+    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
23
+    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
24
+    s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
25
+    s.setsockopt(socket.SOL_SOCKET, 25, iface + '\0')
26
+    s.bind(('', 68))
27
+    s.sendto(dhcp.EncodePacket(), ('255.255.255.255', 67))
28
+    s.close()
29
+
30
+
31
+  def get_offer(self, mac, iface, timeout = 10):
32
+    pc = pcap.pcap(name=iface)
33
+    pc.setfilter('udp and udp src port 67 and udp dst port 68')
34
+    xid = [random.randrange(255), random.randrange(255),
35
+        random.randrange(255), random.randrange(255)]
36
+    self.send_packet(mac, iface, xid)
37
+    pc.setnonblock()
38
+    start = time.time()
39
+    while True:
40
+        try:
41
+            for pkt in pc.readpkts():
42
+                eth = dpkt.ethernet.Ethernet(pkt[1])
43
+                dh = DhcpPacket()
44
+                dh.DecodePacket(eth.data.data.data)
45
+                if (dh.GetOption('xid') == xid and
46
+                    dh.GetOption('op') == [2] and
47
+                    dh.GetOption('dhcp_message_type') == [2]):
48
+                    return dh
49
+        except:
50
+            pass
51
+        time.sleep(0.5)
52
+        if time.time() - start >= timeout:
53
+            return None
54
+

+ 414
- 0
dhcp_constants.py View File

@@ -0,0 +1,414 @@
1
+# pydhcplib
2
+# Copyright (C) 2008 Mathieu Ignacio -- mignacio@april.org
3
+#
4
+# This file is part of pydhcplib.
5
+# Pydhcplib is free software; you can redistribute it and/or modify
6
+# it under the terms of the GNU General Public License as published by
7
+# the Free Software Foundation; either version 3 of the License, or
8
+# (at your option) any later version.
9
+#
10
+# This program is distributed in the hope that it will be useful,
11
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+# GNU General Public License for more details.
14
+#
15
+# You should have received a copy of the GNU General Public License
16
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+
19
+MagicCookie = [99,130,83,99]
20
+PyDhcpLibVersion = '0.6'
21
+
22
+# DhcpBaseOptions = '{fieldname':[location,length]}
23
+DhcpFields = {'op':[0,1],
24
+                     'htype':[1,1],
25
+                     'hlen':[2,1],
26
+                     'hops':[3,1],
27
+                     'xid':[4,4],
28
+                     'secs':[8,2],
29
+                     'flags':[10,2],
30
+                     'ciaddr':[12,4],
31
+                     'yiaddr':[16,4],
32
+                     'siaddr':[20,4],
33
+                     'giaddr':[24,4],
34
+                     'chaddr':[28,16],
35
+                     'sname':[44,64],
36
+                     'file':[108,128]
37
+                     }
38
+DhcpFieldsName = { 'op' : { '0': 'ERROR_UNDEF', '1' : 'BOOTREQUEST' , '2' : 'BOOTREPLY'},
39
+                   'dhcp_message_type' : { '0': 'ERROR_UNDEF', '1': 'DHCP_DISCOVER', '2': 'DHCP_OFFER',
40
+                                           '3' : 'DHCP_REQUEST','4':'DHCP_DECLINE', '5': 'DHCP_ACK', '6': 'DHCP_NACK',
41
+                                           '7': 'DHCP_RELEASE', '8' : 'DHCP_INFORM' }
42
+                   }
43
+DhcpNames = { 'ERROR_UNDEF':0 , 'BOOTREQUEST':1 , 'BOOTREPLY':2 ,
44
+              'DHCP_DISCOVER':1 , 'DHCP_OFFER':2 , 'DHCP_REQUEST':3 ,
45
+              'DHCP_DECLINE':4 , 'DHCP_ACK':5 , 'DHCP_NACK':6 ,
46
+              'DHCP_RELEASE':7 , 'DHCP_INFORM':8 }
47
+
48
+DhcpFieldsTypes = {'op':"int",
49
+                     'htype':"int",
50
+                     'hlen':"int",
51
+                     'hops':"int",
52
+                     'xid':"int4",
53
+                     'secs':"int2",
54
+                     'flags':"int2",
55
+                     'ciaddr':"ipv4",
56
+                     'yiaddr':"ipv4",
57
+                     'siaddr':"ipv4",
58
+                     'giaddr':"ipv4",
59
+                     'chaddr':"hwmac",
60
+                     'sname':"str",
61
+                     'file':"str"
62
+                     }
63
+
64
+# DhcpOptions = 'option_name':option_code
65
+DhcpOptions = {'pad':0,
66
+
67
+               # Vendor Extension
68
+               'subnet_mask':1,'time_offset':2,
69
+               'router':3,'time_server':4,'name_server':5,
70
+               'domain_name_server':6,'log_server':7,
71
+               'cookie_server':8,'lpr_server':9,
72
+               'impress_server':10,'resource_location_server':11,
73
+               'host_name':12,'boot_file':13,'merit_dump_file':14,
74
+               'domain_name':15,'swap_server':16,'root_path':17,'extensions_path':18,
75
+
76
+               # IP layer parameters per host
77
+               'ip_forwarding':19,'nonlocal_source_rooting':20,
78
+               'policy_filter':21,'maximum_datagram_reassembly_size':22,
79
+               'default_ip_time-to-live':23,'path_mtu_aging_timeout':24,
80
+               'path_mtu_table':25,
81
+
82
+               # IP layer parameters per interface
83
+               'interface_mtu':26,'all_subnets_are_local':27,
84
+               'broadcast_address':28,'perform_mask_discovery':29,
85
+               'mask_supplier':30,'perform_router_discovery':31,
86
+               'routeur_solicitation_address':32,'static_route':33,
87
+
88
+               # link layer parameters per interface
89
+               'trailer_encapsulation':34,'arp_cache_timeout':35,
90
+               'ethernet_encapsulation':36,
91
+
92
+               # TCP parameters
93
+               'tcp_default_ttl':37,'tcp_keepalive_interval':38,
94
+               'tcp_keepalive_garbage':39,
95
+
96
+               # Applications and service parameters
97
+               'nis_domain':40,
98
+               'nis_servers':41,
99
+               'ntp_servers':42,
100
+               'vendor_specific':43,
101
+               'nbns':44,
102
+               'nbdd':45,'nb_node_type':46,
103
+               'nb_scope':47,'x_window_system_font_server':48,
104
+               'x_window_system_display_manager':49,
105
+
106
+               # DHCP extensions
107
+               'request_ip_address':50,
108
+               'ip_address_lease_time':51,
109
+               'overload':52,
110
+               'dhcp_message_type':53,
111
+               'server_identifier':54,
112
+               'parameter_request_list':55,
113
+               'message':56,
114
+               'maximum_dhcp_message_size':57,
115
+               'renewal_time_value':58,
116
+               'rebinding_time_value':59,
117
+               'vendor_class':60,
118
+               'client_identifier':61,
119
+
120
+               # Add from RFC 2132 
121
+               'netware_ip_domain_name':62,
122
+               'netware_ip_sub_options':63,
123
+               
124
+               'nis+_domain':64,
125
+               'nis+_servers':65,
126
+               'tftp_server_name':66,
127
+               'bootfile_name':67,
128
+               'mobile_ip_home_agent':68,
129
+               'smtp_servers':69,
130
+               'pop_servers':70,
131
+               'nntp_servers':71,
132
+               'default_www_server':72,
133
+               'default_finger_server':73,
134
+               'default_irc_server':74,
135
+               'streettalk_server':75,
136
+               'streettalk_directory_assistance_server':76,
137
+
138
+               'user_class':77,
139
+               'directory_agent':78,
140
+               'service_scope':79,
141
+               'rapid_commit':80,
142
+
143
+               'client_fqdn':81,
144
+               'relay_agent':82,
145
+               'internet_storage_name_service':83,
146
+               '84':84,
147
+               'nds_server':85,
148
+               'nds_tree_name':86,
149
+               'nds_context':87,
150
+               '88':88,
151
+               '89':89,
152
+               'authentication':90,
153
+               'client_last_transaction_time':91,
154
+               'associated_ip':92,
155
+               'client_system':93,
156
+               'client_ndi':94,
157
+               'ldap':95,
158
+               'unassigned':96,
159
+               'uuid_guid':97,
160
+               'open_group_user_auth':98,
161
+               'unassigned':99,
162
+               'unassigned':100,
163
+               'unassigned':101,
164
+               'unassigned':102,
165
+               'unassigned':103,
166
+               'unassigned':104,
167
+               'unassigned':105,
168
+               'unassigned':106,
169
+               'unassigned':107,
170
+               'unassigned':108,
171
+               'unassigned':109,
172
+               'unassigned':110,
173
+               'unassigned':111,
174
+               'netinfo_address':112,
175
+               'netinfo_tag':113,
176
+               'url':114,
177
+               'unassigned':115,
178
+               'auto_config':116,
179
+               'name_service_search':117,
180
+               'subnet_selection':118,
181
+               'domain_search':119,
182
+               'sip_servers':120,
183
+               'classless_static_route':121,
184
+               'cablelabs_client_configuration':122,
185
+               'geoconf':123,
186
+               'vendor_class':124,
187
+               'vendor_specific':125,
188
+               '126':126,'127':127,'128':128,'129':129,
189
+               '130':130,'131':131,'132':132,'133':133,
190
+               '134':134,'135':135,'136':136,'137':137,
191
+               '138':138,'139':139,'140':140,'141':141,
192
+               '142':142,'143':143,'144':144,'145':145,
193
+               '146':146,'147':147,'148':148,'149':149,
194
+               '150':150,'151':151,'152':152,'153':153,
195
+               '154':154,'155':155,'156':156,'157':157,
196
+               '158':158,'159':159,'160':160,'161':161,
197
+               '162':162,'163':163,'164':164,'165':165,
198
+               '166':166,'167':167,'168':168,'169':169,
199
+               '170':170,'171':171,'172':172,'173':173,
200
+               '174':174,'175':175,'176':176,'177':177,
201
+               '178':178,'179':179,'180':180,'181':181,
202
+               '182':182,'183':183,'184':184,'185':185,
203
+               '186':186,'187':187,'188':188,'189':189,
204
+               '190':190,'191':191,'192':192,'193':193,
205
+               '194':194,'195':195,'196':196,'197':197,
206
+               '198':198,'199':199,'200':200,'201':201,
207
+               '202':202,'203':203,'204':204,'205':205,
208
+               '206':206,'207':207,'208':208,'209':209,
209
+               '210':210,'211':211,'212':212,'213':213,
210
+               '214':214,'215':215,'216':216,'217':217,
211
+               '218':218,'219':219,'220':220,'221':221,
212
+               '222':222,'223':223,'224':224,'225':225,
213
+               '226':226,'227':227,'228':228,'229':229,
214
+               '230':230,'231':231,'232':232,'233':233,
215
+               '234':234,'235':235,'236':236,'237':237,
216
+               '238':238,'239':239,'240':240,'241':241,
217
+               '242':242,'243':243,'244':244,'245':245,
218
+               '246':246,'247':247,'248':248,'249':249,
219
+               '250':250,'251':251,'252':252,'253':253,
220
+               '254':254,'end':255
221
+
222
+               }
223
+
224
+# DhcpOptionsList : reverse of DhcpOptions
225
+DhcpOptionsList = ['pad',
226
+
227
+                   # Vendor Extension
228
+                   'subnet_mask','time_offset',
229
+                   'router','time_server','name_server',
230
+                   'domain_name_server','log_server',
231
+                   'cookie_server','lpr_server',
232
+                   'impress_server','resource_location_server',
233
+                   'host_name','boot_file','merit_dump_file',
234
+                   'domain_name','swap_server','root_path','extensions_path',
235
+                   
236
+                   # IP layer parameters per host
237
+                   'ip_forwarding','nonlocal_source_rooting',
238
+                   'policy_filter','maximum_datagram_reassembly_size',
239
+                   'default_ip_time-to-live','path_mtu_aging_timeout',
240
+                   'path_mtu_table',
241
+                   
242
+                   # IP layer parameters per interface
243
+                   'interface_mtu','all_subnets_are_local',
244
+                   'broadcast_address','perform_mask_discovery',
245
+                   'mask_supplier','perform_router_discovery',
246
+                   'routeur_solicitation_address','static_route',
247
+                   
248
+                   # link layer parameters per interface
249
+                   'trailer_encapsulation','arp_cache_timeout',
250
+                   'ethernet_encapsulation',
251
+                   
252
+                   # TCP parameters
253
+                   'tcp_default_ttl','tcp_keepalive_interval',
254
+                   'tcp_keepalive_garbage',
255
+                   
256
+                   # Applications and service parameters
257
+                   'nis_domain',
258
+                   'nis_servers',
259
+                   'ntp_servers',
260
+                   'vendor_specific','nbns',
261
+                   'nbdd','nd_node_type',
262
+                   'nb_scope','x_window_system_font_server',
263
+                   'x_window_system_display_manager',
264
+
265
+                   # DHCP extensions
266
+                   'request_ip_address',
267
+                   'ip_address_lease_time',
268
+                   'overload',
269
+                   'dhcp_message_type',
270
+                   'server_identifier',
271
+                   'parameter_request_list',
272
+                   'message',
273
+                   'maximum_dhcp_message_size',
274
+                   'renewal_time_value',
275
+                   'rebinding_time_value',
276
+                   'vendor_class',
277
+                   'client_identifier',
278
+                   
279
+
280
+                   # adds from RFC 2132,2242
281
+                   'netware_ip_domain_name',
282
+                   'netware_ip_sub_options',
283
+                   'nis+_domain',
284
+                   'nis+_servers',
285
+                   'tftp_server_name',
286
+                   'bootfile_name',
287
+                   'mobile_ip_home_agent',
288
+                   'smtp_servers',
289
+                   'pop_servers',
290
+                   'nntp_servers',
291
+                   'default_www_server',
292
+                   'default_finger_server',
293
+                   'default_irc_server',
294
+                   'streettalk_server',
295
+                   'streettalk_directory_assistance_server',
296
+                   'user_class','directory_agent','service_scope',
297
+
298
+                   # 80
299
+                   'rapid_commit','client_fqdn','relay_agent',
300
+                   'internet_storage_name_service',
301
+                   '84',
302
+                   'nds_server','nds_tree_name','nds_context',
303
+                   '88','89',
304
+
305
+                   #90
306
+                   'authentication',
307
+                   'client_last_transaction_time','associated_ip', #RFC 4388
308
+                   'client_system', 'client_ndi', #RFC 3679
309
+                   'ldap','unassigned','uuid_guid', #RFC 3679
310
+                   'open_group_user_auth', #RFC 2485
311
+
312
+                   # 99->115 RFC3679 
313
+                   'unassigned','unassigned','unassigned',
314
+                   'unassigned','unassigned','unassigned',
315
+                   'unassigned','unassigned','unassigned',
316
+                   'unassigned','unassigned','unassigned',
317
+                   'unassigned','netinfo_address','netinfo_tag',
318
+                   'url','unassigned',
319
+
320
+                   #116
321
+                   'auto_config','name_service_search','subnet_selection',
322
+                   'domain_search','sip_servers','classless_static_route',
323
+                   'cablelabs_client_configuration','geoconf',
324
+
325
+                   #124
326
+                   'vendor_class', 'vendor_specific',
327
+
328
+                   '126','127','128','129',
329
+                   '130','131','132','133','134','135','136','137','138','139',
330
+                   '140','141','142','143','144','145','146','147','148','149',
331
+                   '150','151','152','153','154','155','156','157','158','159',
332
+                   '160','161','162','163','164','165','166','167','168','169',
333
+                   '170','171','172','173','174','175','176','177','178','179',
334
+                   '180','181','182','183','184','185','186','187','188','189',
335
+                   '190','191','192','193','194','195','196','197','198','199',
336
+                   '200','201','202','203','204','205','206','207','208','209',
337
+                   '210','211','212','213','214','215','216','217','218','219',
338
+                   '220','221','222','223','224','225','226','227','228','229',
339
+                   '230','231','232','233','234','235','236','237','238','239',
340
+                   '240','241','242','243','244','245','246','247','248','249',
341
+                   '250','251','252','253','254',
342
+
343
+                   'end'
344
+                   ] 
345
+
346
+
347
+# See http://www.iana.org/assignments/bootp-dhcp-parameters
348
+# FIXME : verify all ipv4+ options, somes are 32 bits...
349
+
350
+DhcpOptionsTypes = {0:"none", 1:"ipv4", 2:"ipv4", 3:"ipv4+", 
351
+                    4:"ipv4+", 5:"ipv4+", 6:"ipv4+", 7:"ipv4+", 
352
+                    8:"ipv4+", 9:"ipv4+", 10:"ipv4+", 11:"ipv4+", 
353
+                    12:"string", 13:"16-bits", 14:"string", 15:"string", 
354
+                    16:"ipv4", 17:"string", 18:"string", 19:"bool", 
355
+                    20:"bool", 21:"ipv4+", 22:"16-bits", 23:"char", 
356
+                    24:"ipv4", 25:"16-bits", 26:"16-bits", 27:"bool", 
357
+                    28:"ipv4", 29:"bool", 30:"bool", 31:"bool", 
358
+                    32:"ipv4", 33:"ipv4+", 34:"bool", 35:"32-bits", 
359
+                    36:"bool", 37:"char", 38:"32-bits", 39:"bool", 
360
+                    40:"string", 41:"ipv4+", 42:"ipv4+", 43:"string", 
361
+                    44:"ipv4+", 45:"ipv4+", 46:"char", 47:"string", 
362
+                    48:"ipv4+", 49:"ipv4+", 50:"ipv4", 51:"32-bits", 
363
+                    52:"char", 53:"char", 54:"32-bits", 55:"char+", 
364
+                    56:"string", 57:"16-bits", 58:"32-bits", 59:"32-bits", 
365
+                    60:"string", 61:"identifier", 62:"string", 63:"RFC2242", 
366
+                    64:"string", 65:"ipv4+", 66:"string", 67:"string", 
367
+                    68:"ipv4", 69:"ipv4+", 70:"ipv4+", 71:"ipv4+",                     
368
+                    72:"ipv4+", 73:"ipv4+", 74:"ipv4+", 75:"ipv4+", 
369
+                    76:"ipv4+", 77:"RFC3004", 78:"RFC2610", 79:"RFC2610", 
370
+                    80:"null", 81:"string", 82:"RFC3046", 83:"RFC4174", 
371
+                    84:"Unassigned", 85:"ipv4+", 86:"RFC2241", 87:"RFC2241", 
372
+                    88:"Unassigned", 89:"Unassigned", 90:"RFC3118", 91:"RFC4388", 
373
+                    92:"ipv4+", 93:"Unassigned", 94:"Unassigned", 95:"Unassigned", 
374
+                    96:"Unassigned", 97:"Unassigned", 98:"string", 99:"Unassigned", 
375
+                    100:"Unassigned", 101:"Unassigned", 102:"Unassigned", 103:"Unassigned", 
376
+                    104:"Unassigned", 105:"Unassigned", 106:"Unassigned", 107:"Unassigned", 
377
+                    108:"Unassigned", 109:"Unassigned", 110:"Unassigned", 111:"Unassigned", 
378
+                    112:"Unassigned", 113:"Unassigned", 114:"Unassigned", 115:"Unassigned", 
379
+                    116:"char", 117:"RFC2937", 118:"ipv4", 119:"RFC3397", 
380
+                    120:"RFC3361",
381
+
382
+                    #TODO
383
+                    121:"Unassigned", 122:"Unassigned", 123:"Unassigned", 
384
+                    124:"Unassigned", 125:"Unassigned", 126:"Unassigned", 127:"Unassigned", 
385
+                    128:"Unassigned", 129:"Unassigned", 130:"Unassigned", 131:"Unassigned", 
386
+                    132:"Unassigned", 133:"Unassigned", 134:"Unassigned", 135:"Unassigned", 
387
+                    136:"Unassigned", 137:"Unassigned", 138:"Unassigned", 139:"Unassigned", 
388
+                    140:"Unassigned", 141:"Unassigned", 142:"Unassigned", 143:"Unassigned", 
389
+                    144:"Unassigned", 145:"Unassigned", 146:"Unassigned", 147:"Unassigned", 
390
+                    148:"Unassigned", 149:"Unassigned", 150:"Unassigned", 151:"Unassigned", 
391
+                    152:"Unassigned", 153:"Unassigned", 154:"Unassigned", 155:"Unassigned", 
392
+                    156:"Unassigned", 157:"Unassigned", 158:"Unassigned", 159:"Unassigned", 
393
+                    160:"Unassigned", 161:"Unassigned", 162:"Unassigned", 163:"Unassigned", 
394
+                    164:"Unassigned", 165:"Unassigned", 166:"Unassigned", 167:"Unassigned", 
395
+                    168:"Unassigned", 169:"Unassigned", 170:"Unassigned", 171:"Unassigned", 
396
+                    172:"Unassigned", 173:"Unassigned", 174:"Unassigned", 175:"Unassigned", 
397
+                    176:"Unassigned", 177:"Unassigned", 178:"Unassigned", 179:"Unassigned", 
398
+                    180:"Unassigned", 181:"Unassigned", 182:"Unassigned", 183:"Unassigned", 
399
+                    184:"Unassigned", 185:"Unassigned", 186:"Unassigned", 187:"Unassigned", 
400
+                    188:"Unassigned", 189:"Unassigned", 190:"Unassigned", 191:"Unassigned", 
401
+                    192:"Unassigned", 193:"Unassigned", 194:"Unassigned", 195:"Unassigned", 
402
+                    196:"Unassigned", 197:"Unassigned", 198:"Unassigned", 199:"Unassigned", 
403
+                    200:"Unassigned", 201:"Unassigned", 202:"Unassigned", 203:"Unassigned", 
404
+                    204:"Unassigned", 205:"Unassigned", 206:"Unassigned", 207:"Unassigned", 
405
+                    208:"Unassigned", 209:"Unassigned", 210:"Unassigned", 211:"Unassigned", 
406
+                    212:"Unassigned", 213:"Unassigned", 214:"Unassigned", 215:"Unassigned", 
407
+                    216:"Unassigned", 217:"Unassigned", 218:"Unassigned", 219:"Unassigned", 
408
+                    220:"Unassigned", 221:"Unassigned", 222:"Unassigned", 223:"Unassigned", 
409
+                    224:"Unassigned", 225:"Unassigned", 226:"Unassigned", 227:"Unassigned", 
410
+                    228:"Unassigned", 229:"Unassigned", 230:"Unassigned", 231:"Unassigned", 
411
+                    232:"Unassigned", 233:"Unassigned", 234:"Unassigned", 235:"Unassigned", 
412
+                    236:"Unassigned", 237:"Unassigned", 238:"Unassigned", 239:"Unassigned", 
413
+                    240:"Unassigned", 241:"Unassigned", 242:"Unassigned", 243:"Unassigned", 
414
+                    244:"Unassigned", 245:"Unassigned"}

+ 368
- 0
dhcp_packet.py View File

@@ -0,0 +1,368 @@
1
+# pydhcplib
2
+# Copyright (C) 2008 Mathieu Ignacio -- mignacio@april.org
3
+#
4
+# This file is part of pydhcplib.
5
+# Pydhcplib is free software; you can redistribute it and/or modify
6
+# it under the terms of the GNU General Public License as published by
7
+# the Free Software Foundation; either version 3 of the License, or
8
+# (at your option) any later version.
9
+#
10
+# This program is distributed in the hope that it will be useful,
11
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+# GNU General Public License for more details.
14
+#
15
+# You should have received a copy of the GNU General Public License
16
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+import operator
19
+from struct import unpack
20
+from struct import pack
21
+from dhcp_basic_packet import *
22
+from dhcp_constants import *
23
+from type_ipv4 import ipv4
24
+from type_strlist import strlist
25
+from type_hwmac import hwmac
26
+import sys
27
+
28
+class DhcpPacket(DhcpBasicPacket):
29
+    def str(self):
30
+        # Process headers : 
31
+        printable_data = "# Header fields\n"
32
+
33
+        op = self.packet_data[DhcpFields['op'][0]:DhcpFields['op'][0]+DhcpFields['op'][1]]
34
+        printable_data += "op : " + DhcpFieldsName['op'][str(op[0])] + "\n"
35
+
36
+        
37
+        for opt in  ['htype','hlen','hops','xid','secs','flags',
38
+                     'ciaddr','yiaddr','siaddr','giaddr','chaddr','sname','file'] :
39
+            begin = DhcpFields[opt][0]
40
+            end = DhcpFields[opt][0]+DhcpFields[opt][1]
41
+            data = self.packet_data[begin:end]
42
+            result = ''
43
+            if DhcpFieldsTypes[opt] == "int" : result = str(data[0])
44
+            elif DhcpFieldsTypes[opt] == "int2" : result = str(data[0]*256+data[1])
45
+            elif DhcpFieldsTypes[opt] == "int4" : result = str(ipv4(data).int())
46
+            elif DhcpFieldsTypes[opt] == "str" :
47
+                for each in data :
48
+                    if each != 0 : result += chr(each)
49
+                    else : break
50
+
51
+            elif DhcpFieldsTypes[opt] == "ipv4" : result = ipv4(data).str()
52
+            elif DhcpFieldsTypes[opt] == "hwmac" :
53
+                result = []
54
+                hexsym = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']
55
+                for iterator in range(6) :
56
+                    result += [str(hexsym[data[iterator]/16]+hexsym[data[iterator]%16])]
57
+
58
+                result = ':'.join(result)
59
+
60
+            printable_data += opt+" : "+result  + "\n"
61
+
62
+        # Process options : 
63
+        printable_data += "# Options fields\n"
64
+
65
+        for opt in self.options_data.keys():
66
+            data = self.options_data[opt]
67
+            result = ""
68
+            optnum  = DhcpOptions[opt]
69
+            if opt=='dhcp_message_type' : result = DhcpFieldsName['dhcp_message_type'][str(data[0])]
70
+            elif DhcpOptionsTypes[optnum] == "char" : result = str(data[0])
71
+            elif DhcpOptionsTypes[optnum] == "16-bits" : result = str(data[0]*256+data[0])
72
+            elif DhcpOptionsTypes[optnum] == "32-bits" : result = str(ipv4(data).int())
73
+            elif DhcpOptionsTypes[optnum] == "string" :
74
+                for each in data :
75
+                    if each != 0 : result += chr(each)
76
+                    else : break
77
+        
78
+            elif DhcpOptionsTypes[optnum] == "ipv4" : result = ipv4(data).str()
79
+            elif DhcpOptionsTypes[optnum] == "ipv4+" :
80
+                for i in range(0,len(data),4) :
81
+                    if len(data[i:i+4]) == 4 :
82
+                        result += ipv4(data[i:i+4]).str() + " - "
83
+            elif DhcpOptionsTypes[optnum] == "char+" :
84
+                if optnum == 55 : # parameter_request_list
85
+                    result = ','.join([DhcpOptionsList[each] for each in data])
86
+                else : result += str(data)
87
+                
88
+            printable_data += opt + " : " + result + "\n"
89
+
90
+        return printable_data
91
+
92
+    def AddLine(self,_string) :
93
+        (parameter,junk,value) = _string.partition(':')
94
+        parameter = parameter.strip()
95
+        # If value begin with a whitespace, remove it, leave others
96
+        if len(value)>0 and value[0] == ' ' : value = value[1:]
97
+        value = self._OptionsToBinary(parameter,value)
98
+        if value : self.SetOption(parameter,value)
99
+
100
+    def _OptionsToBinary(self,parameter,value) :
101
+        # Transform textual data into dhcp binary data
102
+
103
+        p = parameter.strip()
104
+        # 1- Search for header informations or specific parameter
105
+        if p == 'op' or p == 'htype' :
106
+            value = value.strip()
107
+            if value.isdigit() : return [int(value)]
108
+            try :
109
+                value = DhcpNames[value.strip()]
110
+                return [value]
111
+            except KeyError :
112
+                return [0]
113
+
114
+        elif p == 'hlen' or p == 'hops' :
115
+            try :
116
+                value = int(value)
117
+                return [value]
118
+            except ValueError :
119
+                return [0]
120
+
121
+        elif p == 'secs' or p == 'flags' :
122
+            try :
123
+                value = ipv4(int(value)).list()
124
+            except ValueError :
125
+                value = [0,0,0,0]
126
+
127
+            return value[2:]
128
+
129
+        elif p == 'xid' :
130
+            try :
131
+                value = ipv4(int(value)).list()
132
+            except ValueError :
133
+                value = [0,0,0,0]
134
+            return value
135
+
136
+        elif p == 'ciaddr' or p == 'yiaddr' or p == 'siaddr' or p == 'giaddr' :
137
+            try :
138
+                ip = ipv4(value).list()
139
+            except ValueError :
140
+                ip = [0,0,0,0]
141
+            return ip
142
+        
143
+        elif p == 'chaddr' :
144
+            try:
145
+                value = hwmac(value).list()+[0]*10
146
+            except ValueError,TypeError :
147
+                value = [0]*16
148
+            return value
149
+            
150
+        elif p == 'sname' :
151
+            return
152
+        elif p == 'file' :
153
+            return
154
+        elif p == 'parameter_request_list' :
155
+            value = value.strip().split(',')
156
+            tmp = []
157
+            for each in value:
158
+                if DhcpOptions.has_key(each) : tmp.append(DhcpOptions[each])
159
+            return tmp
160
+        elif  p=='dhcp_message_type' :
161
+            try :
162
+                return [DhcpNames[value]]
163
+            except KeyError:
164
+                return
165
+
166
+        # 2- Search for options
167
+        try : option_type = DhcpOptionsTypes[DhcpOptions[parameter]]
168
+        except KeyError : return False
169
+
170
+        if option_type == "ipv4" :
171
+            # this is a single ip address
172
+            try :
173
+                binary_value = map(int,value.split("."))
174
+            except ValueError : return False
175
+            
176
+        elif option_type == "ipv4+" :
177
+            # this is multiple ip address
178
+            iplist = value.split(",")
179
+            opt = []
180
+            for single in iplist :
181
+                opt += (ipv4(single).list())
182
+            binary_value = opt
183
+
184
+        elif option_type == "32-bits" :
185
+            # This is probably a number...
186
+            try :
187
+                digit = int(value)
188
+                binary_value = [digit>>24&0xFF,(digit>>16)&0xFF,(digit>>8)&0xFF,digit&0xFF]
189
+            except ValueError :
190
+                return False
191
+
192
+        elif option_type == "16-bits" :
193
+            try :
194
+                digit = int(value)
195
+                binary_value = [(digit>>8)&0xFF,digit&0xFF]
196
+            except ValueError : return False
197
+
198
+
199
+        elif option_type == "char" :
200
+            try :
201
+                digit = int(value)
202
+                binary_value = [digit&0xFF]
203
+            except ValueError : return False
204
+
205
+        elif option_type == "bool" :
206
+            if value=="False" or value=="false" or value==0 :
207
+                binary_value = [0]
208
+            else : binary_value = [1]
209
+            
210
+        elif option_type == "string" :
211
+            binary_value = strlist(value).list()
212
+
213
+        else :
214
+            binary_value = strlist(value).list()
215
+        
216
+        return binary_value
217
+    
218
+    # FIXME: This is called from IsDhcpSomethingPacket, but is this really
219
+    # needed?  Or maybe this testing should be done in
220
+    # DhcpBasicPacket.DecodePacket().
221
+
222
+    # Test Packet Type
223
+    def IsDhcpSomethingPacket(self,type):
224
+        if self.IsDhcpPacket() == False : return False
225
+        if self.IsOption("dhcp_message_type") == False : return False
226
+        if self.GetOption("dhcp_message_type") != type : return False
227
+        return True
228
+    
229
+    def IsDhcpDiscoverPacket(self):
230
+        return self.IsDhcpSomethingPacket([1])
231
+
232
+    def IsDhcpOfferPacket(self):
233
+        return self.IsDhcpSomethingPacket([2])
234
+
235
+    def IsDhcpRequestPacket(self):
236
+        return self.IsDhcpSomethingPacket([3])
237
+
238
+    def IsDhcpDeclinePacket(self):
239
+        return self.IsDhcpSomethingPacket([4])
240
+
241
+    def IsDhcpAckPacket(self):
242
+        return self.IsDhcpSomethingPacket([5])
243
+
244
+    def IsDhcpNackPacket(self):
245
+        return self.IsDhcpSomethingPacket([6])
246
+
247
+    def IsDhcpReleasePacket(self):
248
+        return self.IsDhcpSomethingPacket([7])
249
+
250
+    def IsDhcpInformPacket(self):
251
+        return self.IsDhcpSomethingPacket([8])
252
+
253
+
254
+    def GetMultipleOptions(self,options=()):
255
+        result = {}
256
+        for each in options:
257
+            result[each] = self.GetOption(each)
258
+        return result
259
+
260
+    def SetMultipleOptions(self,options={}):
261
+        for each in options.keys():
262
+            self.SetOption(each,options[each])
263
+
264
+
265
+
266
+
267
+
268
+
269
+    # Creating Response Packet
270
+
271
+    # Server-side functions
272
+    # From RFC 2132 page 28/29
273
+    def CreateDhcpOfferPacketFrom(self,src): # src = discover packet
274
+        self.SetOption("htype",src.GetOption("htype"))
275
+        self.SetOption("xid",src.GetOption("xid"))
276
+        self.SetOption("flags",src.GetOption("flags"))
277
+        self.SetOption("giaddr",src.GetOption("giaddr"))
278
+        self.SetOption("chaddr",src.GetOption("chaddr"))
279
+        self.SetOption("ip_address_lease_time",src.GetOption("ip_address_lease_time"))
280
+        self.TransformToDhcpOfferPacket()
281
+
282
+    def TransformToDhcpOfferPacket(self):
283
+        self.SetOption("dhcp_message_type",[2])
284
+        self.SetOption("op",[2])
285
+        self.SetOption("hlen",[6]) 
286
+
287
+        self.DeleteOption("secs")
288
+        self.DeleteOption("ciaddr")
289
+        self.DeleteOption("request_ip_address")
290
+        self.DeleteOption("parameter_request_list")
291
+        self.DeleteOption("client_identifier")
292
+        self.DeleteOption("maximum_message_size")
293
+
294
+
295
+
296
+
297
+
298
+    """ Dhcp ACK packet creation """
299
+    def CreateDhcpAckPacketFrom(self,src): # src = request or inform packet
300
+        self.SetOption("htype",src.GetOption("htype"))
301
+        self.SetOption("xid",src.GetOption("xid"))
302
+        self.SetOption("ciaddr",src.GetOption("ciaddr"))
303
+        self.SetOption("flags",src.GetOption("flags"))
304
+        self.SetOption("giaddr",src.GetOption("giaddr"))
305
+        self.SetOption("chaddr",src.GetOption("chaddr"))
306
+        self.SetOption("ip_address_lease_time_option",src.GetOption("ip_address_lease_time_option"))
307
+        self.TransformToDhcpAckPacket()
308
+
309
+    def TransformToDhcpAckPacket(self): # src = request or inform packet
310
+        self.SetOption("op",[2])
311
+        self.SetOption("hlen",[6]) 
312
+        self.SetOption("dhcp_message_type",[5])
313
+
314
+        self.DeleteOption("secs")
315
+        self.DeleteOption("request_ip_address")
316
+        self.DeleteOption("parameter_request_list")
317
+        self.DeleteOption("client_identifier")
318
+        self.DeleteOption("maximum_message_size")
319
+
320
+
321
+    """ Dhcp NACK packet creation """
322
+    def CreateDhcpNackPacketFrom(self,src): # src = request or inform packet
323
+        
324
+        self.SetOption("htype",src.GetOption("htype"))
325
+        self.SetOption("xid",src.GetOption("xid"))
326
+        self.SetOption("flags",src.GetOption("flags"))
327
+        self.SetOption("giaddr",src.GetOption("giaddr"))
328
+        self.SetOption("chaddr",src.GetOption("chaddr"))
329
+        self.TransformToDhcpNackPacket()
330
+
331
+    def TransformToDhcpNackPacket(self):
332
+        self.SetOption("op",[2])
333
+        self.SetOption("hlen",[6]) 
334
+        self.DeleteOption("secs")
335
+        self.DeleteOption("ciaddr")
336
+        self.DeleteOption("yiaddr")
337
+        self.DeleteOption("siaddr")
338
+        self.DeleteOption("sname")
339
+        self.DeleteOption("file")
340
+        self.DeleteOption("request_ip_address")
341
+        self.DeleteOption("ip_address_lease_time_option")
342
+        self.DeleteOption("parameter_request_list")
343
+        self.DeleteOption("client_identifier")
344
+        self.DeleteOption("maximum_message_size")
345
+        self.SetOption("dhcp_message_type",[6])
346
+
347
+
348
+
349
+
350
+
351
+
352
+
353
+    """ GetClientIdentifier """
354
+
355
+    def GetClientIdentifier(self) :
356
+        if self.IsOption("client_identifier") :
357
+            return self.GetOption("client_identifier")
358
+        return []
359
+
360
+    def GetGiaddr(self) :
361
+        return self.GetOption("giaddr")
362
+
363
+    def GetHardwareAddress(self) :
364
+        length = self.GetOption("hlen")[0]
365
+        full_hw = self.GetOption("chaddr")
366
+        if length!=[] and length<len(full_hw) : return full_hw[0:length]
367
+        return full_hw
368
+

+ 85
- 0
type_hwmac.py View File

@@ -0,0 +1,85 @@
1
+# pydhcplib
2
+# Copyright (C) 2008 Mathieu Ignacio -- mignacio@april.org
3
+#
4
+# This file is part of pydhcplib.
5
+# Pydhcplib is free software; you can redistribute it and/or modify
6
+# it under the terms of the GNU General Public License as published by
7
+# the Free Software Foundation; either version 3 of the License, or
8
+# (at your option) any later version.
9
+#
10
+# This program is distributed in the hope that it will be useful,
11
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+# GNU General Public License for more details.
14
+#
15
+# You should have received a copy of the GNU General Public License
16
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+
19
+from binascii import unhexlify,hexlify
20
+
21
+# Check and convert hardware/nic/mac address type
22
+class hwmac:
23
+    def __init__(self,value="00:00:00:00:00:00") :
24
+        self._hw_numlist = []
25
+        self._hw_string = ""
26
+        hw_type = type(value)
27
+        if hw_type == str :
28
+            value = value.strip()
29
+            self._hw_string = value
30
+            self._StringToNumlist(value)
31
+            self._CheckNumList()
32
+        elif hw_type == list :
33
+            self._hw_numlist = value
34
+            self._CheckNumList()
35
+            self._NumlistToString()
36
+        else : raise TypeError , 'hwmac init : Valid types are str and list'
37
+
38
+
39
+
40
+    # Check if _hw_numlist is valid and raise error if not.
41
+    def _CheckNumList(self) :
42
+        if len(self._hw_numlist) != 6 : raise ValueError , "hwmac : wrong list length."
43
+        for part in self._hw_numlist :
44
+            if type (part) != int : raise TypeError , "hwmac : each element of list must be int"
45
+            if part < 0 or part > 255 : raise ValueError , "hwmac : need numbers between 0 and 255."
46
+        return True
47
+
48
+
49
+    def _StringToNumlist(self,value):
50
+        self._hw_string = self._hw_string.replace("-",":").replace(".",":")
51
+        self._hw_string = self._hw_string.lower()
52
+
53
+        for twochar in self._hw_string.split(":"):
54
+            self._hw_numlist.append(ord(unhexlify(twochar)))
55
+            
56
+    # Convert NumList type ip to String type ip
57
+    def _NumlistToString(self) :
58
+        self._hw_string = ":".join(map(hexlify,map(chr,self._hw_numlist)))
59
+
60
+    # Convert String type ip to NumList type ip
61
+    # return ip string
62
+    def str(self) :
63
+        return self._hw_string
64
+
65
+    # return ip list (useful for DhcpPacket class)
66
+    def list(self) :
67
+        return self._hw_numlist+[0]*10
68
+
69
+    def __hash__(self) :
70
+        return self._hw_string.__hash__()
71
+
72
+    def __repr__(self) :
73
+        return self._hw_string
74
+
75
+    def __cmp__(self,other) :
76
+        if self._hw_string == other : return 0
77
+        return 1
78
+
79
+    def __nonzero__(self) :
80
+        if self._hw_string != "00:00:00:00:00:00" : return 1
81
+        return 0
82
+
83
+
84
+
85
+

+ 112
- 0
type_ipv4.py View File

@@ -0,0 +1,112 @@
1
+# pydhcplib
2
+# Copyright (C) 2008 Mathieu Ignacio -- mignacio@april.org
3
+#
4
+# This file is part of pydhcplib.
5
+# Pydhcplib is free software; you can redistribute it and/or modify
6
+# it under the terms of the GNU General Public License as published by
7
+# the Free Software Foundation; either version 3 of the License, or
8
+# (at your option) any later version.
9
+#
10
+# This program is distributed in the hope that it will be useful,
11
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+# GNU General Public License for more details.
14
+#
15
+# You should have received a copy of the GNU General Public License
16
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+
19
+# Check and convert ipv4 address type
20
+class ipv4:
21
+    def __init__(self,value="0.0.0.0") :
22
+        ip_type = type(value)
23
+        if ip_type == str :
24
+            if not self.CheckString(value) : raise ValueError, "ipv4 string argument is not an valid ip "
25
+            self._ip_string = value
26
+            self._StringToNumlist()
27
+            self._StringToLong()
28
+            self._NumlistToString()
29
+        elif ip_type == list :
30
+            if not self.CheckNumList(value) : raise ValueError, "ipv4 list argument is not an valid ip "
31
+            self._ip_numlist = value
32
+            self._NumlistToString()
33
+            self._StringToLong()
34
+        elif ip_type == int or ip_type == long:
35
+            self._ip_long = value
36
+            self._LongToNumlist()
37
+            self._NumlistToString()
38
+        elif ip_type == bool :
39
+            self._ip_long = 0
40
+            self._LongToNumlist()
41
+            self._NumlistToString()
42
+            
43
+        else : raise TypeError , 'ipv4 init : Valid types are str, list, int or long'
44
+
45
+    # Convert Long type ip to numlist ip
46
+    def _LongToNumlist(self) :
47
+        self._ip_numlist = [self._ip_long >> 24 & 0xFF]
48
+        self._ip_numlist.append(self._ip_long >> 16 & 0xFF)
49
+        self._ip_numlist.append(self._ip_long >> 8 & 0xFF)
50
+        self._ip_numlist.append(self._ip_long & 0xFF)
51
+        if not self.CheckNumList(self._ip_numlist) : raise ValueError, "ipv4 list argument is not an valid ip "
52
+    # Convert String type ip to Long type ip
53
+    def _StringToLong(self) :
54
+        ip_numlist = map(int,self._ip_string.split('.'))
55
+        self._ip_long = ip_numlist[3] + ip_numlist[2]*256 + ip_numlist[1]*256*256 + ip_numlist[0]*256*256*256
56
+        if not self.CheckNumList(self._ip_numlist) : raise ValueError, "ipv4 list argument is not an valid ip "
57
+    # Convert NumList type ip to String type ip
58
+    def _NumlistToString(self) :
59
+        self._ip_string = ".".join(map(str,self._ip_numlist))
60
+        if not self.CheckNumList(self._ip_numlist) : raise ValueError, "ipv4 list argument is not an valid ip "
61
+    # Convert String type ip to NumList type ip
62
+    def _StringToNumlist(self) :
63
+        self._ip_numlist = map(int,self._ip_string.split('.'))
64
+        if not self.CheckNumList(self._ip_numlist) : raise ValueError, "ipv4 list argument is not an valid ip "
65
+
66
+    """ Public methods """
67
+    # Check if _ip_numlist is valid and raise error if not.
68
+    # self._ip_numlist
69
+    def CheckNumList(self,value) :
70
+        if len(value) != 4 : return False
71
+        for part in value :
72
+            if part < 0 or part > 255 : return False
73
+        return True
74
+
75
+    # Check if _ip_numlist is valid and raise error if not.
76
+    def CheckString(self,value) :
77
+        tmp = value.strip().split('.')
78
+        if len(tmp) != 4 :  return False
79
+        for each in tmp : 
80
+            if not each.isdigit() : return False
81
+        return True
82
+    
83
+    # return ip string
84
+    def str(self) :
85
+        return self._ip_string
86
+
87
+    # return ip list (useful for DhcpPacket class)
88
+    def list(self) :
89
+        return self._ip_numlist
90
+
91
+    # return Long ip type (useful for SQL ip address backend)
92
+    def int(self) :
93
+        return self._ip_long
94
+
95
+
96
+    """ Useful function for native python operations """
97
+
98
+    def __hash__(self) :
99
+        return self._ip_long.__hash__()
100
+
101
+    def __repr__(self) :
102
+        return self._ip_string
103
+
104
+    def __cmp__(self,other) :
105
+        return cmp(self._ip_long, other._ip_long);
106
+
107
+    def __nonzero__(self) :
108
+        if self._ip_long != 0 : return 1
109
+        return 0
110
+
111
+
112
+

+ 65
- 0
type_strlist.py View File

@@ -0,0 +1,65 @@
1
+# pydhcplib
2
+# Copyright (C) 2008 Mathieu Ignacio -- mignacio@april.org
3
+#
4
+# This file is part of pydhcplib.
5
+# Pydhcplib is free software; you can redistribute it and/or modify
6
+# it under the terms of the GNU General Public License as published by
7
+# the Free Software Foundation; either version 3 of the License, or
8
+# (at your option) any later version.
9
+#
10
+# This program is distributed in the hope that it will be useful,
11
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+# GNU General Public License for more details.
14
+#
15
+# You should have received a copy of the GNU General Public License
16
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+class strlist :
19
+    def __init__(self,data="") :
20
+        str_type = type(data)
21
+        self._str = ""
22
+        self._list = []
23
+        
24
+        if str_type == str :
25
+            self._str = data
26
+            for each in range(len(self._str)) :
27
+                self._list.append(ord(self._str[each]))
28
+        elif str_type == list :
29
+            self._list = data
30
+            self._str = "".join(map(chr,self._list))
31
+        else : raise TypeError , 'strlist init : Valid types are str and  list of int'
32
+
33
+    # return string
34
+    def str(self) :
35
+        return self._str
36
+
37
+    # return list (useful for DhcpPacket class)
38
+    def list(self) :
39
+        return self._list
40
+
41
+    # return int
42
+    # FIXME
43
+    def int(self) :
44
+        return 0
45
+
46
+
47
+
48
+    """ Useful function for native python operations """
49
+
50
+    def __hash__(self) :
51
+        return self._str.__hash__()
52
+
53
+    def __repr__(self) :
54
+        return self._str
55
+
56
+    def __nonzero__(self) :
57
+        if self._str != "" : return 1
58
+        return 0
59
+
60
+    def __cmp__(self,other) :
61
+        if self._str == other : return 0
62
+        return 1
63
+		    
64
+
65
+

Loading…
Cancel
Save