OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [userland/] [ping/] [ping.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 745 simons
/*
2
 * Copyright (c) 1989 The Regents of the University of California.
3
 * All rights reserved.
4
 *
5
 * This code is derived from software contributed to Berkeley by
6
 * Mike Muuss.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. All advertising materials mentioning features or use of this software
17
 *    must display the following acknowledgement:
18
 *      This product includes software developed by the University of
19
 *      California, Berkeley and its contributors.
20
 * 4. Neither the name of the University nor the names of its contributors
21
 *    may be used to endorse or promote products derived from this software
22
 *    without specific prior written permission.
23
 *
24
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34
 * SUCH DAMAGE.
35
 */
36
 
37
char copyright[] =
38
  "@(#) Copyright (c) 1989 The Regents of the University of California.\n"
39
  "All rights reserved.\n";
40
/*
41
 * From: @(#)ping.c     5.9 (Berkeley) 5/12/91
42
 */
43
char rcsid[] = "$Original-Id: ping.c,v 1.22 1997/06/08 19:39:47 dholland Exp $";
44
char pkg[] = "netkit-base-0.10";
45
 
46
/*
47
 *                      P I N G . C
48
 *
49
 * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
50
 * measure round-trip-delays and packet loss across network paths.
51
 *
52
 * Author -
53
 *      Mike Muuss
54
 *      U. S. Army Ballistic Research Laboratory
55
 *      December, 1983
56
 *
57
 * Status -
58
 *      Public Domain.  Distribution Unlimited.
59
 * Bugs -
60
 *      More statistics could always be gathered.
61
 *      This program has to run SUID to ROOT to access the ICMP socket.
62
 */
63
 
64
#include <sys/param.h>
65
#include <sys/socket.h>
66
#include <sys/file.h>
67
#include <sys/time.h>
68
#include <sys/signal.h>
69
 
70
#include <netinet/in.h>
71
#include <netinet/ip.h>
72
#include <netinet/ip_icmp.h>
73
#include <arpa/inet.h>
74
#include <netdb.h>
75
#include <unistd.h>
76
#include <stdlib.h>
77
#include <string.h>
78
#include <stdio.h>
79
#include <ctype.h>
80
#include <errno.h>
81
#include <getopt.h>
82
#include <resolv.h>
83
 
84
/*
85
 * Note: on some systems dropping root makes the process dumpable or
86
 * traceable. In that case if you enable dropping root and someone
87
 * traces ping, they get control of a raw socket and can start
88
 * spoofing whatever packets they like. SO BE CAREFUL.
89
 */
90
#ifdef __linux__
91
#define SAFE_TO_DROP_ROOT
92
#endif
93
 
94
#if defined(__GLIBC__) && (__GLIBC__ >= 2)
95
#define icmphdr                 icmp
96
/*
97
#define ICMP_DEST_UNREACH       ICMP_UNREACH
98
#define ICMP_NET_UNREACH        ICMP_UNREACH_NET
99
#define ICMP_HOST_UNREACH       ICMP_UNREACH_HOST
100
#define ICMP_PORT_UNREACH       ICMP_UNREACH_PORT
101
#define ICMP_PROT_UNREACH       ICMP_UNREACH_PROTOCOL
102
#define ICMP_FRAG_NEEDED        ICMP_UNREACH_NEEDFRAG
103
#define ICMP_SR_FAILED          ICMP_UNREACH_SRCFAIL
104
#define ICMP_NET_UNKNOWN        ICMP_UNREACH_NET_UNKNOWN
105
#define ICMP_HOST_UNKNOWN       ICMP_UNREACH_HOST_UNKNOWN
106
#define ICMP_HOST_ISOLATED      ICMP_UNREACH_ISOLATED
107
#define ICMP_NET_UNR_TOS        ICMP_UNREACH_TOSNET
108
#define ICMP_HOST_UNR_TOS       ICMP_UNREACH_TOSHOST
109
#define ICMP_SOURCE_QUENCH      ICMP_SOURCEQUENCH
110
#define ICMP_REDIR_NET          ICMP_REDIRECT_NET
111
#define ICMP_REDIR_HOST         ICMP_REDIRECT_HOST
112
#define ICMP_REDIR_NETTOS       ICMP_REDIRECT_TOSNET
113
#define ICMP_REDIR_HOSTTOS      ICMP_REDIRECT_TOSHOST
114
#define ICMP_TIME_EXCEEDED      ICMP_TIMXCEED
115
#define ICMP_EXC_TTL            ICMP_TIMXCEED_INTRANS
116
#define ICMP_EXC_FRAGTIME       ICMP_TIMXCEED_REASS
117
#define ICMP_PARAMETERPROB      ICMP_PARAMPROB
118
#define ICMP_TIMESTAMP          ICMP_TSTAMP
119
#define ICMP_TIMESTAMPREPLY     ICMP_TSTAMPREPLY
120
#define ICMP_INFO_REQUEST       ICMP_IREQ
121
#define ICMP_INFO_REPLY         ICMP_IREQREPLY
122
*/
123
#else
124
#define ICMP_MINLEN     28
125
#define inet_ntoa(x) inet_ntoa(*((struct in_addr *)&(x)))
126
#endif
127
 
128
 
129
#define DEFDATALEN      (64 - 8)        /* default data length */
130
#define MAXIPLEN        60
131
#define MAXICMPLEN      76
132
#define MAXPACKET       (2048 - 60 - 8)/* max packet size */
133
#define MAXWAIT         10              /* max seconds to wait for response */
134
#define NROUTES         9               /* number of record route slots */
135
 
136
#define A(bit)          rcvd_tbl[(bit)>>3]      /* identify byte in array */
137
#define B(bit)          (1 << ((bit) & 0x07))   /* identify bit in byte */
138
#define SET(bit)        (A(bit) |= B(bit))
139
#define CLR(bit)        (A(bit) &= (~B(bit)))
140
#define TST(bit)        (A(bit) & B(bit))
141
 
142
/* various options */
143
int options;
144
#define F_FLOOD         0x001
145
#define F_INTERVAL      0x002
146
#define F_NUMERIC       0x004
147
#define F_PINGFILLED    0x008
148
#define F_QUIET         0x010
149
#define F_RROUTE        0x020
150
#define F_SO_DEBUG      0x040
151
#define F_SO_DONTROUTE  0x080
152
#define F_VERBOSE       0x100
153
 
154
/* multicast options */
155
int moptions;
156
#define MULTICAST_NOLOOP        0x001
157
#define MULTICAST_TTL           0x002
158
#define MULTICAST_IF            0x004
159
 
160
/*
161
 * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
162
 * number of received sequence numbers we can keep track of.  Change 128
163
 * to 8192 for complete accuracy...
164
 */
165
#define MAX_DUP_CHK     (8 * 128)
166
int mx_dup_ck = MAX_DUP_CHK;
167
char rcvd_tbl[MAX_DUP_CHK / 8];
168
 
169
struct sockaddr whereto;        /* who to ping */
170
int datalen = DEFDATALEN;
171
int s;                          /* socket file descriptor */
172
u_char outpack[MAXPACKET];
173
char BSPACE = '\b';             /* characters written for flood */
174
char DOT = '.';
175
static char *hostname;
176
static int ident;               /* process id to identify our packets */
177
 
178
/* counters */
179
static long npackets;           /* max packets to transmit */
180
static long nreceived;          /* # of packets we got back */
181
static long nrepeats;           /* number of duplicates */
182
static long ntransmitted;       /* sequence # for outbound packets = #sent */
183
static int interval = 1;        /* interval between packets */
184
 
185
/* timing */
186
static int timing;              /* flag to do timing */
187
static long tmin = LONG_MAX;    /* minimum round trip time */
188
static long tmax = 0;            /* maximum round trip time */
189
static u_long tsum;             /* sum of all times, for doing average */
190
 
191
/* protos */
192
static char *pr_addr(u_long);
193
static int in_cksum(u_short *addr, int len);
194
static void catcher(int);
195
static void finish(int ignore);
196
static void pinger(void);
197
static void fill(void *bp, char *patp);
198
static void usage(void);
199
static void pr_pack(char *buf, int cc, struct sockaddr_in *from);
200
static void tvsub(struct timeval *out, struct timeval *in);
201
static void pr_icmph(struct icmphdr *icp);
202
static void pr_retip(struct iphdr *ip);
203
 
204
 
205
int
206
main(int argc, char *argv[])
207
{
208
        struct timeval timeout;
209
        struct hostent *hp;
210
        struct sockaddr_in *to;
211
        struct protoent *proto;
212
        struct in_addr ifaddr;
213
        int i;
214
        int ch, fdmask, hold, packlen, preload;
215
        u_char *datap, *packet;
216
        char *target, hnamebuf[MAXHOSTNAMELEN];
217
        u_char ttl, loop;
218
        int am_i_root;
219
#ifdef IP_OPTIONS
220
        char rspace[3 + 4 * NROUTES + 1];       /* record route space */
221
#endif
222
 
223
        static char *null = NULL;
224
 
225
        /*__environ = &null;*/
226
        am_i_root = (getuid()==0);
227
 
228
        /*
229
         * Pull this stuff up front so we can drop root if desired.
230
         */
231
        if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
232
                if (errno==EPERM) {
233
                        fprintf(stderr, "ping: ping must run as root\n");
234
                }
235
                else perror("ping: socket");
236
                exit(2);
237
        }
238
 
239
#ifdef SAFE_TO_DROP_ROOT
240
        setuid(getuid());
241
#endif
242
 
243
        preload = 0;
244
        datap = &outpack[8 + sizeof(struct timeval)];
245
        while ((ch = getopt(argc, argv, "I:LRc:dfh:i:l:np:qrs:t:v")) != EOF)
246
                switch(ch) {
247
                case 'c':
248
                        npackets = atoi(optarg);
249
                        if (npackets <= 0) {
250
                                (void)fprintf(stderr,
251
                                    "ping: bad number of packets to transmit.\n");
252
                                exit(2);
253
                        }
254
                        break;
255
                case 'd':
256
                        options |= F_SO_DEBUG;
257
                        break;
258
                case 'f':
259
                        if (!am_i_root) {
260
                                (void)fprintf(stderr,
261
                                    "ping: %s\n", strerror(EPERM));
262
                                exit(2);
263
                        }
264
                        options |= F_FLOOD;
265
                        setbuf(stdout, NULL);
266
                        break;
267
                case 'i':               /* wait between sending packets */
268
                        interval = atoi(optarg);
269
                        if (interval <= 0) {
270
                                (void)fprintf(stderr,
271
                                    "ping: bad timing interval.\n");
272
                                exit(2);
273
                        }
274
                        options |= F_INTERVAL;
275
                        break;
276
                case 'l':
277
                        if (!am_i_root) {
278
                                (void)fprintf(stderr,
279
                                    "ping: %s\n", strerror(EPERM));
280
                                exit(2);
281
                        }
282
                        preload = atoi(optarg);
283
                        if (preload < 0) {
284
                                (void)fprintf(stderr,
285
                                    "ping: bad preload value.\n");
286
                                exit(2);
287
                        }
288
                        break;
289
                case 'n':
290
                        options |= F_NUMERIC;
291
                        break;
292
                case 'p':               /* fill buffer with user pattern */
293
                        options |= F_PINGFILLED;
294
                        fill(datap, optarg);
295
                        break;
296
                case 'q':
297
                        options |= F_QUIET;
298
                        break;
299
                case 'R':
300
                        options |= F_RROUTE;
301
                        break;
302
                case 'r':
303
                        options |= F_SO_DONTROUTE;
304
                        break;
305
                case 's':               /* size of packet to send */
306
                        datalen = atoi(optarg);
307
                        if (datalen > MAXPACKET) {
308
                                (void)fprintf(stderr,
309
                                    "ping: packet size too large.\n");
310
                                exit(2);
311
                        }
312
                        if (datalen <= 0) {
313
                                (void)fprintf(stderr,
314
                                    "ping: illegal packet size.\n");
315
                                exit(2);
316
                        }
317
                        break;
318
                case 'v':
319
                        options |= F_VERBOSE;
320
                        break;
321
                case 'L':
322
                        moptions |= MULTICAST_NOLOOP;
323
                        loop = 0;
324
                        break;
325
                case 't':
326
                        moptions |= MULTICAST_TTL;
327
                        i = atoi(optarg);
328
                        if (i < 0 || i > 255) {
329
                                printf("ttl %u out of range\n", i);
330
                                exit(2);
331
                        }
332
                        ttl = i;
333
                        break;
334
                case 'I':
335
                        moptions |= MULTICAST_IF;
336
                        {
337
                                int i1, i2, i3, i4;
338
                                char junk;
339
 
340
                                if (sscanf(optarg, "%u.%u.%u.%u%c",
341
                                           &i1, &i2, &i3, &i4, &junk) != 4) {
342
                                        printf("bad interface address '%s'\n",
343
                                               optarg);
344
                                        exit(2);
345
                                }
346
                                ifaddr.s_addr = (i1<<24)|(i2<<16)|(i3<<8)|i4;
347
                                ifaddr.s_addr = htonl(ifaddr.s_addr);
348
                        }
349
                        break;
350
                default:
351
                        usage();
352
                }
353
        argc -= optind;
354
        argv += optind;
355
 
356
        if (argc != 1)
357
                usage();
358
        target = *argv;
359
 
360
        memset(&whereto, 0, sizeof(struct sockaddr));
361
        to = (struct sockaddr_in *)&whereto;
362
        to->sin_family = AF_INET;
363
        if (inet_aton(target, &to->sin_addr)) {
364
                hostname = target;
365
        }
366
        else {
367
/*
368
                char * addr = resolve_name(target, 0);
369
                if (!addr) {
370
                        (void)fprintf(stderr,
371
                            "ping: unknown host %s\n", target);
372
                        exit(2);
373
                }
374
                to->sin_addr.s_addr = inet_addr(addr);
375
                hostname = target;
376
*/
377
 
378
                hp = gethostbyname(target);
379
                if (!hp) {
380
                        (void)fprintf(stderr,
381
                            "ping: unknown host %s\n", target);
382
                        exit(2);
383
                }
384
                to->sin_family = hp->h_addrtype;
385
                if (hp->h_length > (int)sizeof(to->sin_addr)) {
386
                        hp->h_length = sizeof(to->sin_addr);
387
                }
388
                memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
389
                (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
390
                hostname = hnamebuf;
391
 
392
        }
393
 
394
        if (options & F_FLOOD && options & F_INTERVAL) {
395
                (void)fprintf(stderr,
396
                    "ping: -f and -i incompatible options.\n");
397
                exit(2);
398
        }
399
 
400
        if (datalen >= (int)sizeof(struct timeval)) /* can we time transfer */
401
                timing = 1;
402
        packlen = datalen + MAXIPLEN + MAXICMPLEN;
403
        packet = malloc((u_int)packlen);
404
        if (!packet) {
405
                (void)fprintf(stderr, "ping: out of memory.\n");
406
                exit(2);
407
        }
408
        if (!(options & F_PINGFILLED))
409
                for (i = 8; i < datalen; ++i)
410
                        *datap++ = i;
411
 
412
        ident = getpid() & 0xFFFF;
413
        hold = 1;
414
 
415
        if (options & F_SO_DEBUG)
416
                (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
417
                    sizeof(hold));
418
 
419
        if (options & F_SO_DONTROUTE)
420
                (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
421
                    sizeof(hold));
422
 
423
        /* this is necessary for broadcast pings to work */
424
        setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&hold, sizeof(hold));
425
 
426
        /* record route option */
427
        if (options & F_RROUTE) {
428
#ifdef IP_OPTIONS
429
                memset(rspace, 0, sizeof(rspace));
430
                rspace[IPOPT_OPTVAL] = IPOPT_RR;
431
                rspace[IPOPT_OLEN] = sizeof(rspace)-1;
432
                rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
433
                if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,
434
                    sizeof(rspace)) < 0) {
435
                        perror("ping: record route");
436
                        exit(2);
437
                }
438
#else
439
                (void)fprintf(stderr,
440
                  "ping: record route not available in this implementation.\n");
441
                exit(2);
442
#endif /* IP_OPTIONS */
443
        }
444
 
445
        /*
446
         * When pinging the broadcast address, you can get a lot of answers.
447
         * Doing something so evil is useful if you are trying to stress the
448
         * ethernet, or just want to fill the arp cache to get some stuff for
449
         * /etc/ethers.
450
         */
451
        hold = 48 * 1024;
452
        (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
453
            sizeof(hold));
454
 
455
/*#if 0*/
456
        if (moptions & MULTICAST_NOLOOP) {
457
                if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP,
458
                                                        &loop, 1) == -1) {
459
                        perror ("can't disable multicast loopback");
460
                        exit(92);
461
                }
462
        }
463
        if (moptions & MULTICAST_TTL) {
464
                if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL,
465
                                                        &ttl, 1) == -1) {
466
                        perror ("can't set multicast time-to-live");
467
                        exit(93);
468
                }
469
        }
470
        if (moptions & MULTICAST_IF) {
471
                if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
472
                                        &ifaddr, sizeof(ifaddr)) == -1) {
473
                        perror ("can't set multicast source interface");
474
                        exit(94);
475
                }
476
        }
477
/*#endif*/
478
 
479
        if (to->sin_family == AF_INET)
480
                (void)printf("PING %s (%s): %d data bytes\n", hostname,
481
                    inet_ntoa(*(struct in_addr *)&to->sin_addr.s_addr),
482
                    datalen);
483
        else
484
                (void)printf("PING %s: %d data bytes\n", hostname, datalen);
485
 
486
        (void)signal(SIGINT, finish);
487
        (void)signal(SIGALRM, catcher);
488
 
489
        while (preload--)               /* fire off them quickies */
490
                pinger();
491
 
492
        if ((options & F_FLOOD) == 0)
493
                catcher(0);              /* start things going */
494
 
495
        for (;;) {
496
                struct sockaddr_in from;
497
                register int cc;
498
                int fromlen;
499
 
500
                if (options & F_FLOOD) {
501
                        pinger();
502
                        timeout.tv_sec = 0;
503
                        timeout.tv_usec = 10000;
504
                        fdmask = 1 << s;
505
                        if (select(s + 1, (fd_set *)&fdmask, (fd_set *)NULL,
506
                            (fd_set *)NULL, &timeout) < 1)
507
                                continue;
508
                }
509
                fromlen = sizeof(from);
510
                if ((cc = recvfrom(s, (char *)packet, packlen, 0,
511
                    (struct sockaddr *)&from, &fromlen)) < 0) {
512
                        if (errno == EINTR)
513
                                continue;
514
                        perror("ping: recvfrom");
515
                        continue;
516
                }
517
                pr_pack((char *)packet, cc, &from);
518
                if (npackets && nreceived >= npackets)
519
                        break;
520
        }
521
        finish(0);
522
        /* NOTREACHED */
523
        return 0;
524
}
525
 
526
/*
527
 * catcher --
528
 *      This routine causes another PING to be transmitted, and then
529
 * schedules another SIGALRM for 1 second from now.
530
 *
531
 * bug --
532
 *      Our sense of time will slowly skew (i.e., packets will not be
533
 * launched exactly at 1-second intervals).  This does not affect the
534
 * quality of the delay and loss statistics.
535
 */
536
static void
537
catcher(int ignore)
538
{
539
        int waittime;
540
 
541
        (void)ignore;
542
        pinger();
543
        (void)signal(SIGALRM, catcher);
544
        if (!npackets || ntransmitted < npackets)
545
                alarm((u_int)interval);
546
        else {
547
                if (nreceived) {
548
                        waittime = 2 * tmax / 1000;
549
                        if (!waittime)
550
                                waittime = 1;
551
                        if (waittime > MAXWAIT)
552
                                waittime = MAXWAIT;
553
                } else
554
                        waittime = MAXWAIT;
555
                (void)signal(SIGALRM, finish);
556
                (void)alarm((u_int)waittime);
557
        }
558
}
559
 
560
#if !defined(__GLIBC__) || (__GLIBC__ < 2)
561
#define icmp_type type
562
#define icmp_code code
563
#define icmp_cksum checksum
564
#define icmp_id un.echo.id
565
#define icmp_seq un.echo.sequence
566
#define icmp_gwaddr un.gateway
567
#endif /* __GLIBC__ */
568
 
569
#define ip_hl ihl
570
#define ip_v version
571
#define ip_tos tos
572
#define ip_len tot_len
573
#define ip_id id
574
#define ip_off frag_off
575
#define ip_ttl ttl
576
#define ip_p protocol
577
#define ip_sum check
578
#define ip_src saddr
579
#define ip_dst daddr
580
 
581
/*
582
 * pinger --
583
 *      Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
584
 * will be added on by the kernel.  The ID field is our UNIX process ID,
585
 * and the sequence number is an ascending integer.  The first 8 bytes
586
 * of the data portion are used to hold a UNIX "timeval" struct in VAX
587
 * byte-order, to compute the round-trip time.
588
 */
589
static void
590
pinger(void)
591
{
592
        register struct icmphdr *icp;
593
        register int cc;
594
        int i;
595
 
596
        icp = (struct icmphdr *)outpack;
597
        icp->icmp_type = ICMP_ECHO;
598
        icp->icmp_code = 0;
599
        icp->icmp_cksum = 0;
600
        icp->icmp_seq = ntransmitted++;
601
        icp->icmp_id = ident;                   /* ID */
602
 
603
        CLR(icp->icmp_seq % mx_dup_ck);
604
 
605
        if (timing)
606
                (void)gettimeofday((struct timeval *)&outpack[8],
607
                    (struct timezone *)NULL);
608
 
609
        cc = datalen + 8;                       /* skips ICMP portion */
610
 
611
        /* compute ICMP checksum here */
612
        icp->icmp_cksum = in_cksum((u_short *)icp, cc);
613
 
614
        i = sendto(s, (char *)outpack, cc, 0, &whereto,
615
            sizeof(struct sockaddr));
616
 
617
        if (i < 0 || i != cc)  {
618
                if (i < 0)
619
                        perror("ping: sendto");
620
                (void)printf("ping: wrote %s %d chars, ret=%d\n",
621
                    hostname, cc, i);
622
        }
623
        if (!(options & F_QUIET) && options & F_FLOOD)
624
                (void)write(STDOUT_FILENO, &DOT, 1);
625
}
626
 
627
/*
628
 * pr_pack --
629
 *      Print out the packet, if it came from us.  This logic is necessary
630
 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
631
 * which arrive ('tis only fair).  This permits multiple copies of this
632
 * program to be run without having intermingled output (or statistics!).
633
 */
634
void
635
pr_pack(char *buf, int cc, struct sockaddr_in *from)
636
{
637
        register struct icmphdr *icp;
638
        register int i;
639
        register u_char *cp,*dp;
640
/*#if 0*/
641
        register u_long l;
642
        register int j;
643
        static int old_rrlen;
644
        static char old_rr[MAX_IPOPTLEN];
645
/*#endif*/
646
        struct iphdr *ip;
647
        struct timeval tv, *tp;
648
        long triptime = 0;
649
        int hlen, dupflag;
650
 
651
        (void)gettimeofday(&tv, (struct timezone *)NULL);
652
 
653
        /* Check the IP header */
654
        ip = (struct iphdr *)buf;
655
        hlen = ip->ip_hl << 2;
656
        if (cc < datalen + ICMP_MINLEN) {
657
                if (options & F_VERBOSE)
658
                        (void)fprintf(stderr,
659
                          "ping: packet too short (%d bytes) from %s\n", cc,
660
                          inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr));
661
                return;
662
        }
663
 
664
        /* Now the ICMP part */
665
        cc -= hlen;
666
        icp = (struct icmphdr *)(buf + hlen);
667
        if (icp->icmp_type == ICMP_ECHOREPLY) {
668
                if (icp->icmp_id != ident)
669
                        return;                 /* 'Twas not our ECHO */
670
                ++nreceived;
671
                if (timing) {
672
#ifndef icmp_data
673
                        tp = (struct timeval *)(icp + 1);
674
#else
675
                        tp = (struct timeval *)icp->icmp_data;
676
#endif
677
                        tvsub(&tv, tp);
678
                        triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100);
679
                        tsum += triptime;
680
                        if (triptime < tmin)
681
                                tmin = triptime;
682
                        if (triptime > tmax)
683
                                tmax = triptime;
684
                }
685
 
686
                if (TST(icp->icmp_seq % mx_dup_ck)) {
687
                        ++nrepeats;
688
                        --nreceived;
689
                        dupflag = 1;
690
                } else {
691
                        SET(icp->icmp_seq % mx_dup_ck);
692
                        dupflag = 0;
693
                }
694
 
695
                if (options & F_QUIET)
696
                        return;
697
 
698
                if (options & F_FLOOD)
699
                        (void)write(STDOUT_FILENO, &BSPACE, 1);
700
                else {
701
                        (void)printf("%d bytes from %s: icmp_seq=%u", cc,
702
                           inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr),
703
                           icp->icmp_seq);
704
                        (void)printf(" ttl=%d", ip->ip_ttl);
705
                        if (timing)
706
                                (void)printf(" time=%ld.%ld ms", triptime/10,
707
                                                triptime%10);
708
                        if (dupflag)
709
                                (void)printf(" (DUP!)");
710
                        /* check the data */
711
#ifndef icmp_data
712
                        cp = ((u_char*)(icp + 1) + 8);
713
#else
714
                        cp = (u_char*)icp->icmp_data + 8;
715
#endif
716
                        dp = &outpack[8 + sizeof(struct timeval)];
717
                        for (i = 8; i < datalen; ++i, ++cp, ++dp) {
718
                                if (*cp != *dp) {
719
        (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
720
            i, *dp, *cp);
721
                                        cp = (u_char*)(icp + 1);
722
                                        for (i = 8; i < datalen; ++i, ++cp) {
723
                                                if ((i % 32) == 8)
724
                                                        (void)printf("\n\t");
725
                                                (void)printf("%x ", *cp);
726
                                        }
727
                                        break;
728
                                }
729
                        }
730
                }
731
        } else {
732
                /* We've got something other than an ECHOREPLY */
733
                if (!(options & F_VERBOSE))
734
                        return;
735
                (void)printf("%d bytes from %s: ", cc,
736
                    pr_addr(from->sin_addr.s_addr));
737
                pr_icmph(icp);
738
        }
739
 
740
/*#if 0*/
741
        /* Display any IP options */
742
        cp = (u_char *)buf + sizeof(struct iphdr);
743
 
744
        for (; hlen > (int)sizeof(struct iphdr); --hlen, ++cp)
745
                switch (*cp) {
746
                case IPOPT_EOL:
747
                        hlen = 0;
748
                        break;
749
                case IPOPT_LSRR:
750
                        (void)printf("\nLSRR: ");
751
                        hlen -= 2;
752
                        j = *++cp;
753
                        ++cp;
754
                        if (j > IPOPT_MINOFF)
755
                                for (;;) {
756
                                        l = *++cp;
757
                                        l = (l<<8) + *++cp;
758
                                        l = (l<<8) + *++cp;
759
                                        l = (l<<8) + *++cp;
760
                                        if (l == 0)
761
                                                (void)printf("\t0.0.0.0");
762
                                else
763
                                        (void)printf("\t%s", pr_addr(ntohl(l)));
764
                                hlen -= 4;
765
                                j -= 4;
766
                                if (j <= IPOPT_MINOFF)
767
                                        break;
768
                                (void)putchar('\n');
769
                        }
770
                        break;
771
                case IPOPT_RR:
772
                        j = *++cp;              /* get length */
773
                        i = *++cp;              /* and pointer */
774
                        hlen -= 2;
775
                        if (i > j)
776
                                i = j;
777
                        i -= IPOPT_MINOFF;
778
                        if (i <= 0)
779
                                continue;
780
                        if (i == old_rrlen
781
                            && cp == (u_char *)buf + sizeof(struct iphdr) + 2
782
                            && !memcmp((char *)cp, old_rr, i)
783
                            && !(options & F_FLOOD)) {
784
                                (void)printf("\t(same route)");
785
                                i = ((i + 3) / 4) * 4;
786
                                hlen -= i;
787
                                cp += i;
788
                                break;
789
                        }
790
                        old_rrlen = i;
791
                        memcpy(old_rr, cp, i);
792
                        (void)printf("\nRR: ");
793
                        for (;;) {
794
                                l = *++cp;
795
                                l = (l<<8) + *++cp;
796
                                l = (l<<8) + *++cp;
797
                                l = (l<<8) + *++cp;
798
                                if (l == 0)
799
                                        (void)printf("\t0.0.0.0");
800
                                else
801
                                        (void)printf("\t%s", pr_addr(ntohl(l)));
802
                                hlen -= 4;
803
                                i -= 4;
804
                                if (i <= 0)
805
                                        break;
806
                                (void)putchar('\n');
807
                        }
808
                        break;
809
                case IPOPT_NOP:
810
                        (void)printf("\nNOP");
811
                        break;
812
                default:
813
                        (void)printf("\nunknown option %x", *cp);
814
                        break;
815
                }
816
/*#endif*/
817
        if (!(options & F_FLOOD)) {
818
                (void)putchar('\n');
819
                (void)fflush(stdout);
820
        }
821
}
822
 
823
/*
824
 * in_cksum --
825
 *      Checksum routine for Internet Protocol family headers (C Version)
826
 */
827
static int
828
in_cksum(u_short *addr, int len)
829
{
830
        register int nleft = len;
831
        register u_short *w = addr;
832
        register int sum = 0;
833
        u_short answer = 0;
834
 
835
        /*
836
         * Our algorithm is simple, using a 32 bit accumulator (sum), we add
837
         * sequential 16 bit words to it, and at the end, fold back all the
838
         * carry bits from the top 16 bits into the lower 16 bits.
839
         */
840
        while (nleft > 1)  {
841
                sum += *w++;
842
                nleft -= 2;
843
        }
844
 
845
        /* mop up an odd byte, if necessary */
846
        if (nleft == 1) {
847
                *(u_char *)(&answer) = *(u_char *)w ;
848
                sum += answer;
849
        }
850
 
851
        /* add back carry outs from top 16 bits to low 16 bits */
852
        sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
853
        sum += (sum >> 16);                     /* add carry */
854
        answer = ~sum;                          /* truncate to 16 bits */
855
        return(answer);
856
}
857
 
858
/*
859
 * tvsub --
860
 *      Subtract 2 timeval structs:  out = out - in.  Out is assumed to
861
 * be >= in.
862
 */
863
static void
864
tvsub(register struct timeval *out, register struct timeval *in)
865
{
866
        if ((out->tv_usec -= in->tv_usec) < 0) {
867
                --out->tv_sec;
868
                out->tv_usec += 1000000;
869
        }
870
        out->tv_sec -= in->tv_sec;
871
}
872
 
873
/*
874
 * finish --
875
 *      Print out statistics, and give up.
876
 */
877
static void
878
finish(int ignore)
879
{
880
        (void)ignore;
881
 
882
        (void)signal(SIGINT, SIG_IGN);
883
        (void)putchar('\n');
884
        (void)fflush(stdout);
885
        (void)printf("--- %s ping statistics ---\n", hostname);
886
        (void)printf("%ld packets transmitted, ", ntransmitted);
887
        (void)printf("%ld packets received, ", nreceived);
888
        if (nrepeats)
889
                (void)printf("+%ld duplicates, ", nrepeats);
890
        if (ntransmitted) {
891
                if (nreceived > ntransmitted)
892
                        (void)printf("-- somebody's printing up packets!");
893
                else
894
                        (void)printf("%d%% packet loss",
895
                            (int) (((ntransmitted - nreceived) * 100) /
896
                            ntransmitted));
897
        }
898
        (void)putchar('\n');
899
        if (nreceived && timing)
900
                (void)printf("round-trip min/avg/max = %ld.%ld/%lu.%ld/%ld.%ld ms\n",
901
                        tmin/10, tmin%10,
902
                        (tsum / (nreceived + nrepeats))/10,
903
                        (tsum / (nreceived + nrepeats))%10,
904
                        tmax/10, tmax%10);
905
 
906
        if (nreceived==0) exit(1);
907
        exit(0);
908
}
909
 
910
#ifdef notdef
911
static char *ttab[] = {
912
        "Echo Reply",           /* ip + seq + udata */
913
        "Dest Unreachable",     /* net, host, proto, port, frag, sr + IP */
914
        "Source Quench",        /* IP */
915
        "Redirect",             /* redirect type, gateway, + IP  */
916
        "Echo",
917
        "Time Exceeded",        /* transit, frag reassem + IP */
918
        "Parameter Problem",    /* pointer + IP */
919
        "Timestamp",            /* id + seq + three timestamps */
920
        "Timestamp Reply",      /* " */
921
        "Info Request",         /* id + sq */
922
        "Info Reply"            /* " */
923
};
924
#endif
925
 
926
/*
927
 * pr_icmph --
928
 *      Print a descriptive string about an ICMP header.
929
 */
930
static void
931
pr_icmph(struct icmphdr *icp)
932
{
933
        switch(icp->icmp_type) {
934
        case ICMP_ECHOREPLY:
935
                (void)printf("Echo Reply\n");
936
                /* XXX ID + Seq + Data */
937
                break;
938
        case ICMP_DEST_UNREACH:
939
                switch(icp->icmp_code) {
940
                case ICMP_NET_UNREACH:
941
                        (void)printf("Destination Net Unreachable\n");
942
                        break;
943
                case ICMP_HOST_UNREACH:
944
                        (void)printf("Destination Host Unreachable\n");
945
                        break;
946
                case ICMP_PROT_UNREACH:
947
                        (void)printf("Destination Protocol Unreachable\n");
948
                        break;
949
                case ICMP_PORT_UNREACH:
950
                        (void)printf("Destination Port Unreachable\n");
951
                        break;
952
                case ICMP_FRAG_NEEDED:
953
                        (void)printf("frag needed and DF set\n");
954
                        break;
955
                case ICMP_SR_FAILED:
956
                        (void)printf("Source Route Failed\n");
957
                        break;
958
                case ICMP_NET_UNKNOWN:
959
                        (void)printf("Network Unknown\n");
960
                        break;
961
                case ICMP_HOST_UNKNOWN:
962
                        (void)printf("Host Unknown\n");
963
                        break;
964
                case ICMP_HOST_ISOLATED:
965
                        (void)printf("Host Isolated\n");
966
                        break;
967
                case ICMP_NET_UNR_TOS:
968
                        printf("Destination Network Unreachable At This TOS\n");
969
                        break;
970
                case ICMP_HOST_UNR_TOS:
971
                        printf("Destination Host Unreachable At This TOS\n");
972
                        break;
973
#ifdef ICMP_PKT_FILTERED
974
                case ICMP_PKT_FILTERED:
975
                        (void)printf("Packet Filtered\n");
976
                        break;
977
#endif
978
#ifdef ICMP_PREC_VIOLATION
979
                case ICMP_PREC_VIOLATION:
980
                        (void)printf("Precedence Violation\n");
981
                        break;
982
#endif
983
#ifdef ICMP_PREC_CUTOFF
984
                case ICMP_PREC_CUTOFF:
985
                        (void)printf("Precedence Cutoff\n");
986
                        break;
987
#endif
988
                default:
989
                        (void)printf("Dest Unreachable, Unknown Code: %d\n",
990
                            icp->icmp_code);
991
                        break;
992
                }
993
                /* Print returned IP header information */
994
#ifndef icmp_data
995
                pr_retip((struct iphdr *)(icp + 1));
996
#else
997
                pr_retip((struct iphdr *)icp->icmp_data);
998
#endif
999
                break;
1000
        case ICMP_SOURCE_QUENCH:
1001
                (void)printf("Source Quench\n");
1002
#ifndef icmp_data
1003
                pr_retip((struct iphdr *)(icp + 1));
1004
#else
1005
                pr_retip((struct iphdr *)icp->icmp_data);
1006
#endif
1007
                break;
1008
        case ICMP_REDIRECT:
1009
                switch(icp->icmp_code) {
1010
                case ICMP_REDIR_NET:
1011
                        (void)printf("Redirect Network");
1012
                        break;
1013
                case ICMP_REDIR_HOST:
1014
                        (void)printf("Redirect Host");
1015
                        break;
1016
                case ICMP_REDIR_NETTOS:
1017
                        (void)printf("Redirect Type of Service and Network");
1018
                        break;
1019
                case ICMP_REDIR_HOSTTOS:
1020
                        (void)printf("Redirect Type of Service and Host");
1021
                        break;
1022
                default:
1023
                        (void)printf("Redirect, Bad Code: %d", icp->icmp_code);
1024
                        break;
1025
                }
1026
                (void)printf("(New addr: %s)\n",
1027
                             inet_ntoa(icp->icmp_gwaddr));
1028
#ifndef icmp_data
1029
                pr_retip((struct iphdr *)(icp + 1));
1030
#else
1031
                pr_retip((struct iphdr *)icp->icmp_data);
1032
#endif
1033
                break;
1034
        case ICMP_ECHO:
1035
                (void)printf("Echo Request\n");
1036
                /* XXX ID + Seq + Data */
1037
                break;
1038
        case ICMP_TIME_EXCEEDED:
1039
                switch(icp->icmp_code) {
1040
                case ICMP_EXC_TTL:
1041
                        (void)printf("Time to live exceeded\n");
1042
                        break;
1043
                case ICMP_EXC_FRAGTIME:
1044
                        (void)printf("Frag reassembly time exceeded\n");
1045
                        break;
1046
                default:
1047
                        (void)printf("Time exceeded, Bad Code: %d\n",
1048
                            icp->icmp_code);
1049
                        break;
1050
                }
1051
#ifndef icmp_data
1052
                pr_retip((struct iphdr *)(icp + 1));
1053
#else
1054
                pr_retip((struct iphdr *)icp->icmp_data);
1055
#endif
1056
                break;
1057
        case ICMP_PARAMETERPROB:
1058
                (void)printf("Parameter problem: IP address = %s\n",
1059
                        inet_ntoa (icp->icmp_gwaddr));
1060
#ifndef icmp_data
1061
                pr_retip((struct iphdr *)(icp + 1));
1062
#else
1063
                pr_retip((struct iphdr *)icp->icmp_data);
1064
#endif
1065
                break;
1066
        case ICMP_TIMESTAMP:
1067
                (void)printf("Timestamp\n");
1068
                /* XXX ID + Seq + 3 timestamps */
1069
                break;
1070
        case ICMP_TIMESTAMPREPLY:
1071
                (void)printf("Timestamp Reply\n");
1072
                /* XXX ID + Seq + 3 timestamps */
1073
                break;
1074
        case ICMP_INFO_REQUEST:
1075
                (void)printf("Information Request\n");
1076
                /* XXX ID + Seq */
1077
                break;
1078
        case ICMP_INFO_REPLY:
1079
                (void)printf("Information Reply\n");
1080
                /* XXX ID + Seq */
1081
                break;
1082
#ifdef ICMP_MASKREQ
1083
        case ICMP_MASKREQ:
1084
                (void)printf("Address Mask Request\n");
1085
                break;
1086
#endif
1087
#ifdef ICMP_MASKREPLY
1088
        case ICMP_MASKREPLY:
1089
                (void)printf("Address Mask Reply\n");
1090
                break;
1091
#endif
1092
        default:
1093
                (void)printf("Bad ICMP type: %d\n", icp->icmp_type);
1094
        }
1095
}
1096
 
1097
/*
1098
 * pr_iph --
1099
 *      Print an IP header with options.
1100
 */
1101
static void
1102
pr_iph(struct iphdr *ip)
1103
{
1104
        int hlen;
1105
        u_char *cp;
1106
 
1107
        hlen = ip->ip_hl << 2;
1108
        cp = (u_char *)ip + 20;         /* point to options */
1109
 
1110
        (void)printf("Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst Data\n");
1111
        (void)printf(" %1x  %1x  %02x %04x %04x",
1112
            ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id);
1113
        (void)printf("   %1x %04x", ((ip->ip_off) & 0xe000) >> 13,
1114
            (ip->ip_off) & 0x1fff);
1115
        (void)printf("  %02x  %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum);
1116
        (void)printf(" %s ", inet_ntoa(*((struct in_addr *) &ip->ip_src)));
1117
        (void)printf(" %s ", inet_ntoa(*((struct in_addr *) &ip->ip_dst)));
1118
        /* dump and option bytes */
1119
        while (hlen-- > 20) {
1120
                (void)printf("%02x", *cp++);
1121
        }
1122
        (void)putchar('\n');
1123
}
1124
 
1125
/*
1126
 * pr_addr --
1127
 *      Return an ascii host address as a dotted quad and optionally with
1128
 * a hostname.
1129
 */
1130
static char *
1131
pr_addr(u_long l)
1132
{
1133
        struct hostent *hp;
1134
        static char buf[256];
1135
 
1136
        if ((options & F_NUMERIC) ||
1137
            !(hp = gethostbyaddr((char *)&l, 4, AF_INET)))
1138
                (void)sprintf(buf, /*sizeof(buf),*/ "%s",
1139
                               inet_ntoa(*(struct in_addr *)&l));
1140
        else
1141
                (void)sprintf(buf, /*sizeof(buf),*/ "%s (%s)", hp->h_name,
1142
                    inet_ntoa(*(struct in_addr *)&l));
1143
        return(buf);
1144
}
1145
 
1146
/*
1147
 * pr_retip --
1148
 *      Dump some info on a returned (via ICMP) IP packet.
1149
 */
1150
static void
1151
pr_retip(struct iphdr *ip)
1152
{
1153
        int hlen;
1154
        u_char *cp;
1155
 
1156
        pr_iph(ip);
1157
        hlen = ip->ip_hl << 2;
1158
        cp = (u_char *)ip + hlen;
1159
 
1160
        if (ip->ip_p == 6)
1161
                (void)printf("TCP: from port %u, to port %u (decimal)\n",
1162
                    (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
1163
        else if (ip->ip_p == 17)
1164
                (void)printf("UDP: from port %u, to port %u (decimal)\n",
1165
                        (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
1166
}
1167
 
1168
static void
1169
fill(void *bp1, char *patp)
1170
{
1171
        register int ii, jj, kk;
1172
        int pat[16];
1173
        char *cp, *bp = (char *)bp1;
1174
 
1175
        for (cp = patp; *cp; cp++)
1176
                if (!isxdigit(*cp)) {
1177
                        (void)fprintf(stderr,
1178
                            "ping: patterns must be specified as hex digits.\n");
1179
                        exit(2);
1180
                }
1181
        ii = sscanf(patp,
1182
            "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
1183
            &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
1184
            &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
1185
            &pat[13], &pat[14], &pat[15]);
1186
 
1187
        if (ii > 0)
1188
                for (kk = 0; kk <= MAXPACKET - (8 + ii); kk += ii)
1189
                        for (jj = 0; jj < ii; ++jj)
1190
                                bp[jj + kk] = pat[jj];
1191
        if (!(options & F_QUIET)) {
1192
                (void)printf("PATTERN: 0x");
1193
                for (jj = 0; jj < ii; ++jj)
1194
                        (void)printf("%02x", bp[jj] & 0xFF);
1195
                (void)printf("\n");
1196
        }
1197
}
1198
 
1199
static void
1200
usage(void)
1201
{
1202
        (void)fprintf(stderr,
1203
            "usage: ping [-LRdfnqrv] [-c count] [-i wait] [-l preload]\n\t[-p pattern] [-s packetsize] [-t ttl] [-I interface address] host\n");
1204
        exit(2);
1205
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.