Subversion Repositories Kolibri OS

Rev

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