Rev 6029 | Rev 7891 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
3545 | hidnplayr | 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
2 | ;; ;; |
||
5805 | hidnplayr | 3 | ;; Copyright (C) KolibriOS team 2010-2015. All rights reserved. ;; |
3545 | hidnplayr | 4 | ;; Distributed under terms of the GNU General Public License ;; |
5 | ;; ;; |
||
6 | ;; ping.asm - ICMP echo client for KolibriOS ;; |
||
7 | ;; ;; |
||
8 | ;; Written by hidnplayr@kolibrios.org ;; |
||
9 | ;; ;; |
||
10 | ;; GNU GENERAL PUBLIC LICENSE ;; |
||
11 | ;; Version 2, June 1991 ;; |
||
12 | ;; ;; |
||
13 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
14 | |||
15 | format binary as "" |
||
16 | |||
3618 | hidnplayr | 17 | BUFFERSIZE = 1500 |
4012 | hidnplayr | 18 | IDENTIFIER = 0x1337 |
3618 | hidnplayr | 19 | |
3545 | hidnplayr | 20 | use32 |
21 | org 0x0 |
||
22 | |||
23 | db 'MENUET01' ; signature |
||
24 | dd 1 ; header version |
||
5805 | hidnplayr | 25 | dd START ; entry point |
3545 | hidnplayr | 26 | dd I_END ; initialized size |
5805 | hidnplayr | 27 | dd IM_END+0x1000 ; required memory |
28 | dd IM_END+0x1000 ; stack pointer |
||
5842 | hidnplayr | 29 | dd params ; parameters |
3545 | hidnplayr | 30 | dd 0 ; path |
31 | |||
5805 | hidnplayr | 32 | include '../../proc32.inc' |
3618 | hidnplayr | 33 | include '../../macros.inc' |
3545 | hidnplayr | 34 | purge mov,add,sub |
3618 | hidnplayr | 35 | include '../../dll.inc' |
5842 | hidnplayr | 36 | include '../../struct.inc' |
3618 | hidnplayr | 37 | include '../../network.inc' |
3545 | hidnplayr | 38 | |
6477 | hidnplayr | 39 | include '../icmp.inc' |
40 | include '../ip.inc' |
||
3545 | hidnplayr | 41 | |
42 | |||
5805 | hidnplayr | 43 | START: |
44 | ; init heap |
||
45 | mcall 68, 11 |
||
46 | test eax, eax |
||
47 | jz exit |
||
3545 | hidnplayr | 48 | ; load libraries |
49 | stdcall dll.Load, @IMPORT |
||
50 | test eax, eax |
||
51 | jnz exit |
||
52 | ; initialize console |
||
53 | push 1 |
||
54 | call [con_start] |
||
55 | push title |
||
5842 | hidnplayr | 56 | push 250 |
3545 | hidnplayr | 57 | push 80 |
58 | push 25 |
||
59 | push 80 |
||
60 | call [con_init] |
||
5842 | hidnplayr | 61 | ; expand payload to 65504 bytes |
62 | mov edi, icmp_packet.data+32 |
||
63 | mov ecx, 65504/32-1 |
||
64 | .expand_payload: |
||
65 | mov esi, icmp_packet.data |
||
66 | movsd |
||
67 | movsd |
||
68 | movsd |
||
69 | movsd |
||
70 | movsd |
||
71 | movsd |
||
72 | movsd |
||
73 | movsd |
||
74 | dec ecx |
||
75 | jnz .expand_payload |
||
3545 | hidnplayr | 76 | ; main loop |
5842 | hidnplayr | 77 | cmp byte[params], 0 |
5249 | hidnplayr | 78 | jne parse_param |
4019 | hidnplayr | 79 | |
80 | push str_welcome |
||
81 | call [con_write_asciiz] |
||
3545 | hidnplayr | 82 | main: |
83 | ; write prompt |
||
4019 | hidnplayr | 84 | push str_prompt |
3545 | hidnplayr | 85 | call [con_write_asciiz] |
86 | ; read string |
||
5842 | hidnplayr | 87 | mov esi, params |
88 | push 1024 |
||
3545 | hidnplayr | 89 | push esi |
90 | call [con_gets] |
||
91 | ; check for exit |
||
92 | test eax, eax |
||
4024 | hidnplayr | 93 | jz exit |
3545 | hidnplayr | 94 | cmp byte [esi], 10 |
4024 | hidnplayr | 95 | jz exit |
3545 | hidnplayr | 96 | ; delete terminating '\n' |
97 | push esi |
||
98 | @@: |
||
99 | lodsb |
||
100 | test al, al |
||
101 | jnz @b |
||
5805 | hidnplayr | 102 | mov [esi-2], al |
3545 | hidnplayr | 103 | pop esi |
104 | |||
4019 | hidnplayr | 105 | ; reset stats |
106 | mov [stats.tx], 0 |
||
107 | mov [stats.rx], 0 |
||
108 | mov [stats.time], 0 |
||
109 | |||
5249 | hidnplayr | 110 | parse_param: |
5842 | hidnplayr | 111 | ; parameters defaults |
112 | mov [count], 4 |
||
113 | mov [size], 32 |
||
114 | mov [ttl], 128 |
||
115 | mov [timeout], 300 |
||
5249 | hidnplayr | 116 | |
117 | ; Check if any additional parameters were given |
||
5842 | hidnplayr | 118 | mov esi, params |
5249 | hidnplayr | 119 | mov ecx, 1024 |
120 | .addrloop: |
||
121 | lodsb |
||
122 | test al, al |
||
123 | jz .resolve |
||
124 | cmp al, ' ' |
||
125 | jne .addrloop |
||
126 | mov byte[esi-1], 0 |
||
127 | jmp .param |
||
128 | |||
129 | .param_loop: |
||
130 | lodsb |
||
131 | test al, al |
||
132 | jz .resolve |
||
133 | cmp al, ' ' |
||
134 | jne .invalid |
||
135 | .param: |
||
136 | lodsb |
||
137 | cmp al, '-' |
||
138 | jne .invalid |
||
139 | lodsb |
||
140 | cmp al, 't' |
||
141 | jne @f |
||
142 | mov [count], -1 ; infinite |
||
143 | jmp .param_loop |
||
144 | @@: |
||
5842 | hidnplayr | 145 | cmp al, 'n' |
146 | jne @f |
||
147 | call ascii_to_dec |
||
148 | test ebx, ebx |
||
149 | jz .invalid |
||
150 | mov [count], ebx |
||
151 | jmp .param_loop |
||
152 | @@: |
||
153 | cmp al, 'l' |
||
154 | jne @f |
||
155 | call ascii_to_dec |
||
156 | test ebx, ebx |
||
157 | jz .invalid |
||
158 | cmp ebx, 65500 |
||
159 | ja .invalid |
||
160 | mov [size], ebx |
||
161 | jmp .param_loop |
||
162 | @@: |
||
163 | cmp al, 'i' |
||
164 | jne @f |
||
165 | call ascii_to_dec |
||
166 | test ebx, ebx |
||
167 | jz .invalid |
||
168 | cmp ebx, 255 |
||
169 | ja .invalid |
||
170 | mov [ttl], ebx |
||
171 | jmp .param_loop |
||
172 | @@: |
||
173 | cmp al, 'w' |
||
174 | jne @f |
||
175 | call ascii_to_dec |
||
176 | test ebx, ebx |
||
177 | jz .invalid |
||
178 | mov [timeout], ebx |
||
179 | jmp .param_loop |
||
180 | @@: |
||
5249 | hidnplayr | 181 | ; implement more parameters here |
182 | .invalid: |
||
183 | push str13 |
||
184 | call [con_write_asciiz] |
||
185 | jmp main |
||
186 | |||
187 | .resolve: |
||
3545 | hidnplayr | 188 | ; resolve name |
189 | push esp ; reserve stack place |
||
190 | push esp ; fourth parameter |
||
191 | push 0 ; third parameter |
||
192 | push 0 ; second parameter |
||
5842 | hidnplayr | 193 | push params ; first parameter |
3545 | hidnplayr | 194 | call [getaddrinfo] |
195 | pop esi |
||
196 | ; test for error |
||
197 | test eax, eax |
||
198 | jnz fail |
||
199 | |||
200 | ; convert IP address to decimal notation |
||
201 | mov eax, [esi+addrinfo.ai_addr] |
||
202 | mov eax, [eax+sockaddr_in.sin_addr] |
||
203 | mov [sockaddr1.ip], eax |
||
204 | push eax |
||
205 | call [inet_ntoa] |
||
206 | ; write result |
||
207 | mov [ip_ptr], eax |
||
208 | |||
209 | push eax |
||
210 | |||
211 | ; free allocated memory |
||
212 | push esi |
||
213 | call [freeaddrinfo] |
||
214 | |||
215 | push str4 |
||
216 | call [con_write_asciiz] |
||
217 | |||
218 | mcall socket, AF_INET4, SOCK_RAW, IPPROTO_ICMP |
||
219 | cmp eax, -1 |
||
220 | jz fail2 |
||
221 | mov [socketnum], eax |
||
222 | |||
223 | mcall connect, [socketnum], sockaddr1, 18 |
||
5842 | hidnplayr | 224 | cmp eax, -1 |
225 | je fail2 |
||
3545 | hidnplayr | 226 | |
5842 | hidnplayr | 227 | pushd [ttl] |
228 | pushd 4 ; length of option |
||
229 | pushd IP_TTL |
||
230 | pushd IPPROTO_IP |
||
231 | mcall setsockopt, [socketnum], esp |
||
232 | add esp, 16 |
||
233 | cmp eax, -1 |
||
234 | je fail2 |
||
235 | |||
5805 | hidnplayr | 236 | mcall 40, EVM_STACK |
3545 | hidnplayr | 237 | |
238 | push str3 |
||
239 | call [con_write_asciiz] |
||
4012 | hidnplayr | 240 | |
3545 | hidnplayr | 241 | push [ip_ptr] |
242 | call [con_write_asciiz] |
||
243 | |||
5842 | hidnplayr | 244 | push [size] |
4012 | hidnplayr | 245 | push str3b |
246 | call [con_printf] |
||
5842 | hidnplayr | 247 | add esp, 2*4 |
4012 | hidnplayr | 248 | |
249 | mainloop: |
||
5249 | hidnplayr | 250 | call [con_get_flags] |
251 | test eax, 0x200 ; con window closed? |
||
252 | jnz exit_now |
||
253 | |||
4012 | hidnplayr | 254 | inc [stats.tx] |
5805 | hidnplayr | 255 | mcall 26, 10 ; Get high precision timer count |
3545 | hidnplayr | 256 | mov [time_reference], eax |
5842 | hidnplayr | 257 | mov esi, [size] |
258 | add esi, sizeof.ICMP_header |
||
259 | xor edi, edi |
||
260 | mcall send, [socketnum], icmp_packet |
||
261 | cmp eax, -1 |
||
262 | je fail2 |
||
3545 | hidnplayr | 263 | |
5842 | hidnplayr | 264 | mcall 23, [timeout] |
5805 | hidnplayr | 265 | mcall 26, 10 ; Get high precision timer count |
4014 | hidnplayr | 266 | sub eax, [time_reference] |
5805 | hidnplayr | 267 | jz @f |
4014 | hidnplayr | 268 | xor edx, edx |
5805 | hidnplayr | 269 | mov ebx, 100000 |
270 | div ebx |
||
271 | cmp edx, 50000 |
||
272 | jb @f |
||
273 | inc eax |
||
274 | @@: |
||
4014 | hidnplayr | 275 | mov [time_reference], eax |
3545 | hidnplayr | 276 | |
5842 | hidnplayr | 277 | ; Receive reply |
4012 | hidnplayr | 278 | mcall recv, [socketnum], buffer_ptr, BUFFERSIZE, MSG_DONTWAIT |
3545 | hidnplayr | 279 | cmp eax, -1 |
280 | je .no_response |
||
5842 | hidnplayr | 281 | test eax, eax |
282 | jz fail2 |
||
3545 | hidnplayr | 283 | |
5842 | hidnplayr | 284 | ; IP header length |
285 | movzx esi, byte[buffer_ptr] |
||
286 | and esi, 0xf |
||
287 | shl esi, 2 |
||
288 | |||
289 | ; Check packet length |
||
290 | sub eax, esi |
||
291 | sub eax, sizeof.ICMP_header |
||
4469 | hidnplayr | 292 | jb .invalid |
4012 | hidnplayr | 293 | mov [recvd], eax |
294 | |||
5842 | hidnplayr | 295 | ; make esi point to ICMP packet header |
296 | add esi, buffer_ptr |
||
4012 | hidnplayr | 297 | |
5842 | hidnplayr | 298 | ; we have a response, print the sender IP |
299 | push esi |
||
300 | mov eax, [buffer_ptr + IPv4_header.SourceAddress] |
||
301 | rol eax, 16 |
||
302 | movzx ebx, ah |
||
303 | push ebx |
||
304 | movzx ebx, al |
||
305 | push ebx |
||
306 | shr eax, 16 |
||
307 | movzx ebx, ah |
||
308 | push ebx |
||
309 | movzx ebx, al |
||
310 | push ebx |
||
311 | push str11 |
||
312 | call [con_printf] |
||
313 | add esp, 5*4 |
||
314 | pop esi |
||
4012 | hidnplayr | 315 | |
5842 | hidnplayr | 316 | ; What kind of response is it? |
317 | cmp [esi + ICMP_header.Type], ICMP_ECHOREPLY |
||
318 | je .echo_reply |
||
319 | cmp [esi + ICMP_header.Type], ICMP_TIMXCEED |
||
320 | je .ttl_exceeded |
||
4012 | hidnplayr | 321 | |
5842 | hidnplayr | 322 | jmp .invalid |
323 | |||
324 | |||
325 | .echo_reply: |
||
326 | |||
327 | cmp [esi + ICMP_header.Identifier], IDENTIFIER |
||
328 | jne .invalid |
||
329 | |||
330 | ; Validate the packet |
||
331 | add esi, sizeof.ICMP_header |
||
332 | mov ecx, [size] |
||
3545 | hidnplayr | 333 | mov edi, icmp_packet.data |
4012 | hidnplayr | 334 | repe cmpsb |
3545 | hidnplayr | 335 | jne .miscomp |
336 | |||
5842 | hidnplayr | 337 | ; update stats |
338 | inc [stats.rx] |
||
5805 | hidnplayr | 339 | mov eax, [time_reference] |
5842 | hidnplayr | 340 | add [stats.time], eax |
341 | |||
342 | movzx eax, [buffer_ptr + IPv4_header.TimeToLive] |
||
343 | push eax |
||
344 | mov eax, [time_reference] |
||
5805 | hidnplayr | 345 | xor edx, edx |
346 | mov ebx, 10 |
||
347 | div ebx |
||
348 | push edx |
||
4012 | hidnplayr | 349 | push eax |
350 | push [recvd] |
||
351 | |||
3545 | hidnplayr | 352 | push str7 |
353 | call [con_printf] |
||
5842 | hidnplayr | 354 | add esp, 5*4 |
3545 | hidnplayr | 355 | |
4469 | hidnplayr | 356 | jmp .continue |
3545 | hidnplayr | 357 | |
5842 | hidnplayr | 358 | |
359 | .ttl_exceeded: |
||
360 | push str14 |
||
361 | call [con_write_asciiz] |
||
362 | |||
363 | jmp .continue |
||
364 | |||
365 | |||
4012 | hidnplayr | 366 | ; Error in packet, print it to user |
3545 | hidnplayr | 367 | .miscomp: |
5842 | hidnplayr | 368 | sub edi, icmp_packet.data+1 |
3545 | hidnplayr | 369 | push edi |
370 | push str9 |
||
371 | call [con_printf] |
||
5842 | hidnplayr | 372 | add esp, 2*4 |
4469 | hidnplayr | 373 | jmp .continue |
3545 | hidnplayr | 374 | |
4469 | hidnplayr | 375 | ; Invalid reply |
376 | .invalid: |
||
377 | push str10 |
||
378 | call [con_write_asciiz] |
||
379 | jmp .continue |
||
380 | |||
4012 | hidnplayr | 381 | ; Timeout! |
3545 | hidnplayr | 382 | .no_response: |
383 | push str8 |
||
384 | call [con_write_asciiz] |
||
385 | |||
4012 | hidnplayr | 386 | ; Send more ICMP packets ? |
4469 | hidnplayr | 387 | .continue: |
4435 | hidnplayr | 388 | inc [icmp_packet.seq] |
389 | |||
5249 | hidnplayr | 390 | cmp [count], -1 |
391 | je .forever |
||
3545 | hidnplayr | 392 | dec [count] |
5842 | hidnplayr | 393 | jz .stats |
5249 | hidnplayr | 394 | .forever: |
5842 | hidnplayr | 395 | ; wait a second before sending next request |
396 | mcall 5, 100 |
||
3545 | hidnplayr | 397 | jmp mainloop |
398 | |||
5842 | hidnplayr | 399 | ; Print statistics |
400 | .stats: |
||
4019 | hidnplayr | 401 | cmp [stats.rx], 0 |
402 | jne @f |
||
403 | xor eax, eax |
||
5805 | hidnplayr | 404 | xor edx, edx |
4019 | hidnplayr | 405 | jmp .zero |
406 | @@: |
||
4012 | hidnplayr | 407 | xor edx, edx |
408 | mov eax, [stats.time] |
||
409 | div [stats.rx] |
||
5805 | hidnplayr | 410 | xor edx, edx |
411 | mov ebx, 10 |
||
412 | div ebx |
||
4019 | hidnplayr | 413 | .zero: |
5805 | hidnplayr | 414 | push edx |
4012 | hidnplayr | 415 | push eax |
416 | push [stats.rx] |
||
417 | push [stats.tx] |
||
418 | push str12 |
||
419 | call [con_printf] |
||
5842 | hidnplayr | 420 | add esp, 5*4 |
4019 | hidnplayr | 421 | jmp main |
3545 | hidnplayr | 422 | |
4012 | hidnplayr | 423 | ; DNS error |
3545 | hidnplayr | 424 | fail: |
425 | push str5 |
||
426 | call [con_write_asciiz] |
||
4019 | hidnplayr | 427 | jmp main |
4012 | hidnplayr | 428 | |
429 | ; Socket error |
||
3545 | hidnplayr | 430 | fail2: |
431 | push str6 |
||
432 | call [con_write_asciiz] |
||
4019 | hidnplayr | 433 | jmp main |
3545 | hidnplayr | 434 | |
4019 | hidnplayr | 435 | ; Finally.. exit! |
436 | exit: |
||
437 | push 1 |
||
438 | call [con_exit] |
||
5249 | hidnplayr | 439 | exit_now: |
4019 | hidnplayr | 440 | mcall -1 |
441 | |||
442 | |||
5842 | hidnplayr | 443 | ascii_to_dec: |
444 | |||
445 | lodsb |
||
446 | cmp al, ' ' |
||
447 | jne .fail |
||
448 | |||
449 | xor eax, eax |
||
450 | xor ebx, ebx |
||
451 | .loop: |
||
452 | lodsb |
||
453 | test al, al |
||
454 | jz .done |
||
455 | cmp al, ' ' |
||
456 | je .done |
||
457 | sub al, '0' |
||
458 | jb .fail |
||
459 | cmp al, 9 |
||
460 | ja .fail |
||
461 | lea ebx, [ebx*4+ebx] |
||
462 | lea ebx, [ebx*2+eax] |
||
463 | jmp .loop |
||
464 | .fail: |
||
465 | xor ebx, ebx |
||
466 | .done: |
||
467 | dec esi |
||
468 | ret |
||
469 | |||
470 | |||
471 | |||
472 | |||
3545 | hidnplayr | 473 | ; data |
4019 | hidnplayr | 474 | title db 'ICMP echo (ping) client',0 |
475 | str_welcome db 'Please enter the hostname or IP-address of the host you want to ping,',10 |
||
5842 | hidnplayr | 476 | db 'or just press enter to exit.',10,10 |
477 | db 'Options:',10 |
||
478 | db ' -t Send packets till users abort.',10 |
||
479 | db ' -n number Number of requests to send.',10 |
||
480 | db ' -i TTL Time to live.',10 |
||
481 | db ' -l size Size of echo request.',10 |
||
482 | db ' -w time-out Time-out in hundredths of a second.',10,0 |
||
4019 | hidnplayr | 483 | str_prompt db 10,'> ',0 |
4012 | hidnplayr | 484 | str3 db 'Pinging to ',0 |
485 | str3b db ' with %u data bytes',10,0 |
||
486 | |||
3545 | hidnplayr | 487 | str4 db 10,0 |
488 | str5 db 'Name resolution failed.',10,0 |
||
5842 | hidnplayr | 489 | str6 db 'Socket error.',10,0 |
5249 | hidnplayr | 490 | str13 db 'Invalid parameter(s)',10,0 |
4012 | hidnplayr | 491 | |
5842 | hidnplayr | 492 | str11 db 'Answer from %u.%u.%u.%u: ',0 |
493 | str7 db 'bytes=%u time=%u.%u ms TTL=%u',10,0 |
||
5805 | hidnplayr | 494 | str8 db 'Timeout',10,0 |
5842 | hidnplayr | 495 | str9 db 'miscompare at offset %u.',10,0 |
496 | str10 db 'invalid reply.',10,0 |
||
497 | str14 db 'TTL expired.',10,0 |
||
3545 | hidnplayr | 498 | |
5805 | hidnplayr | 499 | str12 db 10,'Statistics:',10,'%u packets sent, %u packets received',10,'average response time=%u.%u ms',10,0 |
4012 | hidnplayr | 500 | |
3545 | hidnplayr | 501 | sockaddr1: |
502 | dw AF_INET4 |
||
503 | .port dw 0 |
||
504 | .ip dd 0 |
||
505 | rb 10 |
||
506 | |||
507 | time_reference dd ? |
||
508 | ip_ptr dd ? |
||
509 | count dd ? |
||
5842 | hidnplayr | 510 | size dd ? |
511 | ttl dd ? |
||
512 | timeout dd ? |
||
4012 | hidnplayr | 513 | recvd dd ? ; received number of bytes in last packet |
3545 | hidnplayr | 514 | |
4012 | hidnplayr | 515 | stats: |
4019 | hidnplayr | 516 | .tx dd ? |
517 | .rx dd ? |
||
518 | .time dd ? |
||
3545 | hidnplayr | 519 | |
520 | ; import |
||
521 | align 4 |
||
522 | @IMPORT: |
||
523 | |||
524 | library network, 'network.obj', console, 'console.obj' |
||
525 | import network, \ |
||
526 | getaddrinfo, 'getaddrinfo', \ |
||
527 | freeaddrinfo, 'freeaddrinfo', \ |
||
528 | inet_ntoa, 'inet_ntoa' |
||
529 | |||
530 | import console, \ |
||
531 | con_start, 'START', \ |
||
532 | con_init, 'con_init', \ |
||
533 | con_write_asciiz, 'con_write_asciiz', \ |
||
534 | con_printf, 'con_printf', \ |
||
535 | con_exit, 'con_exit', \ |
||
536 | con_gets, 'con_gets',\ |
||
537 | con_cls, 'con_cls',\ |
||
538 | con_getch2, 'con_getch2',\ |
||
5249 | hidnplayr | 539 | con_set_cursor_pos, 'con_set_cursor_pos',\ |
540 | con_get_flags, 'con_get_flags' |
||
3545 | hidnplayr | 541 | |
542 | socketnum dd ? |
||
543 | |||
5842 | hidnplayr | 544 | icmp_packet db ICMP_ECHO ; type |
3545 | hidnplayr | 545 | db 0 ; code |
5842 | hidnplayr | 546 | dw 0 ; checksum |
4012 | hidnplayr | 547 | .id dw IDENTIFIER ; identifier |
548 | .seq dw 0x0000 ; sequence number |
||
549 | .data db 'abcdefghijklmnopqrstuvwxyz012345' |
||
3545 | hidnplayr | 550 | |
551 | I_END: |
||
5842 | hidnplayr | 552 | rb 65504-32 |
3545 | hidnplayr | 553 | |
5842 | hidnplayr | 554 | params rb 1024 |
555 | buffer_ptr: rb BUFFERSIZE |
||
3545 | hidnplayr | 556 | |
5805 | hidnplayr | 557 | IM_END: |