12,8 → 12,6 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
; TODO: ttl, user selectable size/number of packets |
|
format binary as "" |
|
BUFFERSIZE = 1500 |
28,7 → 26,7 |
dd I_END ; initialized size |
dd IM_END+0x1000 ; required memory |
dd IM_END+0x1000 ; stack pointer |
dd s ; parameters |
dd params ; parameters |
dd 0 ; path |
|
include '../../proc32.inc' |
35,9 → 33,11 |
include '../../macros.inc' |
purge mov,add,sub |
include '../../dll.inc' |
include '../../struct.inc' |
include '../../network.inc' |
|
include 'icmp.inc' |
include 'ip.inc' |
|
|
START: |
53,13 → 53,28 |
push 1 |
call [con_start] |
push title |
push 25 |
push 250 |
push 80 |
push 25 |
push 80 |
call [con_init] |
; expand payload to 65504 bytes |
mov edi, icmp_packet.data+32 |
mov ecx, 65504/32-1 |
.expand_payload: |
mov esi, icmp_packet.data |
movsd |
movsd |
movsd |
movsd |
movsd |
movsd |
movsd |
movsd |
dec ecx |
jnz .expand_payload |
; main loop |
cmp byte[s], 0 |
cmp byte[params], 0 |
jne parse_param |
|
push str_welcome |
69,8 → 84,8 |
push str_prompt |
call [con_write_asciiz] |
; read string |
mov esi, s |
push 256 |
mov esi, params |
push 1024 |
push esi |
call [con_gets] |
; check for exit |
93,10 → 108,14 |
mov [stats.time], 0 |
|
parse_param: |
mov [count], 4 ; default number of pings to send |
; parameters defaults |
mov [count], 4 |
mov [size], 32 |
mov [ttl], 128 |
mov [timeout], 300 |
|
; Check if any additional parameters were given |
mov esi, s |
mov esi, params |
mov ecx, 1024 |
.addrloop: |
lodsb |
123,6 → 142,42 |
mov [count], -1 ; infinite |
jmp .param_loop |
@@: |
cmp al, 'n' |
jne @f |
call ascii_to_dec |
test ebx, ebx |
jz .invalid |
mov [count], ebx |
jmp .param_loop |
@@: |
cmp al, 'l' |
jne @f |
call ascii_to_dec |
test ebx, ebx |
jz .invalid |
cmp ebx, 65500 |
ja .invalid |
mov [size], ebx |
jmp .param_loop |
@@: |
cmp al, 'i' |
jne @f |
call ascii_to_dec |
test ebx, ebx |
jz .invalid |
cmp ebx, 255 |
ja .invalid |
mov [ttl], ebx |
jmp .param_loop |
@@: |
cmp al, 'w' |
jne @f |
call ascii_to_dec |
test ebx, ebx |
jz .invalid |
mov [timeout], ebx |
jmp .param_loop |
@@: |
; implement more parameters here |
.invalid: |
push str13 |
135,7 → 190,7 |
push esp ; fourth parameter |
push 0 ; third parameter |
push 0 ; second parameter |
push s ; first parameter |
push params ; first parameter |
call [getaddrinfo] |
pop esi |
; test for error |
166,9 → 221,19 |
mov [socketnum], eax |
|
mcall connect, [socketnum], sockaddr1, 18 |
cmp eax, -1 |
je fail2 |
|
pushd [ttl] |
pushd 4 ; length of option |
pushd IP_TTL |
pushd IPPROTO_IP |
mcall setsockopt, [socketnum], esp |
add esp, 16 |
cmp eax, -1 |
je fail2 |
|
mcall 40, EVM_STACK |
; call [con_cls] |
|
push str3 |
call [con_write_asciiz] |
176,9 → 241,10 |
push [ip_ptr] |
call [con_write_asciiz] |
|
push (icmp_packet.length - ICMP_Packet.Data) |
push [size] |
push str3b |
call [con_printf] |
add esp, 2*4 |
|
mainloop: |
call [con_get_flags] |
188,9 → 254,14 |
inc [stats.tx] |
mcall 26, 10 ; Get high precision timer count |
mov [time_reference], eax |
mcall send, [socketnum], icmp_packet, icmp_packet.length, 0 |
mov esi, [size] |
add esi, sizeof.ICMP_header |
xor edi, edi |
mcall send, [socketnum], icmp_packet |
cmp eax, -1 |
je fail2 |
|
mcall 23, 300 ; 3 seconds time-out |
mcall 23, [timeout] |
mcall 26, 10 ; Get high precision timer count |
sub eax, [time_reference] |
jz @f |
203,54 → 274,102 |
@@: |
mov [time_reference], eax |
|
; Receive reply |
mcall recv, [socketnum], buffer_ptr, BUFFERSIZE, MSG_DONTWAIT |
cmp eax, -1 |
je .no_response |
test eax, eax |
jz fail2 |
|
sub eax, ICMP_Packet.Data |
; 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 |
|
cmp word[buffer_ptr + ICMP_Packet.Identifier], IDENTIFIER |
jne .invalid |
; make esi point to ICMP packet header |
add esi, buffer_ptr |
|
; OK, we have a response, update stats and let the user know |
inc [stats.rx] |
mov eax, [time_reference] |
add [stats.time], eax |
; we have a response, print the sender IP |
push esi |
mov eax, [buffer_ptr + IPv4_header.SourceAddress] |
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 str11 |
call [con_printf] |
add esp, 5*4 |
pop esi |
|
push str11 ; TODO: print IP address of packet sender |
call [con_write_asciiz] |
; What kind of response is it? |
cmp [esi + ICMP_header.Type], ICMP_ECHOREPLY |
je .echo_reply |
cmp [esi + ICMP_header.Type], ICMP_TIMXCEED |
je .ttl_exceeded |
|
; validate the packet |
lea esi, [buffer_ptr + ICMP_Packet.Data] |
mov ecx, [recvd] |
jmp .invalid |
|
|
.echo_reply: |
|
cmp [esi + ICMP_header.Identifier], IDENTIFIER |
jne .invalid |
|
; Validate the packet |
add esi, sizeof.ICMP_header |
mov ecx, [size] |
mov edi, icmp_packet.data |
repe cmpsb |
jne .miscomp |
|
; All OK, print to the user! |
; update stats |
inc [stats.rx] |
mov eax, [time_reference] |
add [stats.time], eax |
|
movzx eax, [buffer_ptr + IPv4_header.TimeToLive] |
push eax |
mov eax, [time_reference] |
xor edx, edx |
mov ebx, 10 |
div ebx |
push edx |
push eax |
; movzx eax, word[buffer_ptr + ICMP_Packet.SequenceNumber] |
; push eax |
push [recvd] |
|
push str7 |
call [con_printf] |
add esp, 5*4 |
|
jmp .continue |
|
|
.ttl_exceeded: |
push str14 |
call [con_write_asciiz] |
|
jmp .continue |
|
|
; Error in packet, print it to user |
.miscomp: |
sub edi, icmp_packet.data |
sub edi, icmp_packet.data+1 |
push edi |
push str9 |
call [con_printf] |
add esp, 2*4 |
jmp .continue |
|
; Invalid reply |
271,14 → 390,14 |
cmp [count], -1 |
je .forever |
dec [count] |
jz done |
jz .stats |
.forever: |
mcall 5, 100 ; wait a second |
|
; wait a second before sending next request |
mcall 5, 100 |
jmp mainloop |
|
; Done.. |
done: |
; Print statistics |
.stats: |
cmp [stats.rx], 0 |
jne @f |
xor eax, eax |
298,6 → 417,7 |
push [stats.tx] |
push str12 |
call [con_printf] |
add esp, 5*4 |
jmp main |
|
; DNS error |
320,10 → 440,46 |
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 |
|
|
|
|
; data |
title db 'ICMP echo (ping) client',0 |
str_welcome db 'Please enter the hostname or IP-address of the host you want to ping,',10 |
db 'or just press enter to exit.',10,0 |
db 'or just press enter to exit.',10,10 |
db 'Options:',10 |
db ' -t Send packets till users abort.',10 |
db ' -n number Number of requests to send.',10 |
db ' -i TTL Time to live.',10 |
db ' -l size Size of echo request.',10 |
db ' -w time-out Time-out in hundredths of a second.',10,0 |
str_prompt db 10,'> ',0 |
str3 db 'Pinging to ',0 |
str3b db ' with %u data bytes',10,0 |
330,14 → 486,15 |
|
str4 db 10,0 |
str5 db 'Name resolution failed.',10,0 |
str6 db 'Could not open socket',10,0 |
str6 db 'Socket error.',10,0 |
str13 db 'Invalid parameter(s)',10,0 |
|
str11 db 'Answer: ',0 |
str7 db 'bytes=%u time=%u.%u ms',10,0 |
str11 db 'Answer from %u.%u.%u.%u: ',0 |
str7 db 'bytes=%u time=%u.%u ms TTL=%u',10,0 |
str8 db 'Timeout',10,0 |
str9 db 'Miscompare at offset %u',10,0 |
str10 db 'Invalid reply',10,0 |
str9 db 'miscompare at offset %u.',10,0 |
str10 db 'invalid reply.',10,0 |
str14 db 'TTL expired.',10,0 |
|
str12 db 10,'Statistics:',10,'%u packets sent, %u packets received',10,'average response time=%u.%u ms',10,0 |
|
350,6 → 507,9 |
time_reference dd ? |
ip_ptr dd ? |
count dd ? |
size dd ? |
ttl dd ? |
timeout dd ? |
recvd dd ? ; received number of bytes in last packet |
|
stats: |
381,18 → 541,17 |
|
socketnum dd ? |
|
icmp_packet db 8 ; type |
icmp_packet db ICMP_ECHO ; type |
db 0 ; code |
dw 0 ; |
dw 0 ; checksum |
.id dw IDENTIFIER ; identifier |
.seq dw 0x0000 ; sequence number |
.data db 'abcdefghijklmnopqrstuvwxyz012345' |
.length = $ - icmp_packet |
|
I_END: |
rb 65504-32 |
|
s db 0 |
rb 1024 |
buffer_ptr rb BUFFERSIZE |
params rb 1024 |
buffer_ptr: rb BUFFERSIZE |
|
IM_END: |