Subversion Repositories Kolibri OS

Rev

Rev 1166 | 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 2  ;;;;;
  48. IP_PROTO_UDP    equ 17
  49.  
  50.  
  51.  
  52.  
  53. include '../proc32.inc'
  54. include '../macros.inc'
  55. include '../debug-fdo.inc'
  56. include 'dhcp.inc'
  57. include 'dll.inc'
  58.  
  59.  
  60. Ip2dword:
  61.     push    edx
  62.  
  63.     ; This code validates if the query is an IP containing 4 numbers and 3 dots
  64.  
  65.     xor     al, al            ; make al (dot count) zero
  66.  
  67.    @@:
  68.     cmp     byte[edx],'0'     ; check if this byte is a number, if not jump to no_IP
  69.     jl      no_IP             ;
  70.     cmp     byte[edx],'9'     ;
  71.     jg      no_IP             ;
  72.  
  73.     inc     edx               ; the byte was a number, so lets check the next byte
  74.  
  75.     cmp     byte[edx],0       ; is this byte zero? (have we reached end of query?)
  76.     jz      @f                ; jump to next @@ then
  77.     cmp     byte[edx],':'
  78.     jz      @f
  79.  
  80.     cmp     byte[edx],'.'     ; is this byte a dot?
  81.     jne     @r                ; if not, jump to previous @@
  82.  
  83.     inc     al                ; the byte was a dot so increment al(dot count)
  84.     inc     edx               ; next byte
  85.     jmp     @r                ; lets check for numbers again (jump to previous @@)
  86.  
  87.    @@:                        ; we reach this when end of query reached
  88.     cmp     al,3              ; check if there where 3 dots
  89.     jnz     no_IP             ; if not, jump to no_IP
  90.  
  91.     ; The following code will convert this IP into a dword and output it in eax
  92.     ; If there is also a port number specified, this will be returned in ebx, otherwise ebx is -1
  93.  
  94.     pop     esi               ; edx (query address) was pushed onto stack and is now popped in esi
  95.  
  96.     xor     edx, edx          ; result
  97.     xor     eax, eax          ; current character
  98.     xor     ebx, ebx          ; current byte
  99.  
  100. .outer_loop:
  101.     shl     edx, 8
  102.     add     edx, ebx
  103.     xor     ebx, ebx
  104. .inner_loop:
  105.     lodsb
  106.     test    eax, eax
  107.     jz      .finish
  108.     cmp     al, '.'
  109.     jz      .outer_loop
  110.     sub     eax, '0'
  111.     imul    ebx, 10
  112.     add     ebx, eax
  113.     jmp     .inner_loop
  114. .finish:
  115.     shl     edx, 8
  116.     add     edx, ebx
  117.  
  118.     bswap   edx               ; we want little endian order
  119.  
  120.     ret
  121.  
  122. no_IP:
  123.     pop     edx
  124.     xor     edx, edx
  125.  
  126.     ret
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133. START:                                      ; start of execution
  134.  
  135.     mcall 40, 1 shl 7 ; network event
  136.  
  137. ;    eth.set_network_drv 0x00000383
  138.  
  139.     DEBUGF  1,">Zero-config service:\n"
  140.  
  141. ;    eth.status eax                          ; Read the Stack status
  142. ;    test    eax,eax                         ; if eax is zero, no driver was found
  143. ;    jnz     @f
  144. ;    DEBUGF  1,"No Card found!\n"
  145. ;    jmp     close
  146.  
  147. ;   @@:
  148. ;    DEBUGF  1,"Detected card: %x\n",eax
  149. ;   @@:
  150. ;    eth.check_cable eax
  151. ;    test    al,al
  152. ;    jnz     @f
  153. ;    DEBUGF  1,"Cable disconnected!\n"
  154. ;    mcall   5, 500                          ; loop until cable is connected (check every 5 sec)
  155. ;    jmp     @r
  156.  
  157. ;   @@:
  158. ;    eth.read_mac MAC
  159.  
  160.     mcall 75, 1337 shl 16 + 4
  161.     mov   word[MAC], bx
  162.     mov   dword[MAC+2], eax
  163.  
  164.     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
  165.  
  166.     cld
  167.     mov     edi, path      ; Calculate the length of zero-terminated string
  168.     xor     al , al
  169.     mov     ecx, 1024
  170.     repnz   scas byte[es:edi]
  171.     dec     edi
  172.  
  173.     mov     esi, filename
  174.     movsd
  175.     movsb
  176.  
  177.     DEBUGF  1,"->path to ini: %s\n", path
  178.  
  179.     mcall 68,11
  180.  
  181.     stdcall dll.Load,@IMPORT
  182.     or      eax,eax
  183.     jnz     skip_ini
  184.  
  185.  
  186.     invoke ini.get_str, path, str_ipconfig, str_type, inibuf, 16, 0
  187.  
  188.     mov  eax,dword[inibuf]
  189.  
  190.     cmp  eax,'stat'
  191.     jne  skip_ini
  192.  
  193.     invoke ini.get_str, path, str_ipconfig, str_ip, inibuf, 16, 0
  194.     mov    edx, inibuf
  195.     call   Ip2dword
  196.     mcall  73, 3, edx
  197.  
  198.     invoke ini.get_str, path, str_ipconfig, str_gateway, inibuf, 16, 0
  199.     mov    edx, inibuf
  200.     call   Ip2dword
  201.     mcall  73, 9, edx
  202.  
  203.     invoke ini.get_str, path, str_ipconfig, str_dns, inibuf, 16, 0
  204.     mov    edx, inibuf
  205.     call   Ip2dword
  206.     mcall  73, 7, edx
  207.  
  208.     invoke ini.get_str, path, str_ipconfig, str_subnet, inibuf, 16, 0
  209.     mov    edx, inibuf
  210.     call   Ip2dword
  211.     mcall  73, 5, edx
  212.  
  213.  
  214.     mcall  -1
  215.  
  216.  
  217. skip_ini:
  218.  
  219.     DEBUGF  1,"->Skip ini\n"
  220.  
  221.     mcall 74, 0, AF_INET4, IP_PROTO_UDP, 0      ; open socket (parameters: domain, type, reserved)
  222.     cmp   eax, -1
  223.     je    error
  224.     mov   [socketNum], eax
  225.  
  226.     DEBUGF  1,"->socket %x opened\n", eax
  227.  
  228.     mcall 74, 2, [socketNum], sockaddr1, 18     ; bind socket to local port 68
  229.     cmp   eax, -1
  230.     je    error
  231.  
  232.     DEBUGF  1,"->Socket Bound to local port 68\n"
  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,"->%d bytes received\n", eax
  319.  
  320.     push eax
  321.     mcall 74, 1, [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 75, 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 75, 7, [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 75, 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 75, 5, [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: