Subversion Repositories Kolibri OS

Rev

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