From 355d9a39883f8ff02b6dbf43620bfc4871070639 Mon Sep 17 00:00:00 2001 From: hidnplayr Date: Sun, 11 Jun 2017 11:13:52 +0000 Subject: [PATCH] Trace route program git-svn-id: svn://kolibrios.org@6923 a494cfbc-eb01-0410-851d-a64ba20cac60 --- programs/network/tracert/tracert.asm | 599 +++++++++++++++++++++++++++ 1 file changed, 599 insertions(+) create mode 100644 programs/network/tracert/tracert.asm diff --git a/programs/network/tracert/tracert.asm b/programs/network/tracert/tracert.asm new file mode 100644 index 0000000000..4b34e0c1b6 --- /dev/null +++ b/programs/network/tracert/tracert.asm @@ -0,0 +1,599 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; Copyright (C) KolibriOS team 2010-2017. All rights reserved. ;; +;; Distributed under terms of the GNU General Public License ;; +;; ;; +;; tracert.asm - Trace network route for KolibriOS ;; +;; ;; +;; Written by hidnplayr@kolibrios.org ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +format binary as "" + +BUFFERSIZE = 1500 +IDENTIFIER = 0x1337 + +__DEBUG__ = 1 ; enable/disable +__DEBUG_LEVEL__ = 2 ; 1 = all, 2 = errors + +use32 + org 0x0 + + db 'MENUET01' ; signature + dd 1 ; header version + dd START ; entry point + dd I_END ; initialized size + dd IM_END+0x1000 ; required memory + dd IM_END+0x1000 ; stack pointer + dd params ; parameters + dd 0 ; path + +include '../../proc32.inc' +include '../../macros.inc' +purge mov,add,sub +include '../../dll.inc' +include '../../struct.inc' +include '../../debug-fdo.inc' +include '../../network.inc' + +include '../icmp.inc' +include '../ip.inc' + + +START: +; init heap + mcall 68, 11 + test eax, eax + jz exit +; load libraries + stdcall dll.Load, @IMPORT + test eax, eax + jnz exit +; initialize console + push 1 + call [con_start] + push title + push 250 + push 80 + push 25 + push 80 + call [con_init] +; main loop + cmp byte[params], 0 + jne parse_param + + push str_welcome + call [con_write_asciiz] +main: +; write prompt + push str_prompt + call [con_write_asciiz] +; read string + mov esi, params + push 1024 + push esi + call [con_gets] +; check for exit + test eax, eax + jz exit + cmp byte [esi], 10 + jz exit +; delete terminating '\n' + push esi +@@: + lodsb + test al, al + jnz @b + mov [esi-2], al + pop esi + +parse_param: +; Check if any additional parameters were given + + DEBUGF 2, "parse parameters\n" + mov esi, params + mov ecx, 1024 + .addrloop: + lodsb + test al, al + jz .resolve + cmp al, ' ' + jne .addrloop + mov byte[esi-1], 0 + jmp .param + + .param_loop: + lodsb + test al, al + jz .resolve + cmp al, ' ' + jne .invalid + .param: + lodsb + cmp al, '-' + jne .invalid + lodsb + ; implement more parameters here + .invalid: + push str13 + call [con_write_asciiz] + jmp main + + .resolve: + DEBUGF 2, "resolve\n" +; resolve name + push esp ; reserve stack place + push esp ; fourth parameter + push 0 ; third parameter + push 0 ; second parameter + push params ; first parameter + call [getaddrinfo] + pop esi +; test for error + test eax, eax + jnz fail + +; convert IP address to decimal notation + mov eax, [esi+addrinfo.ai_addr] + mov eax, [eax+sockaddr_in.sin_addr] + mov [sockaddr1.ip], eax + push eax + call [inet_ntoa] +; write result + mov [ip_ptr], eax + + push eax + +; free allocated memory + push esi + call [freeaddrinfo] + + push str4 + call [con_write_asciiz] + + mcall socket, AF_INET4, SOCK_RAW, IPPROTO_ICMP + cmp eax, -1 + jz fail2 + mov [icmp_socket], eax + + mcall socket, AF_INET4, SOCK_DGRAM, 0 + cmp eax, -1 + jz fail2 + mov [udp_socket], eax + + mcall connect, [udp_socket], sockaddr1, 18 + cmp eax, -1 + je fail2 + + mcall 40, EVM_STACK + + push str3 + call [con_write_asciiz] + + push [ip_ptr] + call [con_write_asciiz] + + push str4 + call [con_write_asciiz] + + mov [ttl], 1 + + ;; mcall send, [udp_socket], udp_packet, 5, 0 ; dummy send + + mcall recv, [icmp_socket], buffer_ptr, BUFFERSIZE, MSG_DONTWAIT ;; dummy read + +mainloop: + call [con_get_flags] + test eax, 0x200 ; con window closed? + jnz exit_now + + pushd [ttl] + pushd str9 + call [con_printf] + add esp, 2*4 + + DEBUGF 2, "Setsockopt\n" + + pushd [ttl] + pushd 4 ; length of option + pushd IP_TTL + pushd IPPROTO_IP + mcall setsockopt, [udp_socket], esp + add esp, 16 + cmp eax, -1 + je fail2 + + DEBUGF 2, "Sending\n" + + mcall 26, 10 ; Get high precision timer count + mov [time_reference], eax + mcall send, [udp_socket], udp_packet, 5, 0 + cmp eax, -1 + je fail2 + + DEBUGF 2, "Packet sent\n", str_ini_int + + .receive: + mcall 23, [timeout] + + mcall 26, 10 ; Get high precision timer count + sub eax, [time_reference] + jz @f + xor edx, edx + mov ebx, 100000 + div ebx + cmp edx, 50000 + jb @f + inc eax + @@: + mov [time_reference], eax + +; Receive reply + mcall recv, [icmp_socket], buffer_ptr, BUFFERSIZE, MSG_DONTWAIT + cmp eax, -1 + je .timeout + test eax, eax + jz fail2 + + DEBUGF 2, "Answer after %u\n", eax + +; IP header length + movzx esi, byte[buffer_ptr] + and esi, 0xf + shl esi, 2 + +; Check packet length + sub eax, esi + sub eax, sizeof.ICMP_header + jb .invalid + mov [recvd], eax + + DEBUGF 2, "Packet length OK\n", eax + +; make esi point to ICMP packet header + add esi, buffer_ptr + +; Verify packet +;; movzx eax, [esi + sizeof.ICMP_header + IPv4_header.TimeToLive] +;; cmp eax, [ttl] +;; jne .receive + +; What kind of response is it? + cmp [esi + ICMP_header.Type], ICMP_UNREACH_PORT + je .last + cmp [esi + ICMP_header.Type], ICMP_TIMXCEED + jne .invalid + call .print + jmp .continue + + .last: + call .print + jmp main + + .print: + DEBUGF 2, "Valid response\n" +; we have a response, print a line + mov eax, [time_reference] + xor edx, edx + mov ebx, 10 + div ebx + push edx + push eax + + push str1 + call [con_printf] + add esp, 3*4 + + mov ebx, [buffer_ptr + IPv4_header.SourceAddress] + push ebx + call reverse_dns_lookup + + pop eax + rol eax, 16 + movzx ebx, ah + push ebx + movzx ebx, al + push ebx + shr eax, 16 + movzx ebx, ah + push ebx + movzx ebx, al + push ebx + + push str2 + call [con_printf] + add esp, 5*4 + + ret + + +; Invalid reply + .invalid: + DEBUGF 2, "Invalid response\n" + push str10 + call [con_write_asciiz] + jmp main ;.continue + +; Timeout! + .timeout: + DEBUGF 2, "Timeout\n", eax + push str8 + call [con_write_asciiz] + +; Send more ICMP packets ? + .continue: + inc [ttl] + +; wait a second before sending next request + mcall 5, 100 + jmp mainloop + +; DNS error +fail: + push str5 + call [con_write_asciiz] + jmp main + +; Socket error +fail2: + push str6 + call [con_write_asciiz] + jmp main + +; Finally.. exit! +exit: + push 1 + call [con_exit] +exit_now: + mcall -1 + + +ascii_to_dec: + + lodsb + cmp al, ' ' + jne .fail + + xor eax, eax + xor ebx, ebx + .loop: + lodsb + test al, al + jz .done + cmp al, ' ' + je .done + sub al, '0' + jb .fail + cmp al, 9 + ja .fail + lea ebx, [ebx*4+ebx] + lea ebx, [ebx*2+eax] + jmp .loop + .fail: + xor ebx, ebx + .done: + dec esi + ret + + +; ebx = ip +reverse_dns_lookup: + + push ebx + mcall socket, AF_INET4, SOCK_DGRAM, 0 + pop ebx + cmp eax, -1 + je .fail + mov [dns_socket], eax + + push ebx + mcall connect, [dns_socket], sockaddr2, 18 + pop ebx + cmp eax, -1 + je .fail + + mov edi, dns_pkt.name + rol ebx, 8 + movzx eax, bl + call byte_to_ascii + rol ebx, 8 + movzx eax, bl + call byte_to_ascii + rol ebx, 8 + movzx eax, bl + call byte_to_ascii + rol ebx, 8 + movzx eax, bl + call byte_to_ascii + + mov esi, dns_tr + mov ecx, dns_tr.length + rep movsb + + sub edi, dns_pkt + mov esi, edi + + mcall send, [dns_socket], dns_pkt, , 0 + cmp eax, -1 + je .fail + + push esi + mcall recv, [dns_socket], buffer_ptr, BUFFERSIZE, 0 + pop esi + + mcall close, [dns_socket] + + cmp word[buffer_ptr+6], 0 ; answers + je .fail + + add esi, buffer_ptr+12 + mov edi, buffer_ptr + xor ecx, ecx + lodsb + test al, al + jz @f + movzx ecx, al + @@: + rep movsb + lodsb + test al, al + jz @f + movzx ecx, al + mov al, '.' + stosb + jmp @r + @@: + stosb + + push buffer_ptr + call [con_write_asciiz] + + push str7 + call [con_write_asciiz] + + ret + + .fail: + ret + + + +; input: eax - number +; edi - ptr +byte_to_ascii: + + push ebx ecx edx + + xor edx, edx ; result + xor ecx, ecx ; byte count + inc ecx + mov bl, 10 ; divisor + + div bl + mov dl, ah + add dl, '0' + and ax, 0x00ff + jz .ok + + inc ecx + shl edx, 8 + + div bl + mov dl, ah + add dl, '0' + and ax, 0x00ff + jz .ok + + inc ecx + shl edx, 8 + + mov dl, al + add dl, '0' + + .ok: + shl edx, 8 + mov dl, cl + mov [edi], edx + add edi, ecx + inc edi + + pop edx ecx ebx + ret + + +; data +title db 'Trace route',0 +str_welcome db 'Please enter the hostname or IP-address of the host you want to trace,',10 + db 'or just press enter to exit.',10,10,0 +str_prompt db 10,'> ',0 +str3 db 'Tracing route to ',0 + +str4 db 10,0 +str7 db ' ', 0 +str5 db 'Name resolution failed.',10,0 +str6 db 'Socket error.',10,0 +str13 db 'Invalid parameter(s)',10,0 + +str9 db '%u ',0 +str1 db '%u.%u ms ',0 +str2 db '[%u.%u.%u.%u]',10,0 +str10 db 'Invalid reply',10,0 +str8 db 'Timeout!',10,0 + + +sockaddr1: + dw AF_INET4 +.port dw 666 +.ip dd 0 + rb 10 + +sockaddr2: + dw AF_INET4 +.port dw 53 shl 8 ; DNS port +.ip dd 0x08080808 ; Google DNS + rb 10 + +time_reference dd ? +ip_ptr dd ? +ttl dd ? +timeout dd 500 +recvd dd ? ; received number of bytes in last packet + +; import +align 4 +@IMPORT: + +library console, 'console.obj', \ + network, 'network.obj' + +import console, \ + con_start, 'START', \ + con_init, 'con_init', \ + con_write_asciiz, 'con_write_asciiz', \ + con_printf, 'con_printf', \ + con_exit, 'con_exit', \ + con_gets, 'con_gets',\ + con_cls, 'con_cls',\ + con_getch2, 'con_getch2',\ + con_set_cursor_pos, 'con_set_cursor_pos',\ + con_get_flags, 'con_get_flags' + +import network, \ + getaddrinfo, 'getaddrinfo', \ + freeaddrinfo, 'freeaddrinfo', \ + inet_ntoa, 'inet_ntoa' + +include_debug_strings + +icmp_socket dd ? +udp_socket dd ? +dns_socket dd ? + +udp_packet db 'hello!' + +dns_tr: + db 7,'in-addr',4,'arpa',0 + dw 0x0C00 ; Qtype: PTR + dw 0x0100 ; Class: IN + + .length = $ - dns_tr + +dns_pkt: + dw 0x9A02 ; Transaction ID + dw 0x0001 ; Flags: Recursive desired + dw 0x0100 ; Questions + dw 0x0000 ; Answers + dw 0x0000 ; Authority RR + dw 0x0000 ; Additional RR + .name rb 512 + +I_END: + +params rb 1024 +buffer_ptr: rb BUFFERSIZE + +IM_END: