📄 ping.c
字号:
} FD_ZERO(&mask); /* * Loop forever sending pings. (Well, not quite forever.) */ while (1) { if (dosend) { dosend = 0; pinger(); if (npackets && ntransmitted >= npackets) { /* * That was the last one. * Set `interval' to how long to wait for * any remaining replies to roll in. */ interval.tv_sec = compute_waittime(); interval.tv_usec = 0; } /* set time to next ping: the interval */ gettimeofday(&next, NULL); tvadd(&next, &interval); timeout = interval; } else { /* compute time left to next ping */ gettimeofday(&now, NULL); timeout = next; tvsub(&timeout, &now); } FD_SET(sock, &mask); if (select(sock+1, &mask, NULL, NULL, &timeout) < 1) { /* Timed out - exit if none left to send. */ if (npackets && ntransmitted >= npackets) { break; } /* Otherwise, send another */ dosend = 1; continue; } /* A packet's come in, get it */ fromlen = sizeof(from); packlen = recvfrom(sock, inpack, sizeof(inpack), 0, (struct sockaddr *)&from, &fromlen); if (packlen < 0) { if (errno == EINTR) continue; perror("recvfrom"); continue; } if (pr_pack(packlen, &from)) { /* * In flood mode, getting a packet back instantly * triggers the next one. */ if (options & F_FLOOD) { dosend = 1; } } if (npackets && nreceived >= npackets) { /* * Got all the replies - stop. */ break; } }}/********************* setup code ********************/staticintdosockopt(int code1, int code2, int val){ return setsockopt(sock, code1, code2, &val, sizeof(val));}staticvoid settarget(const char *target){ struct hostent *hp; static char namebuf[MAXHOSTNAMELEN]; memset(&whereto, 0, sizeof(whereto)); hp = gethostbyname(target); if (!hp) { fprintf(stderr, "ping: unknown host %s\n", target); exit(2); } whereto.sin_family = hp->h_addrtype; if (hp->h_length > (int)sizeof(whereto.sin_addr)) { hp->h_length = sizeof(whereto.sin_addr); } memcpy(&whereto.sin_addr, hp->h_addr, hp->h_length); strncpy(namebuf, hp->h_name, sizeof(namebuf) - 1); namebuf[sizeof(namebuf)-1] = 0; hostname = namebuf;}/* * Handle -p option. */staticvoidfill(const char *patstr){ size_t i; int j, patlen; int pat[16]; for (i=0; patstr[i]; i++) { if (!isxdigit(patstr[i])) { fprintf(stderr, "ping: patterns for -p must be " "specified as hex digits.\n"); exit(2); } } patlen = sscanf(patstr, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6], &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12], &pat[13], &pat[14], &pat[15]); /* * Just fill the whole output packet with the pattern, rather * than just the data section. The part at the beginning will get * overlaid with the icmp header and whatnot. * * This means we don't have to know yet if we're sending the * timeval (which depends on the selected packet size), which * is good since get called from option processing and the -s * option might not have turned up yet. */ if (patlen > 0) { for (i=0,j=0; i<sizeof(outpack); i++, j=(j+1)%patlen) { outpack[i] = pat[j]; } } if (!(options & F_QUIET)) { printf("PATTERN: 0x"); for (j=0; j<patlen; j++) { printf("%02x", pat[j]&0xFF); } printf("\n"); }}staticvoidusage(void){ fprintf(stderr, "usage: ping [-LRdfnqrv] [-c count] [-i wait] [-l preload]\n" "\t[-p pattern] [-s packetsize] [-t ttl] " "[-I interface address] host\n"); exit(2);}staticintsecure_startup(void){ int am_i_root; struct protoent *proto; static char *null = NULL; /* * Clear environment. * (This protects against various problems with libc.) */ __environ = &null; /* * Certain options require that the man behind the curtain be * root. Since we should be setuid root anyway, check real uid. */ am_i_root = (getuid()==0); /* * Look up ICMP. */ proto = getprotobyname("icmp"); if (!proto) { fprintf(stderr, "ping: unknown protocol icmp.\n"); exit(2); } /* * Open the raw socket. */ sock = socket(AF_INET, SOCK_RAW, proto->p_proto); if (sock < 0) { if (errno==EPERM) { fprintf(stderr, "ping: ping must run as root\n"); } else { perror("ping: socket"); } exit(2); } /* * If someone's messing with us, bail. * It would be nice to issue an error message, but to where? */ if (sock==STDIN_FILENO || sock==STDOUT_FILENO || sock==STDERR_FILENO) { exit(255); } /* * See discussion at the top of this file. * It's not crucial if this fails. */#ifdef SAFE_TO_DROP_ROOT setuid(getuid());#endif return am_i_root;}intmain(int argc, char *argv[]){ struct in_addr ifaddr; int i; int ch, preload, stoptime=0; u_char ttl=0, loop; int am_i_root; char rspace[3 + 4 * NROUTES + 1]; /* record route space */ am_i_root = secure_startup(); preload = 0; while ((ch = getopt(argc, argv, "I:LRc:dfh:i:l:np:qrs:t:vw:"))!=EOF) { switch(ch) { case 'c': npackets = atoi(optarg); if (npackets <= 0) { fprintf(stderr, "ping: bad number of " "packets to transmit.\n"); exit(2); } break; case 'd': options |= F_SO_DEBUG; break; case 'f': if (!am_i_root) { fprintf(stderr, "ping: %s\n", strerror(EPERM)); exit(2); } options |= F_FLOOD; setbuf(stdout, NULL); break; case 'i': /* wait between sending packets */ intervalsecs = atoi(optarg); if (intervalsecs <= 0) { fprintf(stderr,"ping: bad timing interval.\n"); exit(2); } options |= F_INTERVAL; break; case 'l': if (!am_i_root) { fprintf(stderr, "ping: %s\n", strerror(EPERM)); exit(2); } preload = atoi(optarg); if (preload < 0) { fprintf(stderr, "ping: bad preload count.\n"); exit(2); } break; case 'n': options |= F_NUMERIC; break; case 'p': /* fill buffer with user pattern */ options |= F_PINGFILLED; fill(optarg); break; case 'q': options |= F_QUIET; break; case 'R': options |= F_RROUTE; break; case 'r': options |= F_SO_DONTROUTE; break; case 's': /* size of packet to send */ if (!am_i_root) { fprintf(stderr, "ping: %s\n", strerror(EPERM)); exit(2); } datalen = atoi(optarg); if (datalen > MAXPAYLOAD) { fprintf(stderr, "ping: packet size too large.\n"); exit(2); } if (datalen <= 0) { fprintf(stderr,"ping: illegal packet size.\n"); exit(2); } break; case 'v': options |= F_VERBOSE; break; case 'w': stoptime = atoi(optarg); if (stoptime <= 0) { fprintf(stderr,"ping: illegal timeout.\n"); exit(2); } break; case 'L': moptions |= MULTICAST_NOLOOP; loop = 0; break; case 't': moptions |= MULTICAST_TTL; i = atoi(optarg); if (i < 0 || i > 255) { fprintf(stderr, "ping: ttl %d out of range\n", i); exit(2); } ttl = i; break; case 'I': moptions |= MULTICAST_IF; if (!inet_aton(optarg, &ifaddr)) { fprintf(stderr, "ping: bad interface address '%s'\n", optarg); exit(2); } break; default: usage(); } } if (options & F_FLOOD && options & F_INTERVAL) { fprintf(stderr, "ping: -f and -i: Incompatible options.\n"); exit(2); } argc -= optind; argv += optind; if (argc != 1) { usage(); } settarget(argv[0]); /* if there's space for the time, we can time the transfer */ if (datalen >= (int)sizeof(struct timeval)) { timing = 1; } /* If an explicit pattern wasn't set, use a default fill. */ if ((options & F_PINGFILLED)==0) { int i; u_int8_t *ptr = OUTPACK_PAYLOAD; for (i = 0; i < datalen; i++) { ptr[i] = i; } } /* Use this code to identify this ping process */ ident = getpid() & 0xFFFF; if (options & F_SO_DEBUG) { dosockopt(SOL_SOCKET, SO_DEBUG, 1); } if (options & F_SO_DONTROUTE) { dosockopt(SOL_SOCKET, SO_DONTROUTE, 1); } /* this is necessary for broadcast pings to work */ dosockopt(SOL_SOCKET, SO_BROADCAST, 1); /* record route option */ if (options & F_RROUTE) { memset(rspace, 0, sizeof(rspace)); rspace[IPOPT_OPTVAL] = IPOPT_RR; rspace[IPOPT_OLEN] = sizeof(rspace)-1; rspace[IPOPT_OFFSET] = IPOPT_MINOFF; if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, rspace, sizeof(rspace)) < 0) { perror("ping: record route"); exit(2); } } /* * When pinging the broadcast address, you can get a lot of answers. * Doing something so evil is useful if you are trying to stress the * ethernet, or just want to fill the arp cache to get some stuff for * /etc/ethers. */ dosockopt(SOL_SOCKET, SO_RCVBUF, 64*1024); if (moptions & MULTICAST_NOLOOP) { if (dosockopt(IPPROTO_IP, IP_MULTICAST_LOOP, 0)) { perror("can't disable multicast loopback"); exit(92); } } if (moptions & MULTICAST_TTL) { if (dosockopt(IPPROTO_IP, IP_MULTICAST_TTL, ttl)) { perror("can't set multicast time-to-live"); exit(93); } } if (moptions & MULTICAST_IF) { if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr, sizeof(ifaddr))) { perror("can't set multicast source interface"); exit(94); } } if (whereto.sin_family == AF_INET) { printf("PING %s (%s): %d octets data\n", hostname, inet_ntoa(whereto.sin_addr), datalen); } else { printf("PING %s: %d octets data\n", hostname, datalen); } signal(SIGINT, finish); if (stoptime) { signal(SIGALRM, finish); alarm(stoptime); } while (preload--) { /* fire off them quickies */ pinger(); } doping(); finish(0); /* NOTREACHED */ return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -