; ; DHCP Client ; ; Compile with FASM for Menuet ; include 'lang.inc' include '..\..\..\macros.inc' use32 org 0x0 db 'MENUET01' ; 8 byte id dd 0x01 ; header version dd START ; start of code dd I_END ; size of image dd I_END+0x8000 ; memory for app dd I_END+0x8000 ; esp dd 0x0 , 0x0 ; I_Param , I_Icon START: ; start of execution mov eax,40 ; Report events mov ebx,10000111b ; Stack 8 + defaults int 0x40 red: ; redraw call draw_window ; at first, draw the window still: mov eax,10 ; wait here for event mcall cmp eax,1 ; redraw request ? jz red cmp eax,2 ; key in buffer ? jz key cmp eax,3 ; button in buffer ? jz button jmp still key: ; Keys are not valid at this part of the mov eax,2 ; loop. Just read it and ignore mcall jmp still button: ; button mov eax,17 ; get id mcall cmp ah,1 ; button id=1 ? jnz noclose ; close socket before exiting mov eax, 53 mov ebx, 1 mov ecx, [socketNum] mcall mov eax,0xffffffff ; close this program mcall noclose: cmp ah,3 ; Resolve address? jnz still call draw_window call contactDHCPServer jmp still ;*************************************************************************** ; Function ; parseResponse ; ; Description ; extracts the fields ( client IP address and options ) from ; a DHCP response ; The values go into ; dhcpMsgType,dhcpLease,dhcpClientIP,dhcpServerIP, ; dhcpDNSIP, dhcpSubnet ; The message is stored in dhcpMsg ; ;*************************************************************************** parseResponse: mov edx, dhcpMsg mov eax, [edx+16] mov [dhcpClientIP], eax ; Scan options add edx, 240 ; Point to first option pr001: ; Get option id mov al, [edx] cmp al, 0xff ; End of options? je pr_exit cmp al, 53 ; Msg type is a single byte option jne pr002 mov al, [edx+2] mov [dhcpMsgType], al add edx, 3 jmp pr001 ; Get next option pr002: ; All other (accepted) options are 4 bytes in length inc edx movzx ecx, byte [edx] inc edx ; point to data cmp al, 54 ; server id jne pr0021 mov eax, [edx] ; All options are 4 bytes, so get it mov [dhcpServerIP], eax jmp pr003 pr0021: cmp al, 51 ; lease jne pr0022 mov eax, [edx] ; All options are 4 bytes, so get it mov [dhcpLease], eax jmp pr003 pr0022: cmp al, 1 ; subnet mask jne pr0023 mov eax, [edx] ; All options are 4 bytes, so get it mov [dhcpSubnet], eax jmp pr003 pr0023: cmp al, 6 ; dns ip jne pr0024 mov eax, [edx] ; All options are 4 bytes, so get it mov [dhcpDNSIP], eax pr0024: cmp al, 3 ; gateway ip jne pr003 mov eax, [edx] ; All options are 4 bytes, so get it mov [dhcpGateway], eax pr003: add edx, ecx jmp pr001 pr_exit: ret ;*************************************************************************** ; Function ; buildRequest ; ; Description ; Creates a DHCP request packet. ; ;*************************************************************************** buildRequest: ; Clear dhcpMsg to all zeros xor eax,eax mov edi,dhcpMsg mov ecx,512 cld rep stosb mov edx, dhcpMsg mov [edx], byte 0x01 ; Boot request mov [edx+1], byte 0x01 ; Ethernet mov [edx+2], byte 0x06 ; Ethernet h/w len mov [edx+4], dword 0x11223344 ; xid mov [edx+10], byte 0x80 ; broadcast flag set mov [edx+236], dword 0x63538263 ; magic number ; option DHCP msg type mov [edx+240], word 0x0135 mov al, [dhcpMsgType] mov [edx+240+2], al ; option Lease time = infinity mov [edx+240+3], word 0x0433 mov eax, [dhcpLease] mov [edx+240+5], eax ; option requested IP address mov [edx+240+9], word 0x0432 mov eax, [dhcpClientIP] mov [edx+240+11], eax ; option request list mov [edx+240+15], word 0x0437 mov [edx+240+17], dword 0x0f060301 ; Check which msg we are sending cmp [dhcpMsgType], byte 0x01 jne br001 ; "Discover" options ; end of options marker mov [edx+240+21], byte 0xff mov [dhcpMsgLen], dword 262 jmp br_exit br001: ; "Request" options ; server IP mov [edx+240+21], word 0x0436 mov eax, [dhcpServerIP] mov [edx+240+23], eax ; end of options marker mov [edx+240+27], byte 0xff mov [dhcpMsgLen], dword 268 br_exit: ret ;*************************************************************************** ; Function ; contactDHCPServer ; ; Description ; negotiates settings with a DHCP server ; ;*************************************************************************** contactDHCPServer: ; First, open socket mov eax, 53 mov ebx, 0 mov ecx, 68 ; local port dhcp client mov edx, 67 ; remote port - dhcp server mov esi, 0xffffffff ; broadcast mcall mov [socketNum], eax ; Setup the first msg we will send mov [dhcpMsgType], byte 0x01 ; DHCP discover mov [dhcpLease], dword 0xffffffff mov [dhcpClientIP], dword 0 mov [dhcpServerIP], dword 0 call buildRequest ctr000: ; write to socket ( send broadcast request ) mov eax, 53 mov ebx, 4 mov ecx, [socketNum] mov edx, [dhcpMsgLen] mov esi, dhcpMsg mcall ; Setup the DHCP buffer to receive response mov eax, dhcpMsg mov [dhcpMsgLen], eax ; Used as a pointer to the data ; now, we wait for ; UI redraw ; UI close ; or data from remote ctr001: mov eax,10 ; wait here for event mcall cmp eax,1 ; redraw request ? je ctr003 cmp eax,2 ; key in buffer ? je ctr004 cmp eax,3 ; button in buffer ? je ctr005 ; Any data in the UDP receive buffer? mov eax, 53 mov ebx, 2 mov ecx, [socketNum] mcall cmp eax, 0 je ctr001 ; we have data - this will be the response ctr002: mov eax, 53 mov ebx, 3 mov ecx, [socketNum] mcall ; read byte - block (high byte) ; Store the data in the response buffer mov eax, [dhcpMsgLen] mov [eax], bl inc dword [dhcpMsgLen] mov eax, 53 mov ebx, 2 mov ecx, [socketNum] mcall ; any more data? cmp eax, 0 jne ctr002 ; yes, so get it ; depending on which msg we sent, handle the response ; accordingly. ; If the response is to a dhcp discover, then: ; 1) If response is DHCP OFFER then ; 1.1) record server IP, lease time & IP address. ; 1.2) send a request packet ; 2) else exit ( display error ) ; If the response is to a dhcp request, then: ; 1) If the response is DHCP ACK then ; 1.1) extract the DNS & subnet fields. Set them in the stack ; 2) else exit ( display error ) cmp [dhcpMsgType], byte 0x01 ; did we send a discover? je ctr007 cmp [dhcpMsgType], byte 0x03 ; did we send a request? je ctr008 ; should never get here - we only send discover or request jmp ctr006 ctr007: call parseResponse ; Was the response an offer? It should be cmp [dhcpMsgType], byte 0x02 jne ctr006 ; NO - so quit ; send request mov [dhcpMsgType], byte 0x03 ; DHCP request call buildRequest jmp ctr000 ctr008: call parseResponse ; Was the response an ACK? It should be cmp [dhcpMsgType], byte 0x05 jne ctr006 ; NO - so quit ; Set or display addresses here... ctr006: ; close socket mov eax, 53 mov ebx, 1 mov ecx, [socketNum] mcall mov [socketNum], dword 0xFFFF call draw_window jmp ctr001 ctr003: ; redraw call draw_window jmp ctr001 ctr004: ; key mov eax,2 ; just read it and ignore mcall jmp ctr001 ctr005: ; button mov eax,17 ; get id mcall ; close socket mov eax, 53 mov ebx, 1 mov ecx, [socketNum] mcall mov [socketNum], dword 0xFFFF call draw_window ; at first, draw the window ret ; ********************************************* ; ******* WINDOW DEFINITIONS AND DRAW ******** ; ********************************************* ; Pass in the IP address in edi ; row to display in [ya] drawIP: ; mov edi,hostIP mov ecx, edi add ecx, 4 mov edx,[ya] add edx, 97*65536 mov esi,0x00ffffff mov ebx,3*65536 ipdisplay: mov eax,47 push ecx movzx ecx,byte [edi] mcall pop ecx add edx,6*4*65536 inc edi cmp edi,ecx jb ipdisplay ret drawDHMS: mov eax,[edi] bswap eax mov esi,dhms mov ecx,16 mov edi,text+40*4+12 cmp eax,0xffffffff jne nforever mov esi,forever cld rep movsb ret nforever: cld rep movsb mov ecx,28 xor edx,edx mov ebx,60 div ebx call displayDHMS xor edx,edx div ebx call displayDHMS xor edx,edx mov ebx,24 div ebx call displayDHMS mov edx,eax call displayDHMS ret displayDHMS: pusha mov eax,47 mov ebx,3*65536 mov edx,ecx imul edx,6 shl edx,16 add edx,1*65536+99 mov ecx,[esp+20] mov esi,0xffffff mcall popa sub ecx,4 ret draw_window: mov eax,12 ; function 12:tell os about windowdraw mov ebx,1 ; 1, start of draw mcall ; DRAW WINDOW mov eax,0 ; function 0 : define and draw window mov ebx,100*65536+300 ; [x start] *65536 + [x size] mov ecx,100*65536+156 ; [y start] *65536 + [y size] mov edx,0x14224466 ; color of work area RRGGBB mov edi,title ; WINDOW LABEL mcall mov eax,8 ; Resolve mov ebx,20*65536+90 mov ecx,127*65536+15 mov edx,3 mov esi,0x557799 mcall ; Pass in the IP address in edi ; row to display in [ya] mov edi, dhcpClientIP mov eax, 35 mov [ya], eax call drawIP mov edi, dhcpGateway mov eax, 35 + 16 mov [ya], eax call drawIP mov edi, dhcpSubnet mov eax, 35 + 32 mov [ya], eax call drawIP mov edi, dhcpDNSIP mov eax, 35 + 48 mov [ya], eax call drawIP mov edi, dhcpLease call drawDHMS ; Re-draw the screen text cld mov eax,4 mov ebx,25*65536+35 ; draw info text with function 4 mov ecx,0xffffff mov edx,text mov esi,40 newline: mcall add ebx,16 add edx,40 cmp [edx],byte 'x' jnz newline mov eax,12 ; function 12:tell os about windowdraw mov ebx,2 ; 2, end of draw mcall ret ; DATA AREA ya dd 0x0 text: db 'Client IP : . . . ' db 'Gateway IP: . . . ' db 'Subnet : . . . ' db 'DNS IP : . . . ' db 'Lease Time: d h m s ' db ' ' db ' SEND REQUEST ' db 'x <- END MARKER, DONT DELETE ' dhms db ' d h m s' forever db 'Forever ' title db 'DHCP Client Test',0 dhcpMsgType: db 0 dhcpLease: dd 0 dhcpClientIP: dd 0 dhcpServerIP: dd 0 dhcpDNSIP: dd 0 dhcpSubnet: dd 0 dhcpGateway: dd 0 dhcpMsgLen: dd 0 socketNum: dd 0xFFFF dhcpMsg: I_END: