Subversion Repositories Kolibri OS

Rev

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