Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6923 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
3
;; Copyright (C) KolibriOS team 2010-2017. All rights reserved.    ;;
4
;; Distributed under terms of the GNU General Public License       ;;
5
;;                                                                 ;;
6
;;  tracert.asm - Trace network route 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
 
17
BUFFERSIZE      = 1500
18
IDENTIFIER      = 0x1337
19
 
20
__DEBUG__               = 1             ; enable/disable
21
__DEBUG_LEVEL__         = 2             ; 1 = all, 2 = errors
22
 
23
use32
24
        org     0x0
25
 
26
        db      'MENUET01'      ; signature
27
        dd      1               ; header version
28
        dd      START           ; entry point
29
        dd      I_END           ; initialized size
30
        dd      IM_END+0x1000   ; required memory
31
        dd      IM_END+0x1000   ; stack pointer
32
        dd      params          ; parameters
33
        dd      0               ; path
34
 
35
include '../../proc32.inc'
36
include '../../macros.inc'
37
purge mov,add,sub
38
include '../../dll.inc'
39
include '../../struct.inc'
40
include '../../debug-fdo.inc'
41
include '../../network.inc'
42
 
43
include '../icmp.inc'
44
include '../ip.inc'
45
 
46
 
47
START:
48
; init heap
49
        mcall   68, 11
50
        test    eax, eax
51
        jz      exit
52
; load libraries
53
        stdcall dll.Load, @IMPORT
54
        test    eax, eax
55
        jnz     exit
56
; initialize console
57
        push    1
58
        call    [con_start]
59
        push    title
60
        push    250
61
        push    80
62
        push    25
63
        push    80
64
        call    [con_init]
65
; main loop
66
        cmp     byte[params], 0
67
        jne     parse_param
68
 
69
        push    str_welcome
70
        call    [con_write_asciiz]
71
main:
72
; write prompt
73
        push    str_prompt
74
        call    [con_write_asciiz]
75
; read string
76
        mov     esi, params
77
        push    1024
78
        push    esi
79
        call    [con_gets]
80
; check for exit
81
        test    eax, eax
82
        jz      exit
83
        cmp     byte [esi], 10
84
        jz      exit
85
; delete terminating '\n'
86
        push    esi
87
@@:
88
        lodsb
89
        test    al, al
90
        jnz     @b
91
        mov     [esi-2], al
92
        pop     esi
93
 
94
parse_param:
95
; Check if any additional parameters were given
96
 
97
        DEBUGF  2, "parse parameters\n"
98
        mov     esi, params
99
        mov     ecx, 1024
100
  .addrloop:
101
        lodsb
102
        test    al, al
103
        jz      .resolve
104
        cmp     al, ' '
105
        jne     .addrloop
106
        mov     byte[esi-1], 0
107
        jmp     .param
108
 
109
  .param_loop:
110
        lodsb
111
        test    al, al
112
        jz      .resolve
113
        cmp     al, ' '
114
        jne     .invalid
115
  .param:
116
        lodsb
117
        cmp     al, '-'
118
        jne     .invalid
119
        lodsb
120
        ; implement more parameters here
121
  .invalid:
122
        push    str13
123
        call    [con_write_asciiz]
124
        jmp     main
125
 
126
  .resolve:
127
        DEBUGF  2, "resolve\n"
128
; resolve name
129
        push    esp     ; reserve stack place
130
        push    esp     ; fourth parameter
131
        push    0       ; third parameter
132
        push    0       ; second parameter
133
        push    params  ; first parameter
134
        call    [getaddrinfo]
135
        pop     esi
136
; test for error
137
        test    eax, eax
138
        jnz     fail
139
 
140
; convert IP address to decimal notation
141
        mov     eax, [esi+addrinfo.ai_addr]
142
        mov     eax, [eax+sockaddr_in.sin_addr]
143
        mov     [sockaddr1.ip], eax
144
        push    eax
145
        call    [inet_ntoa]
146
; write result
147
        mov     [ip_ptr], eax
148
 
149
        push    eax
150
 
151
; free allocated memory
152
        push    esi
153
        call    [freeaddrinfo]
154
 
155
        push    str4
156
        call    [con_write_asciiz]
157
 
158
        mcall   socket, AF_INET4, SOCK_RAW, IPPROTO_ICMP
159
        cmp     eax, -1
160
        jz      fail2
161
        mov     [icmp_socket], eax
162
 
163
        mcall   socket, AF_INET4, SOCK_DGRAM, 0
164
        cmp     eax, -1
165
        jz      fail2
166
        mov     [udp_socket], eax
167
 
168
        mcall   connect, [udp_socket], sockaddr1, 18
169
        cmp     eax, -1
170
        je      fail2
171
 
172
        mcall   40, EVM_STACK
173
 
174
        push    str3
175
        call    [con_write_asciiz]
176
 
177
        push    [ip_ptr]
178
        call    [con_write_asciiz]
179
 
180
        push    str4
181
        call    [con_write_asciiz]
182
 
183
        mov     [ttl], 1
184
 
185
 ;;       mcall   send, [udp_socket], udp_packet, 5, 0    ; dummy send
186
 
187
        mcall   recv, [icmp_socket], buffer_ptr, BUFFERSIZE, MSG_DONTWAIT ;; dummy read
188
 
189
mainloop:
190
        call    [con_get_flags]
191
        test    eax, 0x200                      ; con window closed?
192
        jnz     exit_now
193
 
194
        pushd   [ttl]
195
        pushd   str9
196
        call    [con_printf]
197
        add     esp, 2*4
198
 
199
        DEBUGF  2, "Setsockopt\n"
200
 
201
        pushd   [ttl]
202
        pushd   4                               ; length of option
203
        pushd   IP_TTL
204
        pushd   IPPROTO_IP
205
        mcall   setsockopt, [udp_socket], esp
206
        add     esp, 16
207
        cmp     eax, -1
208
        je      fail2
209
 
210
        DEBUGF  2, "Sending\n"
211
 
212
        mcall   26, 10                          ; Get high precision timer count
213
        mov     [time_reference], eax
214
        mcall   send, [udp_socket], udp_packet, 5, 0
215
        cmp     eax, -1
216
        je      fail2
217
 
218
        DEBUGF  2, "Packet sent\n", str_ini_int
219
 
220
   .receive:
221
        mcall   23, [timeout]
222
 
223
        mcall   26, 10                          ; Get high precision timer count
224
        sub     eax, [time_reference]
225
        jz      @f
226
        xor     edx, edx
227
        mov     ebx, 100000
228
        div     ebx
229
        cmp     edx, 50000
230
        jb      @f
231
        inc     eax
232
  @@:
233
        mov     [time_reference], eax
234
 
235
; Receive reply
236
        mcall   recv, [icmp_socket], buffer_ptr, BUFFERSIZE, MSG_DONTWAIT
237
        cmp     eax, -1
238
        je      .timeout
239
        test    eax, eax
240
        jz      fail2
241
 
242
        DEBUGF  2, "Answer after %u\n", eax
243
 
244
; IP header length
245
        movzx   esi, byte[buffer_ptr]
246
        and     esi, 0xf
247
        shl     esi, 2
248
 
249
; Check packet length
250
        sub     eax, esi
251
        sub     eax, sizeof.ICMP_header
252
        jb      .invalid
253
        mov     [recvd], eax
254
 
255
        DEBUGF  2, "Packet length OK\n", eax
256
 
257
; make esi point to ICMP packet header
258
        add     esi, buffer_ptr
259
 
260
; Verify packet
261
;;        movzx   eax, [esi + sizeof.ICMP_header + IPv4_header.TimeToLive]
262
;;        cmp     eax, [ttl]
263
;;        jne     .receive
264
 
265
; What kind of response is it?
266
        cmp     [esi + ICMP_header.Type], ICMP_UNREACH_PORT
267
        je      .last
268
        cmp     [esi + ICMP_header.Type], ICMP_TIMXCEED
269
        jne     .invalid
270
        call    .print
271
        jmp     .continue
272
 
273
  .last:
274
        call    .print
275
        jmp     main
276
 
277
  .print:
278
        DEBUGF  2, "Valid response\n"
279
; we have a response, print a line
280
        mov     eax, [time_reference]
281
        xor     edx, edx
282
        mov     ebx, 10
283
        div     ebx
284
        push    edx
285
        push    eax
286
 
287
        push    str1
288
        call    [con_printf]
289
        add     esp, 3*4
290
 
291
        mov     ebx, [buffer_ptr + IPv4_header.SourceAddress]
292
        push    ebx
293
        call    reverse_dns_lookup
294
 
295
        pop     eax
296
        rol     eax, 16
297
        movzx   ebx, ah
298
        push    ebx
299
        movzx   ebx, al
300
        push    ebx
301
        shr     eax, 16
302
        movzx   ebx, ah
303
        push    ebx
304
        movzx   ebx, al
305
        push    ebx
306
 
307
        push    str2
308
        call    [con_printf]
309
        add     esp, 5*4
310
 
311
        ret
312
 
313
 
314
; Invalid reply
315
  .invalid:
316
        DEBUGF  2, "Invalid response\n"
317
        push    str10
318
        call    [con_write_asciiz]
319
        jmp     main    ;.continue
320
 
321
; Timeout!
322
  .timeout:
323
        DEBUGF  2, "Timeout\n", eax
324
        push    str8
325
        call    [con_write_asciiz]
326
 
327
; Send more ICMP packets ?
328
  .continue:
329
        inc     [ttl]
330
 
331
; wait a second before sending next request
332
        mcall   5, 100
333
        jmp     mainloop
334
 
335
; DNS error
336
fail:
337
        push    str5
338
        call    [con_write_asciiz]
339
        jmp     main
340
 
341
; Socket error
342
fail2:
343
        push    str6
344
        call    [con_write_asciiz]
345
        jmp     main
346
 
347
; Finally.. exit!
348
exit:
349
        push    1
350
        call    [con_exit]
351
exit_now:
352
        mcall   -1
353
 
354
 
355
ascii_to_dec:
356
 
357
        lodsb
358
        cmp     al, ' '
359
        jne     .fail
360
 
361
        xor     eax, eax
362
        xor     ebx, ebx
363
  .loop:
364
        lodsb
365
        test    al, al
366
        jz      .done
367
        cmp     al, ' '
368
        je      .done
369
        sub     al, '0'
370
        jb      .fail
371
        cmp     al, 9
372
        ja      .fail
373
        lea     ebx, [ebx*4+ebx]
374
        lea     ebx, [ebx*2+eax]
375
        jmp     .loop
376
  .fail:
377
        xor     ebx, ebx
378
  .done:
379
        dec     esi
380
        ret
381
 
382
 
383
; ebx = ip
384
reverse_dns_lookup:
385
 
386
        push    ebx
387
        mcall   socket, AF_INET4, SOCK_DGRAM, 0
388
        pop     ebx
389
        cmp     eax, -1
390
        je      .fail
391
        mov     [dns_socket], eax
392
 
393
        push    ebx
394
        mcall   connect, [dns_socket], sockaddr2, 18
395
        pop     ebx
396
        cmp     eax, -1
397
        je      .fail
398
 
399
        mov     edi, dns_pkt.name
400
        rol     ebx, 8
401
        movzx   eax, bl
402
        call    byte_to_ascii
403
        rol     ebx, 8
404
        movzx   eax, bl
405
        call    byte_to_ascii
406
        rol     ebx, 8
407
        movzx   eax, bl
408
        call    byte_to_ascii
409
        rol     ebx, 8
410
        movzx   eax, bl
411
        call    byte_to_ascii
412
 
413
        mov     esi, dns_tr
414
        mov     ecx, dns_tr.length
415
        rep movsb
416
 
417
        sub     edi, dns_pkt
418
        mov     esi, edi
419
 
420
        mcall   send, [dns_socket], dns_pkt, , 0
421
        cmp     eax, -1
422
        je      .fail
423
 
424
        push    esi
425
        mcall   recv, [dns_socket], buffer_ptr, BUFFERSIZE, 0
426
        pop     esi
427
 
428
        mcall   close, [dns_socket]
429
 
430
        cmp     word[buffer_ptr+6], 0   ; answers
431
        je      .fail
432
 
433
        add     esi, buffer_ptr+12
434
        mov     edi, buffer_ptr
435
        xor     ecx, ecx
436
        lodsb
437
        test    al, al
438
        jz      @f
439
        movzx   ecx, al
440
  @@:
441
        rep movsb
442
        lodsb
443
        test    al, al
444
        jz      @f
445
        movzx   ecx, al
446
        mov     al, '.'
447
        stosb
448
        jmp     @r
449
  @@:
450
        stosb
451
 
452
        push    buffer_ptr
453
        call    [con_write_asciiz]
454
 
455
        push    str7
456
        call    [con_write_asciiz]
457
 
458
        ret
459
 
460
  .fail:
461
        ret
462
 
463
 
464
 
465
; input: eax - number
466
;        edi - ptr
467
byte_to_ascii:
468
 
469
        push    ebx ecx edx
470
 
471
        xor     edx, edx        ; result
472
        xor     ecx, ecx        ; byte count
473
        inc     ecx
474
        mov     bl, 10          ; divisor
475
 
476
        div     bl
477
        mov     dl, ah
478
        add     dl, '0'
479
        and     ax, 0x00ff
480
        jz      .ok
481
 
482
        inc     ecx
483
        shl     edx, 8
484
 
485
        div     bl
486
        mov     dl, ah
487
        add     dl, '0'
488
        and     ax, 0x00ff
489
        jz      .ok
490
 
491
        inc     ecx
492
        shl     edx, 8
493
 
494
        mov     dl, al
495
        add     dl, '0'
496
 
497
  .ok:
498
        shl     edx, 8
499
        mov     dl, cl
500
        mov     [edi], edx
501
        add     edi, ecx
502
        inc     edi
503
 
504
        pop     edx ecx ebx
505
        ret
506
 
507
 
508
; data
509
title   db      'Trace route',0
510
str_welcome db  'Please enter the hostname or IP-address of the host you want to trace,',10
511
            db  'or just press enter to exit.',10,10,0
512
str_prompt  db  10,'> ',0
513
str3    db      'Tracing route to ',0
514
 
515
str4    db      10,0
516
str7    db      ' ', 0
517
str5    db      'Name resolution failed.',10,0
518
str6    db      'Socket error.',10,0
519
str13   db      'Invalid parameter(s)',10,0
520
 
521
str9    db      '%u ',0
522
str1    db      '%u.%u ms ',0
523
str2    db      '[%u.%u.%u.%u]',10,0
524
str10   db      'Invalid reply',10,0
525
str8    db      'Timeout!',10,0
526
 
527
 
528
sockaddr1:
529
        dw AF_INET4
530
.port   dw 666
531
.ip     dd 0
532
        rb 10
533
 
534
sockaddr2:
535
        dw AF_INET4
536
.port   dw 53 shl 8     ; DNS port
537
.ip     dd 0x08080808   ; Google DNS
538
        rb 10
539
 
540
time_reference  dd ?
541
ip_ptr          dd ?
542
ttl             dd ?
543
timeout         dd 500
544
recvd           dd ?    ; received number of bytes in last packet
545
 
546
; import
547
align 4
548
@IMPORT:
549
 
550
library console, 'console.obj', \
551
        network, 'network.obj'
552
 
553
import  console,        \
554
        con_start,      'START',        \
555
        con_init,       'con_init',     \
556
        con_write_asciiz,       'con_write_asciiz',     \
557
        con_printf,       'con_printf',     \
558
        con_exit,       'con_exit',     \
559
        con_gets,       'con_gets',\
560
        con_cls,        'con_cls',\
561
        con_getch2,     'con_getch2',\
562
        con_set_cursor_pos, 'con_set_cursor_pos',\
563
        con_get_flags,  'con_get_flags'
564
 
565
import  network,        \
566
        getaddrinfo,    'getaddrinfo',  \
567
        freeaddrinfo,   'freeaddrinfo', \
568
        inet_ntoa,      'inet_ntoa'
569
 
570
include_debug_strings
571
 
572
icmp_socket     dd ?
573
udp_socket      dd ?
574
dns_socket      dd ?
575
 
576
udp_packet      db 'hello!'
577
 
578
dns_tr:
579
        db  7,'in-addr',4,'arpa',0
580
        dw  0x0C00      ; Qtype: PTR
581
        dw  0x0100      ; Class: IN
582
 
583
  .length = $ - dns_tr
584
 
585
dns_pkt:
586
        dw  0x9A02      ; Transaction ID
587
        dw  0x0001      ; Flags: Recursive desired
588
        dw  0x0100      ; Questions
589
        dw  0x0000      ; Answers
590
        dw  0x0000      ; Authority RR
591
        dw  0x0000      ; Additional RR
592
  .name rb  512
593
 
594
I_END:
595
 
596
params          rb 1024
597
buffer_ptr:     rb BUFFERSIZE
598
 
599
IM_END: