Subversion Repositories Kolibri OS

Rev

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