-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdhcp.tbs
371 lines (290 loc) · 9.21 KB
/
dhcp.tbs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
' Po chamsku zerzniete z Tibba. Po to tu jest.
const DHCP_MAX_RETRIES=3 'This is how many times we will try to do DHCP
const DHCP_RANOM_RETRY_DELAY = 20
include "global.tbh"
enum dhcp_phases
DHCP_PHASE_DISCOVER,
DHCP_PHASE_REQUEST
end enum
dim dhcp_phase as dhcp_phases
dim dhcp_server_ip as string(16)
declare sub send_dhcp(byref obtained_ip as string)
declare function proc_dhcp_reply(byref obtained_ip as string(16), byref obtained_gateway as string(16),
byref obtained_netmask as string(16), byref obtained_lease_time as dword) as ok_ng
'=============================================================
public function dhcp_obtain(byref obtained_ip as string, byref obtained_gateway as string,
byref obtained_netmask as string, byref obtained_lease_time as dword, device_name as string(32)) as ok_ng
dim retry_ctr as byte 'we need to limit how much time we will spend here
dim wait_period as word
'setup the socket we need for DHCP communications
if net.ip = "1.0.0.1" then net.ip = "0.0.0.0"
sock.num=SOCK_DHCP
'arrange buffer space
sock.rxbuffrq(5)
sock.txbuffrq(5)
sys.buffalloc
'setup the socket itself
sock.protocol=0
sock.targetport=67
sock.outport=68
sock.targetbcast=YES
sock.acceptbcast=YES
sock.connectiontout=600
sock.inconmode=PL_SOCK_INCONMODE_ANY_IP_ANY_PORT
sock.reconmode=PL_SOCK_RECONMODE_3
sock.gendataarrivalevent=NO
sock.num=SOCK_DHCP
sock.connect
wait_period = sys.timercount
for retry_ctr=1 to DHCP_MAX_RETRIES
while wait_period > sys.timercount
wend
dhcp_phase=DHCP_PHASE_DISCOVER
send_dhcp(obtained_ip)
if proc_dhcp_reply(obtained_ip,obtained_gateway,obtained_netmask,obtained_lease_time)=NG then
goto try_again
end if
dhcp_phase=DHCP_PHASE_REQUEST
send_dhcp(obtained_ip)
if proc_dhcp_reply(obtained_ip,obtained_gateway,obtained_netmask,obtained_lease_time)=NG then
goto try_again
end if
'DHCP interaction completed successfully
dhcp_obtain=OK
goto release_buffer
try_again:
'here when DHCP failed
wait_period = asc(random(1))/DHCP_RANOM_RETRY_DELAY
if sys.timercount < (65535 - wait_period) then wait_period = sys.timercount + wait_period
next retry_ctr
obtained_lease_time = 180 'DHCP failed, try again in 3 mins
dhcp_obtain=NG
release_buffer:
'close the socket, deallocate space
sock.inconmode=PL_SOCK_INCONMODE_NONE
sock.discard
while sock.statesimple<>PL_SSTS_CLOSED
wend
sock.gendataarrivalevent=YES
sock.rxbuffrq(0)
sock.txbuffrq(0)
sys.buffalloc
end function
'=============================================================
public sub send_dhcp(byref obtained_ip as string)
dim s as string
dim x as byte
'1.1.6.0- opcode=rq, hware type= Ethernet, hardware addr len= 6, hop count=0
s=ddval("1.1.6.0")
'transaction ID- last 4 bytes of MAC address
s=s+right(ddval(net.mac),4)
'100.100- number of seconds
'128.0- set broadcast flag
s=s+ddval("100.100.128.0")
select case dhcp_phase
case DHCP_PHASE_DISCOVER:
'for DISCOVER message all fields until MAC-address are unused
s=s+ddval(net.ip)+ddval(net.ip)
s=s+strgen(8,chr(0))
case DHCP_PHASE_REQUEST:
'our IP address and the field for server-suggested IP- fill with zeroes to avoid problems
s=s+strgen(8,chr(0))
'supply IP-address of the server (we obtained from the OFFER message)- this is required
s=s+ddval(dhcp_server_ip)
'no need to set gateway IP
s=s+strgen(4,chr(0))
case else:
end select
s=s+ddval(net.mac) 'client MAC
sock.setdata(s)
'now we just need 204 empty bytes
s=strgen(202,chr(0))
sock.setdata(s)
'continue...
s=ddval("99.130.83.99") 'magic cookie
select case dhcp_phase
case DHCP_PHASE_DISCOVER:
'53.1.1- set message type to DISCOVER
s=s+ddval("53.1.1")
'116.1.1 - DHCP Auto Configuration
s=s+ddval("116.1.1")
'61.7 - Client Identifier
s=s+ddval("61.7.1."+net.mac)
'50.4- suggest our current IP only if IP was assigned already
if obtained_ip <> "" then
s=s+ddval("50.4."+obtained_ip) 'suggest our current IP
else
s=s+ddval("50.4."+net.ip)
end if
'51.4.255.255.255.255- suggest maximum lease time
s=s+ddval("51.4.255.255.255.255")
'55.2.1.3- provide a list of parameters we need
s=s+ddval("55.2.1.3")
case DHCP_PHASE_REQUEST:
'53.1.3- set message type to REQUEST
'54.4- specify the DHCP server we are addressing
s=s+ddval("53.1.3.54.4")
s=s+ddval(dhcp_server_ip) 'DHCP server we are addressing
'50.4- quote the IP-address being suggested by the DHCP server
s=s+ddval("50.4")
s=s+ddval(obtained_ip) 'This is the IP-address that the DHCP server has suggested
'55.2.1.3- provide a list of parameters we need
s=s+ddval("55.2.1.3")
case else:
end select
'add host name option if our owner name or device name is set
'if device_name<>"" then
' s=s+chr(12)+chr(len(device_name))+device_name
'end if
'end of all options and send!
'We pad the packet for compatibility to certain DHCP server that conforms to BOOTP packet size
sock.setdata(s+CHR(255)+strgen(319-len(s),CHR(0)))
sock.send
end sub
'=============================================================
public function proc_dhcp_reply(byref obtained_ip as string(16), byref obtained_gateway as string(16),
byref obtained_netmask as string(16), byref obtained_lease_time as dword) as ok_ng
dim s as string
dim s2 as string(32)
dim x,f as byte
dim message_type as byte
dim t1_found as no_yes
dim w as word
'first, wait for the DHCP packet to arrive
w=sys.timercount
while sock.rxlen=0
if sys.timercount-w>10 then
proc_dhcp_reply=NG 'timeout while waiting for reply!
exit function
end if
wend
sock.nextpacket
s=sock.getdata(236) 'read all the data up to a magic cookie
'verify opcode: must be "reply" (2)
'verify hardware type: must be "ethernet" (1)
'verify hardware address length: must be (6)
if ddstr(mid(s,1,3))<>"2.1.6" then
proc_dhcp_reply=NG
exit function
end if
'verify transaction ID (must match our last 4 digits of MAC address)
if ddstr(mid(s,5,4))<>ddstr(right(ddval(net.mac),4)) then
proc_dhcp_reply=NG
exit function
end if
'branch according to the phase
select case dhcp_phase
case DHCP_PHASE_DISCOVER:
'make sure IP-address being offered is valid
'first number cannot exceed 223
if asc(mid(s,17,1))>223 then
proc_dhcp_reply=NG
exit function
end if
'last number cannot be 0 or 255
x=asc(mid(s,20,1))
if x=0 or x=255 then
proc_dhcp_reply=NG
exit function
end if
'IP-address being offered is correct- extract it!
obtained_ip=ddstr(mid(s,17,4))
case DHCP_PHASE_REQUEST:
'Make sure that the IP-address the DHCP supplied now (ACK) is the same as in OFFER message
'(or the same we've been using if we are extending the lease)
if obtained_ip<>ddstr(mid(s,17,4)) then
proc_dhcp_reply=NG
exit function
end if
case else:
end select
'This part is common for all types of replies received from the DHCP server.
'Extract and verify our own MAC (must be returned by the server)
if ddstr(mid(s,29,6))<>net.mac then
proc_dhcp_reply=NG
exit function
end if
'Read magic cookie and options
s=sock.getdata(255)
'Check magic cookie
if ddstr(mid(s,1,4))<>"99.130.83.99" then
proc_dhcp_reply=NG
exit function
end if
obtained_lease_time=4294967295 'first, assume max lease time
t1_found=NO
'Look through options and extract the ones we need. Only one option-
'message type is REALLY a mast
for f=5 to len(s)
select case asc(mid(s,f,1))
case 255: 'reached the end of all options
goto exit_options
case 0: 'this is a "padding"- just skip it
goto next_option
case 53: 'OK, we HAD to have this option (message type)- make sure its length is 1
if asc(mid(s,f+1,1))<>1 then
proc_dhcp_reply=NG
exit function
end if
'now get the message type and see if it is correct
message_type=asc(mid(s,f+2,1))
select case dhcp_phase
case DHCP_PHASE_DISCOVER:
if message_type<>2 then
proc_dhcp_reply=NG
exit function
end if
case DHCP_PHASE_REQUEST:
if message_type<>5 then
proc_dhcp_reply=NG
exit function
end if
case else:
end select
f=f+2
case 1: 'netmask option!- make sure its length is 5
if asc(mid(s,f+1,1))<>4 then
proc_dhcp_reply=NG
exit function
end if
obtained_netmask=ddstr(mid(s,f+2,4))
f=f+5
case 3: 'default gateway IP option!- there can be N gateways, length must be 4*n
x=asc(mid(s,f+1,1))
if x<4 or x-(x/4)*4<>0 then
proc_dhcp_reply=NG
exit function
end if
obtained_gateway=ddstr(mid(s,f+2,4))
f=f+1+x
case 51: 'offered lease time
'only process this if no T1 option was encountered yet
if t1_found=NO then
goto get_lease
end if
f=f+5
case 59: 'T1- renewal time
t1_found=YES
get_lease: if asc(mid(s,f+1,1))<>4 then
proc_dhcp_reply=NG
exit function
end if
'renewal time is a 4-byte value (in seconds)
obtained_lease_time= asc(mid(s,f+2,1))*16777216+asc(mid(s,f+3,1))*65536+asc(mid(s,f+4,1))*256+asc(mid(s,f+5,1))
f=f+5
case 54: 'server identifier option
if asc(mid(s,f+1,1))<>4 then
proc_dhcp_reply=NG
exit function
end if
dhcp_server_ip=ddstr(mid(s,f+2,4))
f=f+5
case else: 'some other option: just skip it
x=asc(mid(s,f+1,1))
f=f+x+1
end select
next_option:
next f
exit_options:
proc_dhcp_reply=OK
end function