; ; DNS Domain name -> IP lookup ; ; Compile with FASM for Menuet ; ; If you like, you camd change the DNS server default by changing the ; IP address in the dnsServer string. ; Enabling debugging puts the received response to the ; debug board DEBUGGING_ENABLED equ 1 DEBUGGING_DISABLED equ 0 DEBUGGING_STATE equ DEBUGGING_DISABLED use32 org 0x0 db 'MENUET01' ; header dd 0x01 ; header version dd START ; entry point dd I_END ; image size dd I_END+0x10000 ; required memory dd I_END+0x10000 ; esp dd 0x0 , 0x0 ; I_Param , I_Path include 'lang.inc' include 'macros.inc' START: ; start of execution mov eax,40 ; Report events mov ebx,10000111b ; Stack 8 + defaults int 0x40 mov dword [prompt], p1 mov dword [promptlen], p1len - p1 ; 'waiting for command' red: call draw_window ; at first, draw the window still: mov eax,10 ; wait here for event mcall cmp eax,1 ; redraw request ? jz red cmp eax,2 ; key in buffer ? jz key cmp eax,3 ; button in buffer ? jz button jmp still key: ; Keys are not valid at this part of the mov eax,2 ; loop. Just read it and ignore mcall jmp still button: ; button mov eax,17 ; get id mcall cmp ah,1 ; button id=1 ? jnz noclose ; close socket before exiting mov eax, 53 mov ebx, 1 mov ecx, [socketNum] mcall mov eax,0xffffffff ; close this program mcall noclose: cmp ah,3 ; Resolve address? jnz noresolve mov dword [prompt], p5 mov dword [promptlen], p5len - p5 ; display 'Resolving' call draw_window call translateData ; Convert domain & DNS IP address call resolveDomain jmp still noresolve: cmp ah,4 jz f1 ; Enter domain name cmp ah,5 jz f2 ; enter DNS Server IP jmp still f1: mov [addr],dword query mov [ya],dword 35 jmp rk f2: mov [addr],dword dnsServer mov [ya],dword 35+16 rk: mov ecx,26 mov edi,[addr] mov al,' ' rep stosb call print_text mov edi,[addr] f11: mov eax,10 mcall cmp eax,2 jz fbu jmp still fbu: mov eax,2 mcall ; get key shr eax,8 cmp eax,8 jnz nobs cmp edi,[addr] jz f11 sub edi,1 mov [edi],byte ' ' call print_text jmp f11 nobs: cmp eax,dword 31 jbe f11 cmp eax,dword 95 jb keyok sub eax,32 keyok: mov [edi],al call print_text add edi,1 mov esi,[addr] add esi,26 cmp esi,edi jnz f11 jmp still print_text: mov eax,13 mov ebx,103*65536+26*6 mov ecx,[ya] shl ecx,16 mov cx,8 mov edx,0x224466 mcall mov eax,4 mov ebx,103*65536 add ebx,[ya] mov ecx,0xffffff mov edx,[addr] mov esi,26 mcall ret ;*************************************************************************** ; Function ; translateData ; ; Description ; Coverts the domain name and DNS IP address typed in by the user into ; a format suitable for the IP layer. ; ; The ename, in query, is converted and stored in dnsMsg ; The DNS ip, in dnsServer, is converted and stored in dnsIP ; ;*************************************************************************** translateData: ; first, get the IP address of the DNS server ; Then, build up the request string. xor eax, eax mov dh, 10 mov dl, al mov [dnsIP], eax mov esi, dnsServer mov edi, dnsIP mov ecx, 4 td003: lodsb sub al, '0' add dl, al lodsb cmp al, '.' je ipNext cmp al, ' ' je ipNext mov dh, al sub dh, '0' mov al, 10 mul dl add al, dh mov dl, al lodsb cmp al, '.' je ipNext cmp al, ' ' je ipNext mov dh, al sub dh, '0' mov al, 10 mul dl add al, dh mov dl, al lodsb ipNext: mov [edi], dl inc edi mov dl, 0 loop td003 ; Build the request string mov eax, 0x00010100 mov [dnsMsg], eax mov eax, 0x00000100 mov [dnsMsg+4], eax mov eax, 0x00000000 mov [dnsMsg+8], eax ; domain name goes in at dnsMsg+12 mov esi, dnsMsg + 12 ; location of label length mov edi, dnsMsg + 13 ; label start mov edx, query mov ecx, 12 ; total string length so far td002: mov [esi], byte 0 inc ecx td0021: mov al, [edx] cmp al, ' ' je td001 ; we have finished the string translation cmp al, '.' ; we have finished the label je td004 inc byte [esi] inc ecx mov [edi], al inc edi inc edx jmp td0021 td004: mov esi, edi inc edi inc edx jmp td002 ; write label len + label text td001: mov [edi], byte 0 inc ecx inc edi mov [edi], dword 0x01000100 add ecx, 4 mov [dnsMsgLen], ecx ret ;*************************************************************************** ; Function ; resolveDomain ; ; Description ; Sends a question to the dns server ; works out the IP address from the response from the DNS server ; ;*************************************************************************** resolveDomain: ; Get a free port number mov ecx, 1000 ; local port starting at 1000 getlp: inc ecx push ecx mov eax, 53 mov ebx, 9 mcall pop ecx cmp eax, 0 ; is this local port in use? jz getlp ; yes - so try next ; First, open socket mov eax, 53 mov ebx, 0 mov edx, 53 ; remote port - dns mov esi, [dnsIP] mcall mov [socketNum], eax ; write to socket ( request DNS lookup ) mov eax, 53 mov ebx, 4 mov ecx, [socketNum] mov edx, [dnsMsgLen] mov esi, dnsMsg mcall ; Setup the DNS response buffer mov eax, dnsMsg mov [dnsMsgLen], eax ; now, we wait for ; UI redraw ; UI close ; or data from remote ctr001: mov eax,10 ; wait here for event mcall cmp eax,1 ; redraw request ? je ctr003 cmp eax,2 ; key in buffer ? je ctr004 cmp eax,3 ; button in buffer ? je ctr005 ; Any data in the UDP receive buffer? mov eax, 53 mov ebx, 2 mov ecx, [socketNum] mcall cmp eax, 0 je ctr001 ; we have data - this will be the response ctr002: mov eax, 53 mov ebx, 3 mov ecx, [socketNum] mcall ; read byte - block (high byte) ; Store the data in the response buffer mov eax, [dnsMsgLen] mov [eax], bl inc dword [dnsMsgLen] if DEBUGGING_STATE = DEBUGGING_ENABLED call debug_print_rx_ip end if mov eax, 53 mov ebx, 2 mov ecx, [socketNum] mcall ; any more data? cmp eax, 0 jne ctr002 ; yes, so get it ; close socket mov eax, 53 mov ebx, 1 mov ecx, [socketNum] mcall mov [socketNum], dword 0xFFFF ; Now parse the message to get the host IP ; Man, this is complicated. It's described in ; RFC 1035 ; 1) Validate that we have an answer with > 0 responses ; 2) Find the answer record with TYPE 0001 ( host IP ) ; 3) Finally, copy the IP address to the display ; Note: The response is in dnsMsg ; The end of the buffer is pointed to by [dnsMsgLen] ; Clear the IP address text mov [hostIP], dword 0 mov esi, dnsMsg ; Is this a response to my question? mov al, [esi+2] and al, 0x80 cmp al, 0x80 jne ctr002a ; Were there any errors? mov al, [esi+3] and al, 0x0F cmp al, 0x00 jne ctr002a ; Is there ( at least 1 ) answer? mov ax, [esi+6] cmp ax, 0x00 je ctr002a ; Header validated. Scan through and get my answer add esi, 12 ; Skip to the question field ; Skip through the question field call skipName add esi, 4 ; skip past the questions qtype, qclass ctr002z: ; Now at the answer. There may be several answers, ; find the right one ( TYPE = 0x0001 ) call skipName mov ax, [esi] cmp ax, 0x0100 ; Is this the IP address answer? jne ctr002c ; Yes! Point esi to the first byte of the IP address add esi, 10 mov eax, [esi] mov [hostIP], eax jmp ctr002a ; And exit... ctr002c: ; Skip through the answer, move to the next add esi, 8 movzx eax, byte [esi+1] mov ah, [esi] add esi, eax add esi, 2 ; Have we reached the end of the msg? ; This is an error condition, should not happen cmp esi, [dnsMsgLen] jl ctr002z ; Check next answer jmp ctr002a ; abort ctr002a: mov dword [prompt], p4 ; Display IP address mov dword [promptlen], p4len - p4 call draw_window jmp ctr001 ctr003: ; redraw call draw_window jmp ctr001 ctr004: ; key mov eax,2 ; just read it and ignore mcall jmp ctr001 ctr005: ; button mov eax,17 ; get id mcall ; close socket mov eax, 53 mov ebx, 1 mov ecx, [socketNum] mcall mov [socketNum], dword 0xFFFF mov [hostIP], dword 0 mov dword [prompt], p1 mov dword [promptlen], p1len - p1 ; 'waiting for command' call draw_window ; at first, draw the window ret ;*************************************************************************** ; Function ; skipName ; ; Description ; Increment esi to the first byte past the name field ; Names may use compressed labels. Normally do. ; RFC 1035 page 30 gives details ; ;*************************************************************************** skipName: mov al, [esi] cmp al, 0 je sn_exit and al, 0xc0 cmp al, 0xc0 je sn001 movzx eax, byte [esi] inc eax add esi, eax jmp skipName sn001: add esi, 2 ; A pointer is always at the end ret sn_exit: inc esi ret ; ********************************************* ; ******* WINDOW DEFINITIONS AND DRAW ******** ; ********************************************* draw_window: mov eax,12 ; function 12:tell os about windowdraw mov ebx,1 ; 1, start of draw mcall ; DRAW WINDOW mov eax,0 ; function 0 : define and draw window mov ebx,100*65536+300 ; [x start] *65536 + [x size] mov ecx,100*65536+140 ; [y start] *65536 + [y size] mov edx,0x14224466 ; color of work area RRGGBB mov edi,title ; WINDOW LABEL; mcall mov eax,8 ; Resolve mov ebx,20*65536+190 mov ecx,79*65536+15 mov edx,3 mov esi,0x557799 mcall ;mov eax,8 mov ebx,270*65536+10 mov ecx,34*65536+10 inc edx mcall ;mov eax,8 mov ebx,270*65536+10 mov ecx,50*65536+10 inc edx mcall ; Copy the file name to the screen buffer ; file name is same length as IP address, to ; make the math easier later. cld mov esi,query mov edi,text+13 mov ecx,26 rep movsb ; copy the IP address to the screen buffer mov esi,dnsServer mov edi,text+40+13 mov ecx,26 rep movsb ; copy the prompt to the screen buffer mov esi,[prompt] mov edi,text+200 mov ecx,[promptlen] rep movsb ; Re-draw the screen text cld mov eax,4 mov ebx,25*65536+35 ; draw info text with function 4 mov ecx,0xffffff mov edx,text mov esi,40 newline: mcall add ebx,16 add edx,40 cmp [edx],byte 'x' jnz newline ; Write the host IP, if we have one mov eax, [hostIP] cmp eax, 0 je dw001 ; We have an IP address... display it mov edi,hostIP mov edx,97*65536+115 mov esi,0x00ffffff mov ebx,3*65536 ipdisplay: mov eax,47 movzx ecx,byte [edi] mcall add edx,6*4*65536 inc edi cmp edi,hostIP+4 jb ipdisplay dw001: mov eax,12 ; function 12:tell os about windowdraw mov ebx,2 ; 2, end of draw mcall ret if DEBUGGING_STATE = DEBUGGING_ENABLED ;**************************************************************************** ; Function ; debug_print_string ; ; Description ; prints a string to the debug board ; ; esi holds ptr to msg to display ; ; Nothing preserved; I'm assuming a pusha/popa is done before calling ; ;**************************************************************************** debug_print_string: mov cl, [esi] cmp cl, 0 jnz dps_001 ret dps_001: mov eax,63 mov ebx, 1 push esi mcall inc word [ind] mov ax, [ind] and ax, 0x1f cmp ax, 0 jne ds1 mov cl, 13 mov eax,63 mov ebx, 1 mcall mov cl, 10 mov eax,63 mov ebx, 1 mcall ds1: pop esi inc esi jmp debug_print_string ind: dw 0 ; This is used for translating hex to ASCII for display or output hexchars db '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' IP_STR db 'xx',0 debug_print_rx_ip: pusha mov edi, IP_STR xor eax, eax mov al, bl shr al, 4 mov ah, [eax + hexchars] mov [edi], ah inc edi xor eax, eax mov al, bl and al, 0x0f mov ah, [eax + hexchars] mov [edi], ah mov esi, IP_STR call debug_print_string popa ret end if ; DATA AREA addr dd 0x0 ya dd 0x0 text: if lang eq ru db 'Имя хоста : xxxxxxxxxxxxxxx ' db 'DNS сервер : xxx.xxx.xxx.xxx ' db ' ' db ' Получить адрес ' db ' ' db ' ' db 'x <- END MARKER, DONT DELETE ' else db 'Host name : xxxxxxxxxxxxxxx ' db 'DNS server : xxx.xxx.xxx.xxx ' db ' ' db ' RESOLVE ADDRESS ' db ' ' db ' ' db 'x <- END MARKER, DONT DELETE ' end if if lang eq ru title db 'DNS Клиент',0 else title db 'DNS Client',0 end if prompt: dd 0 promptlen: dd 0 if lang eq ru p1: db 'Жду команды ' p1len: else p1: db 'Waiting for Command ' p1len: end if p4: db 'IP Address: . . . ' p4len: p5: db 'Resolving... ' p5len: dnsServer db '194.145.128.1 ' ; iolfree.ie DNS query db 'WWW.MENUETOS.NET ' hostIP: dd 0 dnsIP: dd 0 dnsMsgLen: dd 0 socketNum: dd 0xFFFF dnsMsg: I_END: