Subversion Repositories Kolibri OS

Rev

Rev 1481 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1164 hidnplayr 1
; Zero-config
2
; v 1.4
3
;
4
; DHCP code is based on that by Mike Hibbet (DHCP client for menuetos)
5
;
6
; Written by HidnPlayr & Derpenguin
7
 
8
use32
9
	       org    0x0
10
 
11
	       db     'MENUET01'	    ; 8 byte id
12
	       dd     0x01		    ; header version
13
	       dd     START		    ; start of code
14
	       dd     IM_END		    ; size of image
1192 hidnplayr 15
	       dd     (I_END+0x100)	    ; memory for app
16
	       dd     (I_END+0x100)	    ; esp
17
	       dd     0x0 , path	    ; I_Param , I_Icon
1164 hidnplayr 18
 
19
; CONFIGURATION
20
 
21
 
22
TIMEOUT 	    equ 60		    ; in seconds
23
BUFFER		    equ 1024		    ; in bytes
24
__DEBUG__	    equ 1		    ; enable/disable
25
__DEBUG_LEVEL__     equ 1		    ; 1 = all, 2 = errors
26
 
27
; CONFIGURATION FOR LINK-LOCAL
28
 
29
PROBE_WAIT	    equ 1		    ; second  (initial random delay)
30
PROBE_MIN	    equ 1		    ; second  (minimum delay till repeated probe)
31
PROBE_MAX	    equ 2		    ; seconds (maximum delay till repeated probe)
32
PROBE_NUM	    equ 3		    ;         (number of probe packets)
33
 
34
ANNOUNCE_NUM	    equ 2		    ;         (number of announcement packets)
35
ANNOUNCE_INTERVAL   equ 2		    ; seconds (time between announcement packets)
36
ANNOUNCE_WAIT	    equ 2		    ; seconds (delay before announcing)
37
 
38
MAX_CONFLICTS	    equ 10		    ;         (max conflicts before rate limiting)
39
 
40
RATE_LIMIT_INTERVAL equ 60		    ; seconds (delay between successive attempts)
41
 
42
DEFEND_INTERVAL     equ 10		    ; seconds (min. wait between defensive ARPs)
43
 
44
 
1170 hidnplayr 45
AF_INET4	equ 2  ;;;;;
46
IP_PROTO_UDP	equ 17
1164 hidnplayr 47
 
48
 
49
 
1166 hidnplayr 50
include '../proc32.inc'
51
include '../macros.inc'
52
include '../debug-fdo.inc'
1164 hidnplayr 53
include 'dhcp.inc'
54
include 'dll.inc'
55
 
56
 
57
Ip2dword:
58
    push    edx
59
 
60
    ; This code validates if the query is an IP containing 4 numbers and 3 dots
61
 
62
    xor     al, al	      ; make al (dot count) zero
63
 
64
   @@:
65
    cmp     byte[edx],'0'     ; check if this byte is a number, if not jump to no_IP
66
    jl	    no_IP	      ;
67
    cmp     byte[edx],'9'     ;
68
    jg	    no_IP	      ;
69
 
70
    inc     edx 	      ; the byte was a number, so lets check the next byte
71
 
72
    cmp     byte[edx],0       ; is this byte zero? (have we reached end of query?)
73
    jz	    @f		      ; jump to next @@ then
74
    cmp     byte[edx],':'
75
    jz	    @f
76
 
77
    cmp     byte[edx],'.'     ; is this byte a dot?
78
    jne     @r		      ; if not, jump to previous @@
79
 
80
    inc     al		      ; the byte was a dot so increment al(dot count)
81
    inc     edx 	      ; next byte
82
    jmp     @r		      ; lets check for numbers again (jump to previous @@)
83
 
84
   @@:			      ; we reach this when end of query reached
85
    cmp     al,3	      ; check if there where 3 dots
86
    jnz     no_IP	      ; if not, jump to no_IP
87
 
88
    ; The following code will convert this IP into a dword and output it in eax
89
    ; If there is also a port number specified, this will be returned in ebx, otherwise ebx is -1
90
 
91
    pop     esi 	      ; edx (query address) was pushed onto stack and is now popped in esi
92
 
93
    xor     edx, edx	      ; result
94
    xor     eax, eax	      ; current character
95
    xor     ebx, ebx	      ; current byte
96
 
97
.outer_loop:
98
    shl     edx, 8
99
    add     edx, ebx
100
    xor     ebx, ebx
101
.inner_loop:
102
    lodsb
103
    test    eax, eax
104
    jz	    .finish
105
    cmp     al, '.'
106
    jz	    .outer_loop
107
    sub     eax, '0'
108
    imul    ebx, 10
109
    add     ebx, eax
110
    jmp     .inner_loop
111
.finish:
112
    shl     edx, 8
113
    add     edx, ebx
114
 
115
    bswap   edx 	      ; we want little endian order
116
 
117
    ret
118
 
119
no_IP:
120
    pop     edx
121
    xor     edx, edx
122
 
123
    ret
124
 
125
 
126
 
127
 
128
 
129
 
130
START:					    ; start of execution
131
 
1514 hidnplayr 132
	mcall	40, 1 shl 7 ; network event
1164 hidnplayr 133
 
1514 hidnplayr 134
	DEBUGF	1,">Zero-config service:\n"
1164 hidnplayr 135
 
1514 hidnplayr 136
	mcall	75, 1337 shl 16 + 4
1164 hidnplayr 137
 
1514 hidnplayr 138
	cmp	eax, -1
139
	je	close
1164 hidnplayr 140
 
1514 hidnplayr 141
	mov	word[MAC], bx
142
	mov	dword[MAC+2], eax
1164 hidnplayr 143
 
1514 hidnplayr 144
	DEBUGF	1,"->MAC: %x-%x-%x-%x-%x-%x\n",[MAC]:2,[MAC+1]:2,[MAC+2]:2,[MAC+3]:2,[MAC+4]:2,[MAC+5]:2
1164 hidnplayr 145
 
1514 hidnplayr 146
	cld
147
	mov	edi, path      ; Calculate the length of zero-terminated string
148
	xor	al , al
149
	mov	ecx, 1024
150
	repnz	scas byte[es:edi]
151
	dec	edi
1174 hidnplayr 152
 
1514 hidnplayr 153
	mov	esi, filename
154
	movsd
155
	movsb
1174 hidnplayr 156
 
1514 hidnplayr 157
	DEBUGF	1,"->path to ini: %s\n", path
1164 hidnplayr 158
 
1514 hidnplayr 159
	mcall	    68,11
1164 hidnplayr 160
 
1514 hidnplayr 161
	stdcall dll.Load,@IMPORT
162
	or	eax,eax
163
	jnz	skip_ini
1164 hidnplayr 164
 
165
 
1514 hidnplayr 166
	invoke ini.get_str, path, str_ipconfig, str_type, inibuf, 16, 0
1164 hidnplayr 167
 
1514 hidnplayr 168
	mov    eax,dword[inibuf]
1164 hidnplayr 169
 
1514 hidnplayr 170
	cmp    eax,'stat'
171
	jne    skip_ini
1164 hidnplayr 172
 
1514 hidnplayr 173
	invoke ini.get_str, path, str_ipconfig, str_ip, inibuf, 16, 0
174
	mov    edx, inibuf
175
	call   Ip2dword
176
	mcall  75, 3, edx
1164 hidnplayr 177
 
1514 hidnplayr 178
	invoke ini.get_str, path, str_ipconfig, str_gateway, inibuf, 16, 0
179
	mov    edx, inibuf
180
	call   Ip2dword
181
	mcall  75, 9, edx
1164 hidnplayr 182
 
1514 hidnplayr 183
	invoke ini.get_str, path, str_ipconfig, str_dns, inibuf, 16, 0
184
	mov    edx, inibuf
185
	call   Ip2dword
186
	mcall  75, 5, edx
1164 hidnplayr 187
 
1514 hidnplayr 188
	invoke ini.get_str, path, str_ipconfig, str_subnet, inibuf, 16, 0
189
	mov    edx, inibuf
190
	call   Ip2dword
191
	mcall  75, 7, edx
1164 hidnplayr 192
 
193
 
1514 hidnplayr 194
	mcall  -1
1164 hidnplayr 195
 
196
 
197
skip_ini:
198
 
1514 hidnplayr 199
	DEBUGF	1,"->Skip ini\n"
1164 hidnplayr 200
 
1514 hidnplayr 201
	mcall 74, 0, AF_INET4, IP_PROTO_UDP, 0	    ; open socket (parameters: domain, type, reserved)
202
	cmp   eax, -1
203
	je    error
204
	mov   [socketNum], eax
1164 hidnplayr 205
 
1514 hidnplayr 206
	DEBUGF	1,"->socket %x opened\n", eax
1164 hidnplayr 207
 
1514 hidnplayr 208
	mcall 74, 2, [socketNum], sockaddr1, 18     ; bind socket to local port 68
209
	cmp   eax, -1
210
	je    error
1164 hidnplayr 211
 
1514 hidnplayr 212
	DEBUGF	1,"->Socket Bound to local port 68\n"
1164 hidnplayr 213
 
1514 hidnplayr 214
	mcall 74, 4, [socketNum], sockaddr2, 18     ; connect to 255.255.255.255 on port 67
215
	cmp   eax, -1
216
	je    error
1164 hidnplayr 217
 
1514 hidnplayr 218
	DEBUGF	1,"->Connected to 255.255.255.255 on port 67\n"
1164 hidnplayr 219
 
1514 hidnplayr 220
	mov	byte [dhcpMsgType], 0x01	; DHCP discover
221
	mov	dword [dhcpLease], esi		; esi is still -1 (-1 = forever)
1164 hidnplayr 222
 
1514 hidnplayr 223
	mcall	26, 9
224
	imul	eax,100
225
	mov	[currTime],eax
1164 hidnplayr 226
 
227
buildRequest:				    ; Creates a DHCP request packet.
228
 
1514 hidnplayr 229
	DEBUGF	1,"->Building request\n"
1164 hidnplayr 230
 
1514 hidnplayr 231
	stdcall mem.Alloc, BUFFER
232
	mov	[dhcpMsg], eax
233
	test	eax,eax
234
	jz	apipa
1164 hidnplayr 235
 
1514 hidnplayr 236
	    ;;; todo: skip this bullcrap
1164 hidnplayr 237
 
1514 hidnplayr 238
	mov	edi, eax
239
	mov	ecx, BUFFER
240
	xor	eax, eax
241
	cld
242
	rep	stosb
1164 hidnplayr 243
 
1514 hidnplayr 244
	    ;; todo: put this in a buffer instead of writing bytes and words!
1164 hidnplayr 245
 
1514 hidnplayr 246
	mov	edx,[dhcpMsg]
1164 hidnplayr 247
 
1514 hidnplayr 248
	mov	[edx], byte 0x01		; Boot request
249
	mov	[edx+1], byte 0x01		; Ethernet
250
	mov	[edx+2], byte 0x06		; Ethernet h/w len
251
	mov	[edx+4], dword 0x11223344	; xid                 ;;;;;;;
252
	mov	eax,[currTime]
253
	mov	[edx+8], eax			; secs, our uptime
254
	mov	[edx+10], byte 0x80		; broadcast flag set
255
	mov	eax, dword [MAC]		; first 4 bytes of MAC
256
	mov	[edx+28],dword eax
257
	mov	ax, word [MAC+4]		; last 2 bytes of MAC
258
	mov	[edx+32],word ax
259
	mov	[edx+236], dword 0x63538263	; magic cookie
260
	mov	[edx+240], word 0x0135		; option DHCP msg type
261
	mov	al, [dhcpMsgType]
262
	mov	[edx+240+2], al
263
	mov	[edx+240+3], word 0x0433	; option Lease time = infinity
264
	mov	eax, [dhcpLease]
265
	mov	[edx+240+5], eax
266
	mov	[edx+240+9], word 0x0432	; option requested IP address
267
	mov	eax, [dhcpClientIP]
268
	mov	[edx+240+11], eax
269
	mov	[edx+240+15], word 0x0437	; option request list
270
	mov	[edx+240+17], dword 0x0f060301
1164 hidnplayr 271
 
1514 hidnplayr 272
	cmp	[dhcpMsgType], byte 0x01	; Check which msg we are sending
273
	jne	request_options
1164 hidnplayr 274
 
1514 hidnplayr 275
	mov	[edx+240+21], byte 0xff 	; "Discover" options
1164 hidnplayr 276
 
1514 hidnplayr 277
	mov	[dhcpMsgLen], dword 262 	; end of options marker
278
	jmp	send_request
279
 
1164 hidnplayr 280
request_options:
1514 hidnplayr 281
	mov	[edx+240+21], word 0x0436	; server IP
282
	mov	eax, [dhcpServerIP]
283
	mov	[edx+240+23], eax
1164 hidnplayr 284
 
1514 hidnplayr 285
	mov	[edx+240+27], byte 0xff 	; end of options marker
1164 hidnplayr 286
 
1514 hidnplayr 287
	mov	[dhcpMsgLen], dword 268
1164 hidnplayr 288
 
289
send_request:
1514 hidnplayr 290
	mcall	74, 6, [socketNum], [dhcpMsg], [dhcpMsgLen]	; write to socket ( send broadcast request )
1164 hidnplayr 291
 
1514 hidnplayr 292
	mov	eax, [dhcpMsg]				; Setup the DHCP buffer to receive response
293
	mov	[dhcpMsgLen], eax			; Used as a pointer to the data
1164 hidnplayr 294
 
1514 hidnplayr 295
	mcall	23, TIMEOUT*10				; wait for data
1164 hidnplayr 296
 
1514 hidnplayr 297
read_data:						; we have data - this will be the response
298
	mcall	74, 7, [socketNum], [dhcpMsg], BUFFER	; read data from socket
1164 hidnplayr 299
 
1514 hidnplayr 300
	DEBUGF	1,"->%d bytes received\n", eax
1164 hidnplayr 301
 
1514 hidnplayr 302
	push	eax
303
	mcall	74, 1, [socketNum]		       ; close the socket
304
	pop	eax
1164 hidnplayr 305
 
1514 hidnplayr 306
	cmp	eax, -1
307
	je	error
1164 hidnplayr 308
 
1514 hidnplayr 309
	mov	[dhcpMsgLen], eax
1164 hidnplayr 310
 
311
    ; depending on which msg we sent, handle the response
312
    ; accordingly.
313
    ; If the response is to a dhcp discover, then:
314
    ;  1) If response is DHCP OFFER then
315
    ;  1.1) record server IP, lease time & IP address.
316
    ;  1.2) send a request packet
317
    ; If the response is to a dhcp request, then:
318
    ;  1) If the response is DHCP ACK then
319
    ;  1.1) extract the DNS & subnet fields. Set them in the stack
320
 
321
    cmp     [dhcpMsgType], byte 0x01	    ; did we send a discover?
322
    je	    discover
323
    cmp     [dhcpMsgType], byte 0x03	    ; did we send a request?
324
    je	    request
325
 
1514 hidnplayr 326
	jmp	close				; really unknown, what we did
1164 hidnplayr 327
 
328
discover:
1514 hidnplayr 329
	call	parseResponse
1164 hidnplayr 330
 
1514 hidnplayr 331
	cmp	[dhcpMsgType], byte 0x02	; Was the response an offer?
332
	jne	apipa				; NO - so we do zeroconf
333
	mov	[dhcpMsgType], byte 0x03	; DHCP request
334
	jmp	buildRequest
1164 hidnplayr 335
 
336
request:
1514 hidnplayr 337
	call	parseResponse
1164 hidnplayr 338
 
1514 hidnplayr 339
	cmp	[dhcpMsgType], byte 0x05	; Was the response an ACK? It should be
340
	jne	apipa				; NO - so we do zeroconf
1164 hidnplayr 341
 
1514 hidnplayr 342
	jmp	close
1164 hidnplayr 343
 
344
;***************************************************************************
345
;   Function
346
;      parseResponse
347
;
348
;   Description
349
;      extracts the fields ( client IP address and options ) from
350
;      a DHCP response
351
;      The values go into
352
;       dhcpMsgType,dhcpLease,dhcpClientIP,dhcpServerIP,
353
;       dhcpDNSIP, dhcpSubnet
354
;      The message is stored in dhcpMsg
355
;
356
;***************************************************************************
357
parseResponse:
358
    DEBUGF  1,"Data received, parsing response\n"
359
    mov     edx, [dhcpMsg]
360
 
361
    pusha
1170 hidnplayr 362
    mcall 75, 3, [edx+16]
1164 hidnplayr 363
    mov     eax,[edx]
364
    mov     [dhcpClientIP],eax
365
    DEBUGF  1,"Client: %u.%u.%u.%u\n",[edx+16]:1,[edx+17]:1,[edx+18]:1,[edx+19]:1
366
    popa
367
 
368
    add     edx, 240			    ; Point to first option
369
    xor     ecx, ecx
370
 
371
next_option:
372
    add     edx, ecx
373
pr001:
374
    mov     al, [edx]
375
    cmp     al, 0xff			    ; End of options?
376
    je	    pr_exit
377
 
378
    cmp     al, dhcp_msg_type		    ; Msg type is a single byte option
379
    jne     @f
380
 
381
    mov     al, [edx+2]
382
    mov     [dhcpMsgType], al
383
    add     edx, 3
384
    jmp     pr001			    ; Get next option
385
 
386
@@:
387
    inc     edx
388
    movzx   ecx, byte [edx]
389
    inc     edx 			    ; point to data
390
 
391
    cmp     al, dhcp_dhcp_server_id	    ; server ip
392
    jne     @f
393
    mov     eax, [edx]
394
    mov     [dhcpServerIP], eax
395
    DEBUGF  1,"Server: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1
396
    jmp     next_option
397
 
398
@@:
399
    cmp     al, dhcp_address_time
400
    jne     @f
401
 
402
    pusha
403
    mov     eax,[edx]
404
    bswap   eax
405
    mov     [dhcpLease],eax
406
    DEBUGF  1,"lease: %d\n",eax
407
    popa
408
 
409
    jmp     next_option
410
 
411
@@:
412
    cmp     al, dhcp_subnet_mask
413
    jne     @f
414
 
415
    pusha
1170 hidnplayr 416
    mcall 75, 7, [edx]
1164 hidnplayr 417
    DEBUGF  1,"Subnet: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1
418
    popa
419
 
420
    jmp     next_option
421
 
422
@@:
423
    cmp     al, dhcp_router
424
    jne     @f
425
 
426
    pusha
1170 hidnplayr 427
    mcall 75, 9, [edx]
1164 hidnplayr 428
    DEBUGF  1,"Gateway: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1
429
    popa
430
 
431
    jmp     next_option
432
 
433
 
434
@@:
435
    cmp     al, dhcp_domain_server
436
    jne     next_option
437
 
438
    pusha
1170 hidnplayr 439
    mcall 75, 5, [edx]
1164 hidnplayr 440
    DEBUGF  1,"DNS: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1
441
    popa
442
 
443
    jmp     next_option
444
 
445
pr_exit:
446
 
447
;    DEBUGF  1,"Sending ARP announce\n"
1514 hidnplayr 448
;;;
1164 hidnplayr 449
 
450
    jmp close
451
 
452
apipa:
453
    stdcall mem.Free, [dhcpMsg]
454
 
455
link_local:
456
    call random
457
    mov  ecx,0xfea9			    ; IP 169.254.0.0 link local net, see RFC3927
458
    mov  cx,ax
1196 hidnplayr 459
    mcall 75, 3, ecx			      ; mask is 255.255.0.0
1164 hidnplayr 460
    DEBUGF 1,"Link Local IP assinged: 169.254.%u.%u\n",[generator+2]:1,[generator+3]:1
1196 hidnplayr 461
    mcall 75, 5, 0xffff
462
    mcall 75, 9, 0x0
463
    mcall 75, 7, 0x0
1164 hidnplayr 464
 
465
    mcall 5, PROBE_WAIT*100
466
 
467
    xor esi,esi
468
   probe_loop:
469
    call  random			    ; create a pseudo random number in eax (seeded by MAC)
470
 
471
    cmp   al,PROBE_MIN*100		    ; check if al is bigger then PROBE_MIN
472
    jge   @f				    ; all ok
473
    add   al,(PROBE_MAX-PROBE_MIN)*100	    ; al is too small
474
   @@:
475
 
476
    cmp   al,PROBE_MAX*100
477
    jle   @f
478
    sub   al,(PROBE_MAX-PROBE_MIN)*100
479
   @@:
480
 
481
    movzx ebx,al
482
    DEBUGF  1,"Waiting %u0ms\n",ebx
483
    mcall 5
484
 
485
    DEBUGF  1,"Sending Probe\n"
486
;    eth.ARP_PROBE MAC
487
    inc   esi
488
 
489
    cmp   esi,PROBE_NUM
490
    jl	  probe_loop
491
 
492
; now we wait further ANNOUNCE_WAIT seconds and send ANNOUNCE_NUM ARP announces. If any other host has assingned
493
; IP within this time, we should create another adress, that have to be done later
494
 
495
    DEBUGF  1,"Waiting %us\n",ANNOUNCE_WAIT
496
    mcall 5, ANNOUNCE_WAIT*100
497
    xor   esi,esi
498
   announce_loop:
499
 
500
    DEBUGF  1,"Sending Announce\n"
501
;    eth.ARP_ANNOUNCE MAC
502
 
503
    inc   esi
504
    cmp   esi,ANNOUNCE_NUM
505
    je	  @f
506
 
507
    DEBUGF  1,"Waiting %us\n",ANNOUNCE_INTERVAL
508
    mcall 5, ANNOUNCE_INTERVAL*100
509
    jmp   announce_loop
510
   @@:
511
    ; we should, instead of closing, detect ARP conflicts and detect if cable keeps connected ;)
512
 
513
error:
514
close:
515
    mcall -1
516
 
517
 
518
random:  ; Pseudo random actually
519
 
520
    mov   eax,[generator]
521
    add   eax,-43ab45b5h
522
    ror   eax,1
523
    bswap eax
524
    xor   eax,dword[MAC]
525
    ror   eax,1
526
    xor   eax,dword[MAC+2]
527
    mov   [generator],eax
528
 
529
ret
530
 
531
; DATA AREA
532
 
533
align 16
534
@IMPORT:
535
 
536
library \
537
	libini,'libini.obj'
538
 
539
import	libini, \
1196 hidnplayr 540
	ini.get_str,'ini_get_str'
1164 hidnplayr 541
 
542
include_debug_strings
543
 
544
filename db '.ini',0
545
str_ip db 'ip',0
546
str_subnet db 'subnet',0
547
str_gateway db 'gateway',0
548
str_dns db 'dns',0
549
str_ipconfig db 'ipconfig',0
550
str_type db 'type',0
551
 
552
 
553
sockaddr1:
554
 
555
	dw AF_INET4
1514 hidnplayr 556
	dw 68		; local port
1164 hidnplayr 557
	dd 0		; local IP
558
 
559
	rb 10
560
 
561
 
562
sockaddr2:
563
 
564
	dw AF_INET4
1514 hidnplayr 565
	dw 67		; destination port
1164 hidnplayr 566
	dd -1		; destination IP
567
 
568
	rb 10
569
 
570
 
571
IM_END:
572
 
573
inibuf		rb 16
574
 
575
dhcpClientIP	dd  ?
576
dhcpMsgType	db  ?
577
dhcpLease	dd  ?
578
dhcpServerIP	dd  ?
579
 
580
dhcpMsgLen	dd  ?
581
socketNum	dd  ?
582
 
583
MAC		dp  ?
584
 
585
currTime	dd  ?
586
renewTime	dd  ?
587
generator	dd  ?
588
 
589
dhcpMsg 	dd  ?
590
 
591
I_END_2:
592
 
593
path		rb  1024+5
594
 
595
I_END: