Subversion Repositories Kolibri OS

Rev

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