Changeset View
Changeset View
Standalone View
Standalone View
sbin/ping/ping.c
Show First 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | |||||
#endif /*IPSEC*/ | #endif /*IPSEC*/ | ||||
#include <capsicum_helpers.h> | #include <capsicum_helpers.h> | ||||
#include <ctype.h> | #include <ctype.h> | ||||
#include <err.h> | #include <err.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <math.h> | #include <math.h> | ||||
#include <netdb.h> | #include <netdb.h> | ||||
#include <stddef.h> | |||||
#include <signal.h> | #include <signal.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <sysexits.h> | #include <sysexits.h> | ||||
#include <time.h> | #include <time.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
▲ Show 20 Lines • Show All 116 Lines • ▼ Show 20 Lines | |||||
static void fill(char *, char *); | static void fill(char *, char *); | ||||
static cap_channel_t *capdns_setup(void); | static cap_channel_t *capdns_setup(void); | ||||
static void check_status(void); | static void check_status(void); | ||||
static void finish(void) __dead2; | static void finish(void) __dead2; | ||||
static void pinger(void); | static void pinger(void); | ||||
static char *pr_addr(struct in_addr); | static char *pr_addr(struct in_addr); | ||||
static char *pr_ntime(n_time); | static char *pr_ntime(n_time); | ||||
static void pr_icmph(struct icmp *, struct ip *, const u_char *const); | static void pr_icmph(struct icmp *); | ||||
static void pr_iph(struct ip *); | static void pr_iph(struct ip *); | ||||
static void pr_pack(char *, ssize_t, struct sockaddr_in *, struct timespec *); | static void pr_pack(char *, int, struct sockaddr_in *, struct timespec *); | ||||
static void pr_retip(struct ip *, const u_char *); | static void pr_retip(struct ip *); | ||||
static void status(int); | static void status(int); | ||||
static void stopit(int); | static void stopit(int); | ||||
int | int | ||||
ping(int argc, char *const *argv) | ping(int argc, char *const *argv) | ||||
{ | { | ||||
struct sockaddr_in from, sock_in; | struct sockaddr_in from, sock_in; | ||||
struct in_addr ifaddr; | struct in_addr ifaddr; | ||||
struct timespec last, intvl; | struct timespec last, intvl; | ||||
struct iovec iov; | struct iovec iov; | ||||
struct ip *ip; | |||||
struct msghdr msg; | struct msghdr msg; | ||||
struct sigaction si_sa; | struct sigaction si_sa; | ||||
size_t sz; | size_t sz; | ||||
u_char *datap, packet[IP_MAXPACKET] __aligned(4); | u_char *datap, packet[IP_MAXPACKET] __aligned(4); | ||||
const char *errstr; | const char *errstr; | ||||
char *ep, *source, *target, *payload; | char *ep, *source, *target, *payload; | ||||
struct hostent *hp; | struct hostent *hp; | ||||
#ifdef IPSEC_POLICY_IPSEC | #ifdef IPSEC_POLICY_IPSEC | ||||
▲ Show 20 Lines • Show All 461 Lines • ▼ Show 20 Lines | if (policy_out != NULL) { | ||||
"ipsec policy cannot be configured"); | "ipsec policy cannot be configured"); | ||||
free(buf); | free(buf); | ||||
} | } | ||||
} | } | ||||
#endif /*IPSEC_POLICY_IPSEC*/ | #endif /*IPSEC_POLICY_IPSEC*/ | ||||
#endif /*IPSEC*/ | #endif /*IPSEC*/ | ||||
if (options & F_HDRINCL) { | if (options & F_HDRINCL) { | ||||
struct ip ip; | ip = (struct ip*)outpackhdr; | ||||
memcpy(&ip, outpackhdr, sizeof(ip)); | |||||
if (!(options & (F_TTL | F_MTTL))) { | if (!(options & (F_TTL | F_MTTL))) { | ||||
mib[0] = CTL_NET; | mib[0] = CTL_NET; | ||||
mib[1] = PF_INET; | mib[1] = PF_INET; | ||||
mib[2] = IPPROTO_IP; | mib[2] = IPPROTO_IP; | ||||
mib[3] = IPCTL_DEFTTL; | mib[3] = IPCTL_DEFTTL; | ||||
sz = sizeof(ttl); | sz = sizeof(ttl); | ||||
if (sysctl(mib, 4, &ttl, &sz, NULL, 0) == -1) | if (sysctl(mib, 4, &ttl, &sz, NULL, 0) == -1) | ||||
err(1, "sysctl(net.inet.ip.ttl)"); | err(1, "sysctl(net.inet.ip.ttl)"); | ||||
} | } | ||||
setsockopt(ssend, IPPROTO_IP, IP_HDRINCL, &hold, sizeof(hold)); | setsockopt(ssend, IPPROTO_IP, IP_HDRINCL, &hold, sizeof(hold)); | ||||
ip.ip_v = IPVERSION; | ip->ip_v = IPVERSION; | ||||
ip.ip_hl = sizeof(struct ip) >> 2; | ip->ip_hl = sizeof(struct ip) >> 2; | ||||
ip.ip_tos = tos; | ip->ip_tos = tos; | ||||
ip.ip_id = 0; | ip->ip_id = 0; | ||||
ip.ip_off = htons(df ? IP_DF : 0); | ip->ip_off = htons(df ? IP_DF : 0); | ||||
ip.ip_ttl = ttl; | ip->ip_ttl = ttl; | ||||
ip.ip_p = IPPROTO_ICMP; | ip->ip_p = IPPROTO_ICMP; | ||||
ip.ip_src.s_addr = source ? sock_in.sin_addr.s_addr : INADDR_ANY; | ip->ip_src.s_addr = source ? sock_in.sin_addr.s_addr : INADDR_ANY; | ||||
ip.ip_dst = to->sin_addr; | ip->ip_dst = to->sin_addr; | ||||
memcpy(outpackhdr, &ip, sizeof(ip)); | |||||
} | } | ||||
/* | /* | ||||
* Here we enter capability mode. Further down access to global | * Here we enter capability mode. Further down access to global | ||||
* namespaces (e.g filesystem) is restricted (see capsicum(4)). | * namespaces (e.g filesystem) is restricted (see capsicum(4)). | ||||
* We must connect(2) our socket before this point. | * We must connect(2) our socket before this point. | ||||
*/ | */ | ||||
caph_cache_catpages(); | caph_cache_catpages(); | ||||
▲ Show 20 Lines • Show All 181 Lines • ▼ Show 20 Lines | if (options & F_FLOOD) { | ||||
intvl.tv_sec = interval / 1000; | intvl.tv_sec = interval / 1000; | ||||
intvl.tv_nsec = interval % 1000 * 1000000; | intvl.tv_nsec = interval % 1000 * 1000000; | ||||
} | } | ||||
almost_done = 0; | almost_done = 0; | ||||
while (!finish_up) { | while (!finish_up) { | ||||
struct timespec now, timeout; | struct timespec now, timeout; | ||||
fd_set rfds; | fd_set rfds; | ||||
int n; | int cc, n; | ||||
ssize_t cc; | |||||
check_status(); | check_status(); | ||||
if ((unsigned)srecv >= FD_SETSIZE) | if ((unsigned)srecv >= FD_SETSIZE) | ||||
errx(EX_OSERR, "descriptor too large"); | errx(EX_OSERR, "descriptor too large"); | ||||
FD_ZERO(&rfds); | FD_ZERO(&rfds); | ||||
FD_SET(srecv, &rfds); | FD_SET(srecv, &rfds); | ||||
(void)clock_gettime(CLOCK_MONOTONIC, &now); | (void)clock_gettime(CLOCK_MONOTONIC, &now); | ||||
timespecadd(&last, &intvl, &timeout); | timespecadd(&last, &intvl, &timeout); | ||||
Show All 10 Lines | |||||
#endif | #endif | ||||
msg.msg_namelen = sizeof(from); | msg.msg_namelen = sizeof(from); | ||||
if ((cc = recvmsg(srecv, &msg, 0)) < 0) { | if ((cc = recvmsg(srecv, &msg, 0)) < 0) { | ||||
if (errno == EINTR) | if (errno == EINTR) | ||||
continue; | continue; | ||||
warn("recvmsg"); | warn("recvmsg"); | ||||
continue; | continue; | ||||
} | } | ||||
/* If we have a 0 byte read from recvfrom continue */ | |||||
if (cc == 0) | |||||
continue; | |||||
#ifdef SO_TIMESTAMP | #ifdef SO_TIMESTAMP | ||||
if (cmsg != NULL && | if (cmsg != NULL && | ||||
cmsg->cmsg_level == SOL_SOCKET && | cmsg->cmsg_level == SOL_SOCKET && | ||||
cmsg->cmsg_type == SCM_TIMESTAMP && | cmsg->cmsg_type == SCM_TIMESTAMP && | ||||
cmsg->cmsg_len == CMSG_LEN(sizeof *tv)) { | cmsg->cmsg_len == CMSG_LEN(sizeof *tv)) { | ||||
/* Copy to avoid alignment problems: */ | /* Copy to avoid alignment problems: */ | ||||
memcpy(&now, CMSG_DATA(cmsg), sizeof(now)); | memcpy(&now, CMSG_DATA(cmsg), sizeof(now)); | ||||
tv = &now; | tv = &now; | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | |||||
* bytes of the data portion are used to hold a UNIX "timespec" struct in | * bytes of the data portion are used to hold a UNIX "timespec" struct in | ||||
* host byte-order, to compute the round-trip time. | * host byte-order, to compute the round-trip time. | ||||
*/ | */ | ||||
static void | static void | ||||
pinger(void) | pinger(void) | ||||
{ | { | ||||
struct timespec now; | struct timespec now; | ||||
struct tv32 tv32; | struct tv32 tv32; | ||||
struct icmp icp; | struct ip *ip; | ||||
struct icmp *icp; | |||||
int cc, i; | int cc, i; | ||||
u_char *packet; | u_char *packet; | ||||
packet = outpack; | packet = outpack; | ||||
memcpy(&icp, outpack, ICMP_MINLEN + phdr_len); | memcpy(&icp, &outpack, sizeof(struct icmp *)); | ||||
icp.icmp_type = icmp_type; | icp->icmp_type = icmp_type; | ||||
icp.icmp_code = 0; | icp->icmp_code = 0; | ||||
icp.icmp_cksum = 0; | icp->icmp_cksum = 0; | ||||
icp.icmp_seq = htons(ntransmitted); | icp->icmp_seq = htons(ntransmitted); | ||||
icp.icmp_id = ident; /* ID */ | icp->icmp_id = ident; /* ID */ | ||||
CLR(ntransmitted % mx_dup_ck); | CLR(ntransmitted % mx_dup_ck); | ||||
if ((options & F_TIME) || timing) { | if ((options & F_TIME) || timing) { | ||||
(void)clock_gettime(CLOCK_MONOTONIC, &now); | (void)clock_gettime(CLOCK_MONOTONIC, &now); | ||||
/* | /* | ||||
* Truncate seconds down to 32 bits in order | * Truncate seconds down to 32 bits in order | ||||
* to fit the timestamp within 8 bytes of the | * to fit the timestamp within 8 bytes of the | ||||
* packet. We're only concerned with | * packet. We're only concerned with | ||||
* durations, not absolute times. | * durations, not absolute times. | ||||
*/ | */ | ||||
tv32.tv32_sec = (uint32_t)htonl(now.tv_sec); | tv32.tv32_sec = (uint32_t)htonl(now.tv_sec); | ||||
tv32.tv32_nsec = (uint32_t)htonl(now.tv_nsec); | tv32.tv32_nsec = (uint32_t)htonl(now.tv_nsec); | ||||
if (options & F_TIME) | if (options & F_TIME) | ||||
icp.icmp_otime = htonl((now.tv_sec % (24*60*60)) | icp->icmp_otime = htonl((now.tv_sec % (24*60*60)) | ||||
* 1000 + now.tv_nsec / 1000000); | * 1000 + now.tv_nsec / 1000000); | ||||
if (timing) | if (timing) | ||||
bcopy((void *)&tv32, | bcopy((void *)&tv32, | ||||
(void *)&outpack[ICMP_MINLEN + phdr_len], | (void *)&outpack[ICMP_MINLEN + phdr_len], | ||||
sizeof(tv32)); | sizeof(tv32)); | ||||
} | } | ||||
memcpy(outpack, &icp, ICMP_MINLEN + phdr_len); | |||||
cc = ICMP_MINLEN + phdr_len + datalen; | cc = ICMP_MINLEN + phdr_len + datalen; | ||||
/* compute ICMP checksum here */ | /* compute ICMP checksum here */ | ||||
icp.icmp_cksum = in_cksum(outpack, cc); | icp->icmp_cksum = in_cksum((u_char *)icp, cc); | ||||
/* Update icmp_cksum in the raw packet data buffer. */ | |||||
memcpy(outpack + offsetof(struct icmp, icmp_cksum), &icp.icmp_cksum, | |||||
sizeof(icp.icmp_cksum)); | |||||
if (options & F_HDRINCL) { | if (options & F_HDRINCL) { | ||||
struct ip ip; | |||||
cc += sizeof(struct ip); | cc += sizeof(struct ip); | ||||
ip.ip_len = htons(cc); | ip = (struct ip *)outpackhdr; | ||||
/* Update ip_len in the raw packet data buffer. */ | ip->ip_len = htons(cc); | ||||
memcpy(outpackhdr + offsetof(struct ip, ip_len), &ip.ip_len, | ip->ip_sum = in_cksum(outpackhdr, cc); | ||||
sizeof(ip.ip_len)); | |||||
ip.ip_sum = in_cksum(outpackhdr, cc); | |||||
/* Update ip_sum in the raw packet data buffer. */ | |||||
memcpy(outpackhdr + offsetof(struct ip, ip_sum), &ip.ip_sum, | |||||
sizeof(ip.ip_sum)); | |||||
packet = outpackhdr; | packet = outpackhdr; | ||||
} | } | ||||
i = send(ssend, (char *)packet, cc, 0); | i = send(ssend, (char *)packet, cc, 0); | ||||
if (i < 0 || i != cc) { | if (i < 0 || i != cc) { | ||||
if (i < 0) { | if (i < 0) { | ||||
if (options & F_FLOOD && errno == ENOBUFS) { | if (options & F_FLOOD && errno == ENOBUFS) { | ||||
usleep(FLOOD_BACKOFF); | usleep(FLOOD_BACKOFF); | ||||
return; | return; | ||||
Show All 13 Lines | |||||
/* | /* | ||||
* pr_pack -- | * pr_pack -- | ||||
* Print out the packet, if it came from us. This logic is necessary | * Print out the packet, if it came from us. This logic is necessary | ||||
* because ALL readers of the ICMP socket get a copy of ALL ICMP packets | * because ALL readers of the ICMP socket get a copy of ALL ICMP packets | ||||
* which arrive ('tis only fair). This permits multiple copies of this | * which arrive ('tis only fair). This permits multiple copies of this | ||||
* program to be run without having intermingled output (or statistics!). | * program to be run without having intermingled output (or statistics!). | ||||
*/ | */ | ||||
static void | static void | ||||
pr_pack(char *buf, ssize_t cc, struct sockaddr_in *from, struct timespec *tv) | pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timespec *tv) | ||||
{ | { | ||||
struct in_addr ina; | struct in_addr ina; | ||||
u_char *cp, *dp, l; | u_char *cp, *dp; | ||||
struct icmp icp; | struct icmp *icp, *oicmp; | ||||
struct ip ip; | struct ip *ip, *oip; | ||||
const u_char *icmp_data_raw; | const void *tp; | ||||
ssize_t icmp_data_raw_len; | |||||
double triptime; | double triptime; | ||||
int dupflag, i, j, recv_len; | int dupflag, hlen, i, j, recv_len; | ||||
uint8_t hlen; | |||||
uint16_t seq; | uint16_t seq; | ||||
static int old_rrlen; | static int old_rrlen; | ||||
static char old_rr[MAX_IPOPTLEN]; | static char old_rr[MAX_IPOPTLEN]; | ||||
struct ip oip; | |||||
u_char oip_header_len; | |||||
struct icmp oicmp; | |||||
const u_char *oicmp_raw; | |||||
/* | /* Check the IP header */ | ||||
* Get size of IP header of the received packet. | memcpy(&ip, &buf, sizeof(struct ip *)); | ||||
* The header length is contained in the lower four bits of the first | hlen = ip->ip_hl << 2; | ||||
* byte and represents the number of 4 byte octets the header takes up. | |||||
* | |||||
* The IHL minimum value is 5 (20 bytes) and its maximum value is 15 | |||||
* (60 bytes). | |||||
*/ | |||||
memcpy(&l, buf, sizeof(l)); | |||||
hlen = (l & 0x0f) << 2; | |||||
/* Reject IP packets with a short header */ | |||||
if (hlen < sizeof(struct ip)) { | |||||
if (options & F_VERBOSE) | |||||
warn("IHL too short (%d bytes) from %s", hlen, | |||||
inet_ntoa(from->sin_addr)); | |||||
return; | |||||
} | |||||
memcpy(&ip, buf, sizeof(struct ip)); | |||||
/* Check packet has enough data to carry a valid ICMP header */ | |||||
recv_len = cc; | recv_len = cc; | ||||
if (cc < hlen + ICMP_MINLEN) { | if (cc < hlen + ICMP_MINLEN) { | ||||
if (options & F_VERBOSE) | if (options & F_VERBOSE) | ||||
warn("packet too short (%zd bytes) from %s", cc, | warn("packet too short (%d bytes) from %s", cc, | ||||
inet_ntoa(from->sin_addr)); | inet_ntoa(from->sin_addr)); | ||||
return; | return; | ||||
} | } | ||||
#ifndef icmp_data | |||||
icmp_data_raw = buf + hlen + offsetof(struct icmp, icmp_ip); | |||||
#else | |||||
icmp_data_raw_len = cc - (hlen + offsetof(struct icmp, icmp_data)); | |||||
icmp_data_raw = buf + hlen + offsetof(struct icmp, icmp_data); | |||||
#endif | |||||
/* Now the ICMP part */ | /* Now the ICMP part */ | ||||
cc -= hlen; | cc -= hlen; | ||||
memcpy(&icp, buf + hlen, MIN((ssize_t)sizeof(icp), cc)); | icp = (struct icmp *)(buf + hlen); | ||||
if (icp.icmp_type == icmp_type_rsp) { | if (icp->icmp_type == icmp_type_rsp) { | ||||
if (icp.icmp_id != ident) | if (icp->icmp_id != ident) | ||||
return; /* 'Twas not our ECHO */ | return; /* 'Twas not our ECHO */ | ||||
++nreceived; | ++nreceived; | ||||
triptime = 0.0; | triptime = 0.0; | ||||
if (timing) { | if (timing) { | ||||
struct timespec tv1; | struct timespec tv1; | ||||
struct tv32 tv32; | struct tv32 tv32; | ||||
const u_char *tp; | tp = icp->icmp_data; | ||||
tp = (const char *)tp + phdr_len; | |||||
tp = icmp_data_raw + phdr_len; | |||||
if ((size_t)(cc - ICMP_MINLEN - phdr_len) >= | if ((size_t)(cc - ICMP_MINLEN - phdr_len) >= | ||||
sizeof(tv1)) { | sizeof(tv1)) { | ||||
/* Copy to avoid alignment problems: */ | /* Copy to avoid alignment problems: */ | ||||
memcpy(&tv32, tp, sizeof(tv32)); | memcpy(&tv32, tp, sizeof(tv32)); | ||||
tv1.tv_sec = ntohl(tv32.tv32_sec); | tv1.tv_sec = ntohl(tv32.tv32_sec); | ||||
tv1.tv_nsec = ntohl(tv32.tv32_nsec); | tv1.tv_nsec = ntohl(tv32.tv32_nsec); | ||||
timespecsub(tv, &tv1, tv); | timespecsub(tv, &tv1, tv); | ||||
triptime = ((double)tv->tv_sec) * 1000.0 + | triptime = ((double)tv->tv_sec) * 1000.0 + | ||||
((double)tv->tv_nsec) / 1000000.0; | ((double)tv->tv_nsec) / 1000000.0; | ||||
tsum += triptime; | tsum += triptime; | ||||
tsumsq += triptime * triptime; | tsumsq += triptime * triptime; | ||||
if (triptime < tmin) | if (triptime < tmin) | ||||
tmin = triptime; | tmin = triptime; | ||||
if (triptime > tmax) | if (triptime > tmax) | ||||
tmax = triptime; | tmax = triptime; | ||||
} else | } else | ||||
timing = 0; | timing = 0; | ||||
} | } | ||||
seq = ntohs(icp.icmp_seq); | seq = ntohs(icp->icmp_seq); | ||||
if (TST(seq % mx_dup_ck)) { | if (TST(seq % mx_dup_ck)) { | ||||
++nrepeats; | ++nrepeats; | ||||
--nreceived; | --nreceived; | ||||
dupflag = 1; | dupflag = 1; | ||||
} else { | } else { | ||||
SET(seq % mx_dup_ck); | SET(seq % mx_dup_ck); | ||||
dupflag = 0; | dupflag = 0; | ||||
} | } | ||||
if (options & F_QUIET) | if (options & F_QUIET) | ||||
return; | return; | ||||
if (options & F_WAITTIME && triptime > waittime) { | if (options & F_WAITTIME && triptime > waittime) { | ||||
++nrcvtimeout; | ++nrcvtimeout; | ||||
return; | return; | ||||
} | } | ||||
if (options & F_DOT) | if (options & F_DOT) | ||||
(void)write(STDOUT_FILENO, &BSPACE, 1); | (void)write(STDOUT_FILENO, &BSPACE, 1); | ||||
else { | else { | ||||
(void)printf("%zd bytes from %s: icmp_seq=%u", cc, | (void)printf("%d bytes from %s: icmp_seq=%u", cc, | ||||
pr_addr(from->sin_addr), seq); | pr_addr(from->sin_addr), seq); | ||||
(void)printf(" ttl=%d", ip.ip_ttl); | (void)printf(" ttl=%d", ip->ip_ttl); | ||||
if (timing) | if (timing) | ||||
(void)printf(" time=%.3f ms", triptime); | (void)printf(" time=%.3f ms", triptime); | ||||
if (dupflag) | if (dupflag) | ||||
(void)printf(" (DUP!)"); | (void)printf(" (DUP!)"); | ||||
if (options & F_AUDIBLE) | if (options & F_AUDIBLE) | ||||
(void)write(STDOUT_FILENO, &BBELL, 1); | (void)write(STDOUT_FILENO, &BBELL, 1); | ||||
if (options & F_MASK) { | if (options & F_MASK) { | ||||
/* Just prentend this cast isn't ugly */ | /* Just prentend this cast isn't ugly */ | ||||
(void)printf(" mask=%s", | (void)printf(" mask=%s", | ||||
inet_ntoa(*(struct in_addr *)&(icp.icmp_mask))); | inet_ntoa(*(struct in_addr *)&(icp->icmp_mask))); | ||||
} | } | ||||
if (options & F_TIME) { | if (options & F_TIME) { | ||||
(void)printf(" tso=%s", pr_ntime(icp.icmp_otime)); | (void)printf(" tso=%s", pr_ntime(icp->icmp_otime)); | ||||
(void)printf(" tsr=%s", pr_ntime(icp.icmp_rtime)); | (void)printf(" tsr=%s", pr_ntime(icp->icmp_rtime)); | ||||
(void)printf(" tst=%s", pr_ntime(icp.icmp_ttime)); | (void)printf(" tst=%s", pr_ntime(icp->icmp_ttime)); | ||||
} | } | ||||
if (recv_len != send_len) { | if (recv_len != send_len) { | ||||
(void)printf( | (void)printf( | ||||
"\nwrong total length %d instead of %d", | "\nwrong total length %d instead of %d", | ||||
recv_len, send_len); | recv_len, send_len); | ||||
} | } | ||||
/* check the data */ | /* check the data */ | ||||
cp = (u_char*)(buf + hlen + offsetof(struct icmp, | cp = (u_char*)&icp->icmp_data[phdr_len]; | ||||
icmp_data) + phdr_len); | |||||
dp = &outpack[ICMP_MINLEN + phdr_len]; | dp = &outpack[ICMP_MINLEN + phdr_len]; | ||||
cc -= ICMP_MINLEN + phdr_len; | cc -= ICMP_MINLEN + phdr_len; | ||||
i = 0; | i = 0; | ||||
if (timing) { /* don't check variable timestamp */ | if (timing) { /* don't check variable timestamp */ | ||||
cp += TIMEVAL_LEN; | cp += TIMEVAL_LEN; | ||||
dp += TIMEVAL_LEN; | dp += TIMEVAL_LEN; | ||||
cc -= TIMEVAL_LEN; | cc -= TIMEVAL_LEN; | ||||
i += TIMEVAL_LEN; | i += TIMEVAL_LEN; | ||||
} | } | ||||
for (; i < datalen && cc > 0; ++i, ++cp, ++dp, --cc) { | for (; i < datalen && cc > 0; ++i, ++cp, ++dp, --cc) { | ||||
if (*cp != *dp) { | if (*cp != *dp) { | ||||
(void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", | (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", | ||||
i, *dp, *cp); | i, *dp, *cp); | ||||
(void)printf("\ncp:"); | (void)printf("\ncp:"); | ||||
cp = (u_char*)(buf + hlen + | cp = (u_char*)&icp->icmp_data[0]; | ||||
offsetof(struct icmp, icmp_data)); | |||||
for (i = 0; i < datalen; ++i, ++cp) { | for (i = 0; i < datalen; ++i, ++cp) { | ||||
if ((i % 16) == 8) | if ((i % 16) == 8) | ||||
(void)printf("\n\t"); | (void)printf("\n\t"); | ||||
(void)printf("%2x ", *cp); | (void)printf("%2x ", *cp); | ||||
} | } | ||||
(void)printf("\ndp:"); | (void)printf("\ndp:"); | ||||
cp = &outpack[ICMP_MINLEN]; | cp = &outpack[ICMP_MINLEN]; | ||||
for (i = 0; i < datalen; ++i, ++cp) { | for (i = 0; i < datalen; ++i, ++cp) { | ||||
Show All 11 Lines | (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", | ||||
* See if it's a reply to something that we sent. | * See if it's a reply to something that we sent. | ||||
* We can compare IP destination, protocol, | * We can compare IP destination, protocol, | ||||
* and ICMP type and ID. | * and ICMP type and ID. | ||||
* | * | ||||
* Only print all the error messages if we are running | * Only print all the error messages if we are running | ||||
* as root to avoid leaking information not normally | * as root to avoid leaking information not normally | ||||
* available to those not running as root. | * available to those not running as root. | ||||
*/ | */ | ||||
memcpy(&oip, icp->icmp_data, sizeof(struct ip *)); | |||||
oicmp = (struct icmp *)(oip + 1); | |||||
/* | |||||
* If we don't have enough bytes for a quoted IP header and an | |||||
* ICMP header then stop. | |||||
*/ | |||||
if (icmp_data_raw_len < | |||||
(ssize_t)(sizeof(struct ip) + sizeof(struct icmp))) { | |||||
if (options & F_VERBOSE) | |||||
warnx("quoted data too short (%zd bytes) from %s", | |||||
icmp_data_raw_len, inet_ntoa(from->sin_addr)); | |||||
return; | |||||
} | |||||
memcpy(&oip_header_len, icmp_data_raw, sizeof(oip_header_len)); | |||||
oip_header_len = (oip_header_len & 0x0f) << 2; | |||||
/* Reject IP packets with a short header */ | |||||
if (oip_header_len < sizeof(struct ip)) { | |||||
if (options & F_VERBOSE) | |||||
warnx("inner IHL too short (%d bytes) from %s", | |||||
oip_header_len, inet_ntoa(from->sin_addr)); | |||||
return; | |||||
} | |||||
/* | |||||
* Check against the actual IHL length, to protect against | |||||
* quoated packets carrying IP options. | |||||
*/ | |||||
if (icmp_data_raw_len < | |||||
(ssize_t)(oip_header_len + sizeof(struct icmp))) { | |||||
if (options & F_VERBOSE) | |||||
warnx("inner packet too short (%zd bytes) from %s", | |||||
icmp_data_raw_len, inet_ntoa(from->sin_addr)); | |||||
return; | |||||
} | |||||
memcpy(&oip, icmp_data_raw, sizeof(struct ip)); | |||||
oicmp_raw = icmp_data_raw + oip_header_len; | |||||
memcpy(&oicmp, oicmp_raw, sizeof(struct icmp)); | |||||
if (((options & F_VERBOSE) && uid == 0) || | if (((options & F_VERBOSE) && uid == 0) || | ||||
(!(options & F_QUIET2) && | (!(options & F_QUIET2) && | ||||
(oip.ip_dst.s_addr == whereto.sin_addr.s_addr) && | (oip->ip_dst.s_addr == whereto.sin_addr.s_addr) && | ||||
(oip.ip_p == IPPROTO_ICMP) && | (oip->ip_p == IPPROTO_ICMP) && | ||||
(oicmp.icmp_type == ICMP_ECHO) && | (oicmp->icmp_type == ICMP_ECHO) && | ||||
(oicmp.icmp_id == ident))) { | (oicmp->icmp_id == ident))) { | ||||
(void)printf("%zd bytes from %s: ", cc, | (void)printf("%d bytes from %s: ", cc, | ||||
pr_addr(from->sin_addr)); | pr_addr(from->sin_addr)); | ||||
pr_icmph(&icp, &oip, oicmp_raw); | pr_icmph(icp); | ||||
} else | } else | ||||
return; | return; | ||||
} | } | ||||
/* Display any IP options */ | /* Display any IP options */ | ||||
cp = (u_char *)buf + sizeof(struct ip); | cp = (u_char *)buf + sizeof(struct ip); | ||||
for (; hlen > (int)sizeof(struct ip); --hlen, ++cp) | for (; hlen > (int)sizeof(struct ip); --hlen, ++cp) | ||||
▲ Show 20 Lines • Show All 153 Lines • ▼ Show 20 Lines | else | ||||
exit(2); | exit(2); | ||||
} | } | ||||
/* | /* | ||||
* pr_icmph -- | * pr_icmph -- | ||||
* Print a descriptive string about an ICMP header. | * Print a descriptive string about an ICMP header. | ||||
*/ | */ | ||||
static void | static void | ||||
pr_icmph(struct icmp *icp, struct ip *oip, const u_char *const oicmp_raw) | pr_icmph(struct icmp *icp) | ||||
{ | { | ||||
switch(icp->icmp_type) { | switch(icp->icmp_type) { | ||||
case ICMP_ECHOREPLY: | case ICMP_ECHOREPLY: | ||||
(void)printf("Echo Reply\n"); | (void)printf("Echo Reply\n"); | ||||
/* XXX ID + Seq + Data */ | /* XXX ID + Seq + Data */ | ||||
break; | break; | ||||
case ICMP_UNREACH: | case ICMP_UNREACH: | ||||
Show All 21 Lines | case ICMP_UNREACH_FILTER_PROHIB: | ||||
(void)printf("Communication prohibited by filter\n"); | (void)printf("Communication prohibited by filter\n"); | ||||
break; | break; | ||||
default: | default: | ||||
(void)printf("Dest Unreachable, Bad Code: %d\n", | (void)printf("Dest Unreachable, Bad Code: %d\n", | ||||
icp->icmp_code); | icp->icmp_code); | ||||
break; | break; | ||||
} | } | ||||
/* Print returned IP header information */ | /* Print returned IP header information */ | ||||
pr_retip(oip, oicmp_raw); | pr_retip((struct ip *)icp->icmp_data); | ||||
break; | break; | ||||
case ICMP_SOURCEQUENCH: | case ICMP_SOURCEQUENCH: | ||||
(void)printf("Source Quench\n"); | (void)printf("Source Quench\n"); | ||||
pr_retip(oip, oicmp_raw); | pr_retip((struct ip *)icp->icmp_data); | ||||
break; | break; | ||||
case ICMP_REDIRECT: | case ICMP_REDIRECT: | ||||
switch(icp->icmp_code) { | switch(icp->icmp_code) { | ||||
case ICMP_REDIRECT_NET: | case ICMP_REDIRECT_NET: | ||||
(void)printf("Redirect Network"); | (void)printf("Redirect Network"); | ||||
break; | break; | ||||
case ICMP_REDIRECT_HOST: | case ICMP_REDIRECT_HOST: | ||||
(void)printf("Redirect Host"); | (void)printf("Redirect Host"); | ||||
break; | break; | ||||
case ICMP_REDIRECT_TOSNET: | case ICMP_REDIRECT_TOSNET: | ||||
(void)printf("Redirect Type of Service and Network"); | (void)printf("Redirect Type of Service and Network"); | ||||
break; | break; | ||||
case ICMP_REDIRECT_TOSHOST: | case ICMP_REDIRECT_TOSHOST: | ||||
(void)printf("Redirect Type of Service and Host"); | (void)printf("Redirect Type of Service and Host"); | ||||
break; | break; | ||||
default: | default: | ||||
(void)printf("Redirect, Bad Code: %d", icp->icmp_code); | (void)printf("Redirect, Bad Code: %d", icp->icmp_code); | ||||
break; | break; | ||||
} | } | ||||
(void)printf("(New addr: %s)\n", inet_ntoa(icp->icmp_gwaddr)); | (void)printf("(New addr: %s)\n", inet_ntoa(icp->icmp_gwaddr)); | ||||
pr_retip(oip, oicmp_raw); | pr_retip((struct ip *)icp->icmp_data); | ||||
break; | break; | ||||
case ICMP_ECHO: | case ICMP_ECHO: | ||||
(void)printf("Echo Request\n"); | (void)printf("Echo Request\n"); | ||||
/* XXX ID + Seq + Data */ | /* XXX ID + Seq + Data */ | ||||
break; | break; | ||||
case ICMP_TIMXCEED: | case ICMP_TIMXCEED: | ||||
switch(icp->icmp_code) { | switch(icp->icmp_code) { | ||||
case ICMP_TIMXCEED_INTRANS: | case ICMP_TIMXCEED_INTRANS: | ||||
(void)printf("Time to live exceeded\n"); | (void)printf("Time to live exceeded\n"); | ||||
break; | break; | ||||
case ICMP_TIMXCEED_REASS: | case ICMP_TIMXCEED_REASS: | ||||
(void)printf("Frag reassembly time exceeded\n"); | (void)printf("Frag reassembly time exceeded\n"); | ||||
break; | break; | ||||
default: | default: | ||||
(void)printf("Time exceeded, Bad Code: %d\n", | (void)printf("Time exceeded, Bad Code: %d\n", | ||||
icp->icmp_code); | icp->icmp_code); | ||||
break; | break; | ||||
} | } | ||||
pr_retip(oip, oicmp_raw); | pr_retip((struct ip *)icp->icmp_data); | ||||
break; | break; | ||||
case ICMP_PARAMPROB: | case ICMP_PARAMPROB: | ||||
(void)printf("Parameter problem: pointer = 0x%02x\n", | (void)printf("Parameter problem: pointer = 0x%02x\n", | ||||
icp->icmp_hun.ih_pptr); | icp->icmp_hun.ih_pptr); | ||||
pr_retip(oip, oicmp_raw); | pr_retip((struct ip *)icp->icmp_data); | ||||
break; | break; | ||||
case ICMP_TSTAMP: | case ICMP_TSTAMP: | ||||
(void)printf("Timestamp\n"); | (void)printf("Timestamp\n"); | ||||
/* XXX ID + Seq + 3 timestamps */ | /* XXX ID + Seq + 3 timestamps */ | ||||
break; | break; | ||||
case ICMP_TSTAMPREPLY: | case ICMP_TSTAMPREPLY: | ||||
(void)printf("Timestamp Reply\n"); | (void)printf("Timestamp Reply\n"); | ||||
/* XXX ID + Seq + 3 timestamps */ | /* XXX ID + Seq + 3 timestamps */ | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | pr_addr(struct in_addr ina) | ||||
return(buf); | return(buf); | ||||
} | } | ||||
/* | /* | ||||
* pr_retip -- | * pr_retip -- | ||||
* Dump some info on a returned (via ICMP) IP packet. | * Dump some info on a returned (via ICMP) IP packet. | ||||
*/ | */ | ||||
static void | static void | ||||
pr_retip(struct ip *ip, const u_char *cp) | pr_retip(struct ip *ip) | ||||
{ | { | ||||
u_char *cp; | |||||
int hlen; | |||||
pr_iph(ip); | pr_iph(ip); | ||||
hlen = ip->ip_hl << 2; | |||||
cp = (u_char *)ip + hlen; | |||||
if (ip->ip_p == 6) | if (ip->ip_p == 6) | ||||
(void)printf("TCP: from port %u, to port %u (decimal)\n", | (void)printf("TCP: from port %u, to port %u (decimal)\n", | ||||
(*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); | (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); | ||||
else if (ip->ip_p == 17) | else if (ip->ip_p == 17) | ||||
(void)printf("UDP: from port %u, to port %u (decimal)\n", | (void)printf("UDP: from port %u, to port %u (decimal)\n", | ||||
(*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); | (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 75 Lines • Show Last 20 Lines |