#include <sys/param.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/sysctl.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/ip_var.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MAX_LSRR ((MAX_IPOPTLEN - 4) / 4)
struct packetdata {
u_char seq;
u_int8_t ttl;
u_int32_t sec;
u_int32_t usec;
};
#define ICMP_EXT_OFFSET 8 + 128
#define ICMP_EXT_VERSION 2
#define EXT_VERSION(x) (((x) & 0xf0000000) >> 28)
#define EXT_CHECKSUM(x) ((x) & 0x0000ffff)
struct icmp_ext_obj_hdr {
u_short length;
u_char class_num;
#define MPLS_STACK_ENTRY_CLASS 1
u_char c_type;
#define MPLS_STACK_ENTRY_C_TYPE 1
};
#define MPLS_LABEL(x) (((x) & 0xfffff000) >> 12)
#define MPLS_EXP(x) (((x) & 0x00000e00) >> 9)
#define MPLS_STACK(x) (((x) & 0x00000100) >> 8)
#define MPLS_TTL(x) ((x) & 0x000000ff)
static struct in_addr gateway[MAX_LSRR + 1];
static int lsrrlen = 0;
static int32_t sec_perturb;
static int32_t usec_perturb;
static u_char packet[512], *outpacket;
static void decode_extensions(unsigned char *, int);
static void dump_packet(void);
static int wait_for_reply(int, struct sockaddr_in *, struct timeval *);
static void send_probe(int, u_int8_t, int, struct sockaddr_in *);
static int packet_ok(u_char *, int, struct sockaddr_in *, int, int);
static const char *pr_type(u_int8_t);
static void print(u_char *, int, struct sockaddr_in *);
static char *inetname(struct in_addr);
static u_short in_cksum(u_short *, int);
static void usage(void) __dead2;
static int s;
static int sndsock;
static int datalen;
static int headerlen;
static char *source = NULL;
static char *hostname;
static int nprobes = 3;
static u_int8_t max_ttl = IPDEFTTL;
static u_int8_t first_ttl = 1;
static u_short ident;
static u_short port = 32768+666;
static u_char proto = IPPROTO_UDP;
static u_int8_t icmp_type = ICMP_ECHO;
static u_char icmp_code = 0;
static int options;
static int verbose;
static int waittime = 5;
static int nflag;
static int dump;
static int Mflag;
int
main(int argc, char *argv[])
{
int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
int ttl_flag = 0, incflag = 1, protoset = 0, sump = 0;
int ch, i, lsrr = 0, on = 1, probe, seq = 0, tos = 0;
size_t size = sizeof(max_ttl);
struct sockaddr_in from, to;
struct hostent *hp;
u_int32_t tmprnd;
struct ip *ip;
u_int8_t ttl;
char *ep;
long l;
if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
err(5, "icmp socket");
if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
err(5, "raw socket");
seteuid(getuid());
setuid(getuid());
sysctl(mib, NELEM(mib), &max_ttl, &size, NULL, 0);
while ((ch = getopt(argc, argv, "SDIdg:f:m:np:q:rs:t:w:vlP:cM")) != -1)
switch (ch) {
case 'S':
sump = 1;
break;
case 'f':
errno = 0;
ep = NULL;
l = strtol(optarg, &ep, 10);
if (errno || !*optarg || *ep || l < 1 || l > max_ttl)
errx(1, "min ttl must be 1 to %u.", max_ttl);
first_ttl = (u_int8_t)l;
break;
case 'c':
incflag = 0;
break;
case 'd':
options |= SO_DEBUG;
break;
case 'D':
dump = 1;
break;
case 'g':
if (lsrr >= MAX_LSRR)
errx(1, "too many gateways; max %d", MAX_LSRR);
if (inet_aton(optarg, &gateway[lsrr]) == 0) {
hp = gethostbyname(optarg);
if (hp == NULL)
errx(1, "unknown host %s", optarg);
memcpy(&gateway[lsrr], hp->h_addr, hp->h_length);
}
if (++lsrr == 1)
lsrrlen = 4;
lsrrlen += 4;
break;
case 'I':
if (protoset)
errx(1, "protocol already set with -P");
protoset = 1;
proto = IPPROTO_ICMP;
break;
case 'l':
ttl_flag++;
break;
case 'm':
errno = 0;
ep = NULL;
l = strtol(optarg, &ep, 10);
if (errno || !*optarg || *ep || l < first_ttl ||
l > MAXTTL)
errx(1, "max ttl must be %u to %u.", first_ttl,
MAXTTL);
max_ttl = (u_int8_t)l;
break;
case 'M':
Mflag = 1;
break;
case 'n':
nflag++;
break;
case 'p':
errno = 0;
ep = NULL;
l = strtol(optarg, &ep, 10);
if (errno || !*optarg || *ep || l <= 0 || l >= 65536)
errx(1, "port must be >0, <65536.");
port = (int)l;
break;
case 'P':
if (protoset)
errx(1, "protocol already set with -I");
protoset = 1;
errno = 0;
ep = NULL;
l = strtol(optarg, &ep, 10);
if (errno || !*optarg || *ep || l < 1 ||
l >= IPPROTO_MAX) {
struct protoent *pent;
pent = getprotobyname(optarg);
if (pent)
proto = pent->p_proto;
else
errx(1, "proto must be >=1, or a name.");
} else
proto = (int)l;
break;
case 'q':
errno = 0;
ep = NULL;
l = strtol(optarg, &ep, 10);
if (errno || !*optarg || *ep || l < 1 || l > INT_MAX)
errx(1, "nprobes must be >0.");
nprobes = (int)l;
break;
case 'r':
options |= SO_DONTROUTE;
break;
case 's':
source = optarg;
break;
case 't':
errno = 0;
ep = NULL;
l = strtol(optarg, &ep, 10);
if (errno || !*optarg || *ep || l < 0 || l > 255)
errx(1, "tos must be 0 to 255.");
tos = (int)l;
break;
case 'v':
verbose++;
break;
case 'w':
errno = 0;
ep = NULL;
l = strtol(optarg, &ep, 10);
if (errno || !*optarg || *ep || l <= 1 || l > INT_MAX)
errx(1, "wait must be >1 sec.");
waittime = (int)l;
break;
default:
usage();
}
argc -= optind;
argv += optind;
if (argc < 1)
usage();
setlinebuf (stdout);
memset(&to, 0, sizeof(struct sockaddr));
to.sin_family = AF_INET;
if (inet_aton(*argv, &to.sin_addr) != 0)
hostname = *argv;
else {
hp = gethostbyname(*argv);
if (hp == NULL)
errx(1, "unknown host %s", *argv);
to.sin_family = hp->h_addrtype;
memcpy(&to.sin_addr, hp->h_addr, hp->h_length);
if ((hostname = strdup(hp->h_name)) == NULL)
err(1, "malloc");
if (hp->h_addr_list[1] != NULL)
warnx("Warning: %s has multiple addresses; using %s",
hostname, inet_ntoa(to.sin_addr));
}
if (*++argv) {
errno = 0;
ep = NULL;
l = strtol(*argv, &ep, 10);
if (errno || !*argv || *ep || l < 0 || l > INT_MAX)
errx(1, "datalen out of range");
datalen = (int)l;
}
switch (proto) {
case IPPROTO_UDP:
headerlen = (sizeof(struct ip) + lsrrlen +
sizeof(struct udphdr) + sizeof(struct packetdata));
break;
case IPPROTO_ICMP:
headerlen = (sizeof(struct ip) + lsrrlen +
sizeof(struct icmp) + sizeof(struct packetdata));
break;
default:
headerlen = (sizeof(struct ip) + lsrrlen +
sizeof(struct packetdata));
}
if (datalen < 0 || datalen > IP_MAXPACKET - headerlen)
errx(1, "packet size must be 0 to %d.",
IP_MAXPACKET - headerlen);
datalen += headerlen;
outpacket = (u_char *)malloc(datalen);
if (outpacket == NULL)
err(1, "malloc");
memset(outpacket, 0, datalen);
ip = (struct ip *)outpacket;
if (lsrr != 0) {
u_char *p = (u_char *)(ip + 1);
*p++ = IPOPT_NOP;
*p++ = IPOPT_LSRR;
*p++ = lsrrlen - 1;
*p++ = IPOPT_MINOFF;
gateway[lsrr] = to.sin_addr;
for (i = 1; i <= lsrr; i++) {
memcpy(p, &gateway[i], sizeof(struct in_addr));
p += sizeof(struct in_addr);
}
ip->ip_dst = gateway[0];
} else
ip->ip_dst = to.sin_addr;
ip->ip_off = 0;
ip->ip_hl = (sizeof(struct ip) + lsrrlen) >> 2;
ip->ip_p = proto;
ip->ip_v = IPVERSION;
ip->ip_tos = tos;
ident = (getpid() & 0xffff) | 0x8000;
tmprnd = arc4random();
sec_perturb = (tmprnd & 0x80000000) ? -(tmprnd & 0x7ff) :
(tmprnd & 0x7ff);
usec_perturb = arc4random();
if (options & SO_DEBUG)
setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof(on));
#ifdef SO_SNDBUF
if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
sizeof(datalen)) < 0)
err(6, "SO_SNDBUF");
#endif
#ifdef IP_HDRINCL
if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
sizeof(on)) < 0)
err(6, "IP_HDRINCL");
#endif
if (options & SO_DEBUG)
setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
(char *)&on, sizeof(on));
if (options & SO_DONTROUTE)
setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
(char *)&on, sizeof(on));
if (source) {
memset(&from, 0, sizeof(struct sockaddr));
from.sin_family = AF_INET;
if (inet_aton(source, &from.sin_addr) == 0)
errx(1, "unknown host %s", source);
ip->ip_src = from.sin_addr;
if (getuid() != 0 &&
(ntohl(from.sin_addr.s_addr) & 0xff000000U) == 0x7f000000U &&
(ntohl(to.sin_addr.s_addr) & 0xff000000U) != 0x7f000000U)
errx(1, "source is on 127/8, destination is not");
if (getuid() &&
bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
err(1, "bind");
}
fprintf(stderr, "traceroute to %s (%s)", hostname,
inet_ntoa(to.sin_addr));
if (source)
fprintf(stderr, " from %s", source);
fprintf(stderr, ", %u hops max, %d byte packets\n", max_ttl, datalen);
fflush(stderr);
if (first_ttl > 1)
printf("Skipping %u intermediate hops\n", first_ttl - 1);
for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
int got_there = 0, unreachable = 0, timeout = 0, loss;
int gotlastaddr = 0;
in_addr_t lastaddr = 0;
quad_t dt;
printf("%2u ", ttl);
for (probe = 0, loss = 0; probe < nprobes; ++probe) {
int cc;
struct timeval t1, t2;
int code;
gettimeofday(&t1, NULL);
send_probe(++seq, ttl, incflag, &to);
while ((cc = wait_for_reply(s, &from, &t1))) {
gettimeofday(&t2, NULL);
if (t2.tv_sec - t1.tv_sec > waittime) {
cc = 0;
break;
}
i = packet_ok(packet, cc, &from, seq, incflag);
if (i == 0)
continue;
if (!gotlastaddr ||
from.sin_addr.s_addr != lastaddr) {
if (gotlastaddr)
printf("\n ");
print(packet, cc, &from);
lastaddr = from.sin_addr.s_addr;
++gotlastaddr;
}
dt = (quad_t)(t2.tv_sec - t1.tv_sec) * 1000000 +
(quad_t)(t2.tv_usec - t1.tv_usec);
printf(" %u", (u_int)(dt / 1000));
if (dt % 1000)
printf(".%u", (u_int)(dt % 1000));
printf(" ms");
ip = (struct ip *)packet;
if (ttl_flag)
printf(" (%u)", ip->ip_ttl);
if (i == -2) {
#ifndef ARCHAIC
ip = (struct ip *)packet;
if (ip->ip_ttl <= 1)
printf(" !");
#endif
++got_there;
break;
}
if (i == -1)
break;
code = i - 1;
switch (code) {
case ICMP_UNREACH_PORT:
#ifndef ARCHAIC
ip = (struct ip *)packet;
if (ip->ip_ttl <= 1)
printf(" !");
#endif
++got_there;
break;
case ICMP_UNREACH_NET:
++unreachable;
printf(" !N");
break;
case ICMP_UNREACH_HOST:
++unreachable;
printf(" !H");
break;
case ICMP_UNREACH_PROTOCOL:
++got_there;
printf(" !P");
break;
case ICMP_UNREACH_NEEDFRAG:
++unreachable;
printf(" !F");
break;
case ICMP_UNREACH_SRCFAIL:
++unreachable;
printf(" !S");
break;
case ICMP_UNREACH_FILTER_PROHIB:
++unreachable;
printf(" !X");
break;
case ICMP_UNREACH_NET_PROHIB:
++unreachable;
printf(" !A");
break;
case ICMP_UNREACH_HOST_PROHIB:
++unreachable;
printf(" !C");
break;
case ICMP_UNREACH_NET_UNKNOWN:
case ICMP_UNREACH_HOST_UNKNOWN:
++unreachable;
printf(" !U");
break;
case ICMP_UNREACH_ISOLATED:
++unreachable;
printf(" !I");
break;
case ICMP_UNREACH_TOSNET:
case ICMP_UNREACH_TOSHOST:
++unreachable;
printf(" !T");
break;
default:
++unreachable;
printf(" !<%d>", i - 1);
break;
}
break;
}
if (cc == 0) {
printf(" *");
timeout++;
loss++;
}
else if (cc && probe == nprobes - 1 && Mflag)
decode_extensions(packet, cc);
fflush(stdout);
}
if (sump)
printf(" (%d%% loss)", (loss * 100) / nprobes);
putchar('\n');
if (got_there || (unreachable && (unreachable + timeout) >= nprobes))
break;
}
exit(0);
}
static int
wait_for_reply(int sock, struct sockaddr_in *from, struct timeval *sent)
{
socklen_t fromlen = sizeof (*from);
struct timeval now, wait;
int cc = 0, fdsn;
fd_set *fdsp;
fdsn = howmany(sock+1, NFDBITS) * sizeof(fd_mask);
if ((fdsp = (fd_set *)malloc(fdsn)) == NULL)
err(1, "malloc");
memset(fdsp, 0, fdsn);
FD_SET(sock, fdsp);
gettimeofday(&now, NULL);
wait.tv_sec = (sent->tv_sec + waittime) - now.tv_sec;
wait.tv_usec = sent->tv_usec - now.tv_usec;
if (wait.tv_usec < 0) {
wait.tv_usec += 1000000;
wait.tv_sec--;
}
if (wait.tv_sec < 0)
wait.tv_sec = wait.tv_usec = 0;
if (select(sock+1, fdsp, NULL, NULL, &wait) > 0)
cc = recvfrom(s, (char *)packet, sizeof(packet), 0,
(struct sockaddr *)from, &fromlen);
free(fdsp);
return (cc);
}
static void
decode_extensions(unsigned char *buf, int ip_len)
{
uint32_t *cmn_hdr;
struct icmp_ext_obj_hdr *obj_hdr;
uint32_t mpls_hdr;
int data_len, obj_len;
struct ip *ip;
ip = (struct ip *)buf;
if (ip_len <= (int)(sizeof(struct ip) + ICMP_EXT_OFFSET)) {
return;
}
buf += (ip->ip_hl << 2) + ICMP_EXT_OFFSET;
cmn_hdr = (uint32_t *)buf;
if (EXT_VERSION(ntohl(*cmn_hdr)) != ICMP_EXT_VERSION) {
return;
}
data_len = ip_len - ((u_char *)cmn_hdr - (u_char *)ip);
if (EXT_CHECKSUM(ntohl(*cmn_hdr)) &&
in_cksum((u_short *)cmn_hdr, data_len)) {
return;
}
buf += sizeof(*cmn_hdr);
data_len -= sizeof(*cmn_hdr);
while (data_len >= (int)sizeof(struct icmp_ext_obj_hdr)) {
unsigned char *nextbuf;
obj_hdr = (struct icmp_ext_obj_hdr *)buf;
obj_len = ntohs(obj_hdr->length);
if (obj_len < (int)sizeof(*obj_hdr) || obj_len > data_len)
return;
if (obj_len & 3)
return;
nextbuf = buf + obj_len;
data_len -= obj_len;
buf += sizeof(struct icmp_ext_obj_hdr);
obj_len -= sizeof(struct icmp_ext_obj_hdr);
switch (obj_hdr->class_num) {
case MPLS_STACK_ENTRY_CLASS:
switch (obj_hdr->c_type) {
case MPLS_STACK_ENTRY_C_TYPE:
while (obj_len >= (int)sizeof(uint32_t)) {
mpls_hdr = ntohl(*(uint32_t *)buf);
buf += sizeof(uint32_t);
obj_len -= sizeof(uint32_t);
printf(" [MPLS: Label %d Exp %d]",
MPLS_LABEL(mpls_hdr),
MPLS_EXP(mpls_hdr));
}
if (obj_len > 0) {
return;
}
break;
default:
buf = nextbuf;
break;
}
break;
default:
buf = nextbuf;
break;
}
}
}
static void
dump_packet(void)
{
u_char *p;
int i;
fprintf(stderr, "packet data:");
for (p = outpacket, i = 0; i < datalen; i++) {
if ((i % 24) == 0)
fprintf(stderr, "\n ");
fprintf(stderr, " %02x", *p++);
}
fprintf(stderr, "\n");
}
static void
send_probe(int seq, u_int8_t ttl, int iflag, struct sockaddr_in *to)
{
struct ip *ip = (struct ip *)outpacket;
u_char *p = (u_char *)(ip + 1);
struct udphdr *up = (struct udphdr *)(p + lsrrlen);
struct icmp *icmpp = (struct icmp *)(p + lsrrlen);
struct packetdata *op;
struct timeval tv;
int i;
ip->ip_len = htons(datalen);
ip->ip_ttl = ttl;
ip->ip_id = htons(ident+seq);
switch (proto) {
case IPPROTO_ICMP:
icmpp->icmp_type = icmp_type;
icmpp->icmp_code = icmp_code;
icmpp->icmp_seq = htons(seq);
icmpp->icmp_id = htons(ident);
op = (struct packetdata *)(icmpp + 1);
break;
case IPPROTO_UDP:
up->uh_sport = htons(ident);
if (iflag)
up->uh_dport = htons(port+seq);
else
up->uh_dport = htons(port);
up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip) -
lsrrlen));
up->uh_sum = 0;
op = (struct packetdata *)(up + 1);
break;
default:
op = (struct packetdata *)(ip + 1);
break;
}
op->seq = seq;
op->ttl = ttl;
gettimeofday(&tv, NULL);
op->sec = htonl(tv.tv_sec + sec_perturb);
op->usec = htonl((tv.tv_usec + usec_perturb) % 1000000);
if (proto == IPPROTO_ICMP && icmp_type == ICMP_ECHO) {
icmpp->icmp_cksum = 0;
icmpp->icmp_cksum = in_cksum((u_short *)icmpp,
datalen - sizeof(struct ip) - lsrrlen);
if (icmpp->icmp_cksum == 0)
icmpp->icmp_cksum = 0xffff;
}
if (dump)
dump_packet();
i = sendto(sndsock, outpacket, datalen, 0, (struct sockaddr *)to,
sizeof(struct sockaddr_in));
if (i < 0 || i != datalen) {
if (i < 0)
perror("sendto");
printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
datalen, i);
fflush(stdout);
}
}
static const char *ttab[] = {
"Echo Reply",
"ICMP 1",
"ICMP 2",
"Dest Unreachable",
"Source Quench",
"Redirect",
"ICMP 6",
"ICMP 7",
"Echo",
"Router Advert",
"Router Solicit",
"Time Exceeded",
"Param Problem",
"Timestamp",
"Timestamp Reply",
"Info Request",
"Info Reply",
"Mask Request",
"Mask Reply"
};
static const char *
pr_type(u_int8_t t)
{
if (t > 18)
return ("OUT-OF-RANGE");
return (ttab[t]);
}
static int
packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq, int iflag)
{
struct icmp *icp;
u_char code;
u_int8_t type;
int hlen;
#ifndef ARCHAIC
struct ip *ip;
ip = (struct ip *) buf;
hlen = ip->ip_hl << 2;
if (cc < hlen + ICMP_MINLEN) {
if (verbose)
printf("packet too short (%d bytes) from %s\n", cc,
inet_ntoa(from->sin_addr));
return (0);
}
cc -= hlen;
icp = (struct icmp *)(buf + hlen);
#else
icp = (struct icmp *)buf;
#endif
type = icp->icmp_type;
code = icp->icmp_code;
if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
type == ICMP_UNREACH || type == ICMP_ECHOREPLY) {
struct ip *hip;
struct udphdr *up;
struct icmp *icmpp;
hip = &icp->icmp_ip;
hlen = hip->ip_hl << 2;
switch (proto) {
case IPPROTO_ICMP:
if (icmp_type == ICMP_ECHO &&
type == ICMP_ECHOREPLY &&
icp->icmp_id == htons(ident) &&
icp->icmp_seq == htons(seq))
return (-2);
icmpp = (struct icmp *)((u_char *)hip + hlen);
if (hlen + 8 <= cc && hip->ip_p == IPPROTO_ICMP &&
icmpp->icmp_id == htons(ident) &&
icmpp->icmp_seq == htons(seq))
return (type == ICMP_TIMXCEED? -1 : code + 1);
break;
case IPPROTO_UDP:
up = (struct udphdr *)((u_char *)hip + hlen);
if (hlen + 12 <= cc && hip->ip_p == proto &&
up->uh_sport == htons(ident) &&
((iflag && up->uh_dport == htons(port + seq)) ||
(!iflag && up->uh_dport == htons(port))))
return (type == ICMP_TIMXCEED? -1 : code + 1);
break;
default:
if (hip->ip_p == proto)
return (type == ICMP_TIMXCEED? -1 : code + 1);
}
}
#ifndef ARCHAIC
if (verbose) {
int i;
in_addr_t *lp = (in_addr_t *)&icp->icmp_ip;
printf("\n%d bytes from %s", cc, inet_ntoa(from->sin_addr));
printf(" to %s", inet_ntoa(ip->ip_dst));
printf(": icmp type %u (%s) code %d\n", type, pr_type(type),
icp->icmp_code);
for (i = 4; i < cc ; i += sizeof(in_addr_t))
printf("%2d: x%8.8lx\n", i, (unsigned long)*lp++);
}
#endif
return (0);
}
static void
print(u_char *buf, int cc, struct sockaddr_in *from)
{
struct ip *ip;
int hlen;
ip = (struct ip *) buf;
hlen = ip->ip_hl << 2;
cc -= hlen;
if (nflag)
printf(" %s", inet_ntoa(from->sin_addr));
else
printf(" %s (%s)", inetname(from->sin_addr),
inet_ntoa(from->sin_addr));
if (verbose)
printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
}
static u_short
in_cksum(u_short *addr, int len)
{
u_short *w = addr, answer;
int nleft = len, sum = 0;
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
if (nleft == 1)
sum += *(u_char *)w;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return (answer);
}
static char *
inetname(struct in_addr in)
{
static char domain[MAXHOSTNAMELEN], line[MAXHOSTNAMELEN];
static int first = 1;
struct hostent *hp;
char *cp;
if (first && !nflag) {
first = 0;
if (gethostname(domain, sizeof domain) == 0 &&
(cp = strchr(domain, '.')) != NULL) {
strlcpy(domain, cp + 1, sizeof(domain));
}
}
if (!nflag && in.s_addr != INADDR_ANY) {
hp = gethostbyaddr(&in, sizeof(in), AF_INET);
if (hp != NULL) {
if ((cp = strchr(hp->h_name, '.')) != NULL &&
strcmp(cp + 1, domain) == 0)
*cp = '\0';
strlcpy(line, hp->h_name, sizeof(line));
return (line);
}
}
return (inet_ntoa(in));
}
static void
usage(void)
{
fprintf(stderr,
"usage: %s [-cdDIlMnrSv] [-f first_ttl] [-g gateway_addr] [-m max_ttl]\n"
"\t[-p port] [-P proto] [-q nqueries] [-s src_addr] [-t tos]\n"
"\t[-w waittime] host [packetsize]\n", getprogname());
exit(1);
}