Subversion Repositories Kolibri OS

Rev

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