Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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