Changeset View
Changeset View
Standalone View
Standalone View
sbin/ping6/ping6.c
Show First 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | |||||
* while IPV6_PKTINFO specifies *interface*. Link is defined as collection of | * while IPV6_PKTINFO specifies *interface*. Link is defined as collection of | ||||
* network attached to 1 or more interfaces) | * network attached to 1 or more interfaces) | ||||
*/ | */ | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/capsicum.h> | #include <sys/capsicum.h> | ||||
#include <sys/uio.h> | #include <sys/uio.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/time.h> | |||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/route.h> | #include <net/route.h> | ||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#include <netinet/ip6.h> | #include <netinet/ip6.h> | ||||
#include <netinet/icmp6.h> | #include <netinet/icmp6.h> | ||||
#include <arpa/inet.h> | #include <arpa/inet.h> | ||||
Show All 9 Lines | |||||
#include <errno.h> | #include <errno.h> | ||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#include <math.h> | #include <math.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 <unistd.h> | #include <unistd.h> | ||||
#ifdef IPSEC | #ifdef IPSEC | ||||
#include <netipsec/ah.h> | #include <netipsec/ah.h> | ||||
#include <netipsec/ipsec.h> | #include <netipsec/ipsec.h> | ||||
#endif | #endif | ||||
#include <md5.h> | #include <md5.h> | ||||
struct tv32 { | struct tv32 { | ||||
u_int32_t tv32_sec; | u_int32_t tv32_sec; | ||||
u_int32_t tv32_usec; | u_int32_t tv32_nsec; | ||||
}; | }; | ||||
#define MAXPACKETLEN 131072 | #define MAXPACKETLEN 131072 | ||||
#define IP6LEN 40 | #define IP6LEN 40 | ||||
#define ICMP6ECHOLEN 8 /* icmp echo header len excluding time */ | #define ICMP6ECHOLEN 8 /* icmp echo header len excluding time */ | ||||
#define ICMP6ECHOTMLEN sizeof(struct tv32) | #define ICMP6ECHOTMLEN sizeof(struct tv32) | ||||
#define ICMP6_NIQLEN (ICMP6ECHOLEN + 8) | #define ICMP6_NIQLEN (ICMP6ECHOLEN + 8) | ||||
# define CONTROLLEN 10240 /* ancillary data buffer size RFC3542 20.1 */ | # define CONTROLLEN 10240 /* ancillary data buffer size RFC3542 20.1 */ | ||||
▲ Show 20 Lines • Show All 127 Lines • ▼ Show 20 Lines | static char *dnsdecode(const u_char **, const u_char *, const u_char *, | ||||
char *, size_t); | char *, size_t); | ||||
static void pr_pack(u_char *, int, struct msghdr *); | static void pr_pack(u_char *, int, struct msghdr *); | ||||
static void pr_exthdrs(struct msghdr *); | static void pr_exthdrs(struct msghdr *); | ||||
static void pr_ip6opt(void *, size_t); | static void pr_ip6opt(void *, size_t); | ||||
static void pr_rthdr(void *, size_t); | static void pr_rthdr(void *, size_t); | ||||
static int pr_bitrange(u_int32_t, int, int); | static int pr_bitrange(u_int32_t, int, int); | ||||
static void pr_retip(struct ip6_hdr *, u_char *); | static void pr_retip(struct ip6_hdr *, u_char *); | ||||
static void summary(void); | static void summary(void); | ||||
static void tvsub(struct timeval *, struct timeval *); | |||||
static int setpolicy(int, char *); | static int setpolicy(int, char *); | ||||
static char *nigroup(char *, int); | static char *nigroup(char *, int); | ||||
static void usage(void); | static void usage(void); | ||||
int | int | ||||
main(int argc, char *argv[]) | main(int argc, char *argv[]) | ||||
{ | { | ||||
struct timeval last, intvl; | struct timespec last, intvl; | ||||
struct sockaddr_in6 from, *sin6; | struct sockaddr_in6 from, *sin6; | ||||
struct addrinfo hints, *res; | struct addrinfo hints, *res; | ||||
struct sigaction si_sa; | struct sigaction si_sa; | ||||
int cc, i; | int cc, i; | ||||
int almost_done, ch, hold, packlen, preload, optval, error; | int almost_done, ch, hold, packlen, preload, optval, error; | ||||
int nig_oldmcprefix = -1; | int nig_oldmcprefix = -1; | ||||
u_char *datap; | u_char *datap; | ||||
char *e, *target, *ifname = NULL, *gateway = NULL; | char *e, *target, *ifname = NULL, *gateway = NULL; | ||||
▲ Show 20 Lines • Show All 143 Lines • ▼ Show 20 Lines | #endif | ||||
case 'i': /* wait between sending packets */ | case 'i': /* wait between sending packets */ | ||||
t = strtod(optarg, &e); | t = strtod(optarg, &e); | ||||
if (*optarg == '\0' || *e != '\0') | if (*optarg == '\0' || *e != '\0') | ||||
errx(1, "illegal timing interval %s", optarg); | errx(1, "illegal timing interval %s", optarg); | ||||
if (t < 1 && getuid()) { | if (t < 1 && getuid()) { | ||||
errx(1, "%s: only root may use interval < 1s", | errx(1, "%s: only root may use interval < 1s", | ||||
strerror(EPERM)); | strerror(EPERM)); | ||||
} | } | ||||
intvl.tv_sec = (long)t; | intvl.tv_sec = (time_t)t; | ||||
intvl.tv_usec = | intvl.tv_nsec = | ||||
(long)((t - intvl.tv_sec) * 1000000); | (long)((t - intvl.tv_sec) * 1000000000); | ||||
if (intvl.tv_sec < 0) | if (intvl.tv_sec < 0) | ||||
errx(1, "illegal timing interval %s", optarg); | errx(1, "illegal timing interval %s", optarg); | ||||
/* less than 1/hz does not make sense */ | /* less than 1/hz does not make sense */ | ||||
if (intvl.tv_sec == 0 && intvl.tv_usec < 1) { | if (intvl.tv_sec == 0 && intvl.tv_nsec < 1000) { | ||||
warnx("too small interval, raised to .000001"); | warnx("too small interval, raised to .000001"); | ||||
intvl.tv_usec = 1; | intvl.tv_nsec = 1000; | ||||
} | } | ||||
options |= F_INTERVAL; | options |= F_INTERVAL; | ||||
break; | break; | ||||
case 'l': | case 'l': | ||||
if (getuid()) { | if (getuid()) { | ||||
errno = EPERM; | errno = EPERM; | ||||
errx(1, "Must be superuser to preload"); | errx(1, "Must be superuser to preload"); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 621 Lines • ▼ Show 20 Lines | #endif | ||||
if (preload == 0) | if (preload == 0) | ||||
pinger(); | pinger(); | ||||
else { | else { | ||||
if (npackets != 0 && preload > npackets) | if (npackets != 0 && preload > npackets) | ||||
preload = npackets; | preload = npackets; | ||||
while (preload--) | while (preload--) | ||||
pinger(); | pinger(); | ||||
} | } | ||||
gettimeofday(&last, NULL); | clock_gettime(CLOCK_MONOTONIC, &last); | ||||
sigemptyset(&si_sa.sa_mask); | sigemptyset(&si_sa.sa_mask); | ||||
si_sa.sa_flags = 0; | si_sa.sa_flags = 0; | ||||
si_sa.sa_handler = onsignal; | si_sa.sa_handler = onsignal; | ||||
if (sigaction(SIGINT, &si_sa, 0) == -1) | if (sigaction(SIGINT, &si_sa, 0) == -1) | ||||
err(EX_OSERR, "sigaction SIGINT"); | err(EX_OSERR, "sigaction SIGINT"); | ||||
seenint = 0; | seenint = 0; | ||||
#ifdef SIGINFO | #ifdef SIGINFO | ||||
if (sigaction(SIGINFO, &si_sa, 0) == -1) | if (sigaction(SIGINFO, &si_sa, 0) == -1) | ||||
err(EX_OSERR, "sigaction SIGINFO"); | err(EX_OSERR, "sigaction SIGINFO"); | ||||
seeninfo = 0; | seeninfo = 0; | ||||
#endif | #endif | ||||
if (alarmtimeout > 0) { | if (alarmtimeout > 0) { | ||||
if (sigaction(SIGALRM, &si_sa, 0) == -1) | if (sigaction(SIGALRM, &si_sa, 0) == -1) | ||||
err(EX_OSERR, "sigaction SIGALRM"); | err(EX_OSERR, "sigaction SIGALRM"); | ||||
} | } | ||||
if (options & F_FLOOD) { | if (options & F_FLOOD) { | ||||
intvl.tv_sec = 0; | intvl.tv_sec = 0; | ||||
intvl.tv_usec = 10000; | intvl.tv_nsec = 10000000; | ||||
} else if ((options & F_INTERVAL) == 0) { | } else if ((options & F_INTERVAL) == 0) { | ||||
intvl.tv_sec = interval / 1000; | intvl.tv_sec = interval / 1000; | ||||
intvl.tv_usec = interval % 1000 * 1000; | intvl.tv_nsec = interval % 1000 * 1000000; | ||||
} | } | ||||
almost_done = 0; | almost_done = 0; | ||||
while (seenint == 0) { | while (seenint == 0) { | ||||
struct timeval now, timeout; | struct timespec now, timeout; | ||||
struct msghdr m; | struct msghdr m; | ||||
struct iovec iov[2]; | struct iovec iov[2]; | ||||
fd_set rfds; | fd_set rfds; | ||||
int n; | int n; | ||||
/* signal handling */ | /* signal handling */ | ||||
if (seenint) | if (seenint) | ||||
onint(SIGINT); | onint(SIGINT); | ||||
#ifdef SIGINFO | #ifdef SIGINFO | ||||
if (seeninfo) { | if (seeninfo) { | ||||
summary(); | summary(); | ||||
seeninfo = 0; | seeninfo = 0; | ||||
continue; | continue; | ||||
} | } | ||||
#endif | #endif | ||||
FD_ZERO(&rfds); | FD_ZERO(&rfds); | ||||
FD_SET(srecv, &rfds); | FD_SET(srecv, &rfds); | ||||
gettimeofday(&now, NULL); | clock_gettime(CLOCK_MONOTONIC, &now); | ||||
timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec; | timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec; | ||||
timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec; | timeout.tv_nsec = last.tv_nsec + intvl.tv_nsec - now.tv_nsec; | ||||
asomers: These 10 lines can be replaced by timespecadd. | |||||
jansucanAuthorUnsubmitted Done Inline ActionsFixed. jansucan: Fixed. | |||||
asomersUnsubmitted Not Done Inline ActionsThanks. It's much more readable now. asomers: Thanks. It's much more readable now. | |||||
while (timeout.tv_usec < 0) { | while (timeout.tv_nsec < 0) { | ||||
timeout.tv_usec += 1000000; | timeout.tv_nsec += 1000000000; | ||||
timeout.tv_sec--; | timeout.tv_sec--; | ||||
} | } | ||||
while (timeout.tv_usec > 1000000) { | while (timeout.tv_nsec > 1000000000) { | ||||
timeout.tv_usec -= 1000000; | timeout.tv_nsec -= 1000000000; | ||||
timeout.tv_sec++; | timeout.tv_sec++; | ||||
} | } | ||||
if (timeout.tv_sec < 0) | if (timeout.tv_sec < 0) | ||||
timeout.tv_sec = timeout.tv_usec = 0; | timeout.tv_sec = timeout.tv_nsec = 0; | ||||
n = select(srecv + 1, &rfds, NULL, NULL, &timeout); | n = pselect(srecv + 1, &rfds, NULL, NULL, &timeout, NULL); | ||||
if (n < 0) | if (n < 0) | ||||
continue; /* EINTR */ | continue; /* EINTR */ | ||||
if (n == 1) { | if (n == 1) { | ||||
m.msg_name = (caddr_t)&from; | m.msg_name = (caddr_t)&from; | ||||
m.msg_namelen = sizeof(from); | m.msg_namelen = sizeof(from); | ||||
memset(&iov, 0, sizeof(iov)); | memset(&iov, 0, sizeof(iov)); | ||||
iov[0].iov_base = (caddr_t)packet; | iov[0].iov_base = (caddr_t)packet; | ||||
iov[0].iov_len = packlen; | iov[0].iov_len = packlen; | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | if (n == 0 || (options & F_FLOOD)) { | ||||
break; | break; | ||||
almost_done = 1; | almost_done = 1; | ||||
/* | /* | ||||
* If we're not transmitting any more packets, | * If we're not transmitting any more packets, | ||||
* change the timer to wait two round-trip times | * change the timer to wait two round-trip times | ||||
* if we've received any packets or (waittime) | * if we've received any packets or (waittime) | ||||
* milliseconds if we haven't. | * milliseconds if we haven't. | ||||
*/ | */ | ||||
intvl.tv_usec = 0; | intvl.tv_nsec = 0; | ||||
if (nreceived) { | if (nreceived) { | ||||
intvl.tv_sec = 2 * tmax / 1000; | intvl.tv_sec = 2 * tmax / 1000; | ||||
if (intvl.tv_sec == 0) | if (intvl.tv_sec == 0) | ||||
intvl.tv_sec = 1; | intvl.tv_sec = 1; | ||||
} else { | } else { | ||||
intvl.tv_sec = waittime / 1000; | intvl.tv_sec = waittime / 1000; | ||||
intvl.tv_usec = waittime % 1000 * 1000; | intvl.tv_nsec = | ||||
waittime % 1000 * 1000000; | |||||
} | } | ||||
} | } | ||||
gettimeofday(&last, NULL); | clock_gettime(CLOCK_MONOTONIC, &last); | ||||
if (ntransmitted - nreceived - 1 > nmissedmax) { | if (ntransmitted - nreceived - 1 > nmissedmax) { | ||||
nmissedmax = ntransmitted - nreceived - 1; | nmissedmax = ntransmitted - nreceived - 1; | ||||
if (options & F_MISSED) | if (options & F_MISSED) | ||||
(void)write(STDOUT_FILENO, &BBELL, 1); | (void)write(STDOUT_FILENO, &BBELL, 1); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
sigemptyset(&si_sa.sa_mask); | sigemptyset(&si_sa.sa_mask); | ||||
Show All 26 Lines | #endif | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* pinger -- | * pinger -- | ||||
* Compose and transmit an ICMP ECHO REQUEST packet. The IP packet | * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet | ||||
* will be added on by the kernel. The ID field is our UNIX process ID, | * will be added on by the kernel. The ID field is our UNIX process ID, | ||||
* and the sequence number is an ascending integer. The first 8 bytes | * and the sequence number is an ascending integer. The first 8 bytes | ||||
* of the data portion are used to hold a UNIX "timeval" struct in VAX | * of the data portion are used to hold a UNIX "timespec" struct in VAX | ||||
* byte-order, to compute the round-trip time. | * byte-order, to compute the round-trip time. | ||||
*/ | */ | ||||
static size_t | static size_t | ||||
pingerlen(void) | pingerlen(void) | ||||
{ | { | ||||
size_t l; | size_t l; | ||||
if (options & F_FQDN) | if (options & F_FQDN) | ||||
▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | if (options & F_FQDN) { | ||||
cc = ICMP6_NIQLEN; | cc = ICMP6_NIQLEN; | ||||
datalen = 0; | datalen = 0; | ||||
} else { | } else { | ||||
icp->icmp6_type = ICMP6_ECHO_REQUEST; | icp->icmp6_type = ICMP6_ECHO_REQUEST; | ||||
icp->icmp6_code = 0; | icp->icmp6_code = 0; | ||||
icp->icmp6_id = htons(ident); | icp->icmp6_id = htons(ident); | ||||
icp->icmp6_seq = ntohs(seq); | icp->icmp6_seq = ntohs(seq); | ||||
if (timing) { | if (timing) { | ||||
struct timeval tv; | struct timespec tv; | ||||
struct tv32 *tv32; | struct tv32 *tv32; | ||||
(void)gettimeofday(&tv, NULL); | (void)clock_gettime(CLOCK_MONOTONIC, &tv); | ||||
tv32 = (struct tv32 *)&outpack[ICMP6ECHOLEN]; | tv32 = (struct tv32 *)&outpack[ICMP6ECHOLEN]; | ||||
tv32->tv32_sec = htonl(tv.tv_sec); | /* | ||||
tv32->tv32_usec = htonl(tv.tv_usec); | * Truncate seconds down to 32 bits in order | ||||
* to fit the timestamp within 8 bytes of the | |||||
* packet. We're only concerned with | |||||
* durations, not absolute times. | |||||
*/ | |||||
tv32->tv32_sec = (uint32_t)htonl(tv.tv_sec); | |||||
tv32->tv32_nsec = (uint32_t)htonl(tv.tv_nsec); | |||||
} | } | ||||
cc = ICMP6ECHOLEN + datalen; | cc = ICMP6ECHOLEN + datalen; | ||||
} | } | ||||
#ifdef DIAGNOSTIC | #ifdef DIAGNOSTIC | ||||
if (pingerlen() != cc) | if (pingerlen() != cc) | ||||
errx(1, "internal error; length mismatch"); | errx(1, "internal error; length mismatch"); | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | #define safeputc(c) printf((isprint((c)) ? "%c" : "\\%03o"), c) | ||||
struct icmp6_hdr *icp; | struct icmp6_hdr *icp; | ||||
struct icmp6_nodeinfo *ni; | struct icmp6_nodeinfo *ni; | ||||
int i; | int i; | ||||
int hoplim; | int hoplim; | ||||
struct sockaddr *from; | struct sockaddr *from; | ||||
int fromlen; | int fromlen; | ||||
u_char *cp = NULL, *dp, *end = buf + cc; | u_char *cp = NULL, *dp, *end = buf + cc; | ||||
struct in6_pktinfo *pktinfo = NULL; | struct in6_pktinfo *pktinfo = NULL; | ||||
struct timeval tv, tp; | struct timespec tv, tp; | ||||
struct tv32 *tpp; | struct tv32 *tpp; | ||||
double triptime = 0; | double triptime = 0; | ||||
int dupflag; | int dupflag; | ||||
size_t off; | size_t off; | ||||
int oldfqdn; | int oldfqdn; | ||||
u_int16_t seq; | u_int16_t seq; | ||||
char dnsname[MAXDNAME + 1]; | char dnsname[MAXDNAME + 1]; | ||||
(void)gettimeofday(&tv, NULL); | (void)clock_gettime(CLOCK_MONOTONIC, &tv); | ||||
if (!mhdr || !mhdr->msg_name || | if (!mhdr || !mhdr->msg_name || | ||||
mhdr->msg_namelen != sizeof(struct sockaddr_in6) || | mhdr->msg_namelen != sizeof(struct sockaddr_in6) || | ||||
((struct sockaddr *)mhdr->msg_name)->sa_family != AF_INET6) { | ((struct sockaddr *)mhdr->msg_name)->sa_family != AF_INET6) { | ||||
if (options & F_VERBOSE) | if (options & F_VERBOSE) | ||||
warnx("invalid peername"); | warnx("invalid peername"); | ||||
return; | return; | ||||
} | } | ||||
Show All 22 Lines | #define safeputc(c) printf((isprint((c)) ? "%c" : "\\%03o"), c) | ||||
} | } | ||||
if (icp->icmp6_type == ICMP6_ECHO_REPLY && myechoreply(icp)) { | if (icp->icmp6_type == ICMP6_ECHO_REPLY && myechoreply(icp)) { | ||||
seq = ntohs(icp->icmp6_seq); | seq = ntohs(icp->icmp6_seq); | ||||
++nreceived; | ++nreceived; | ||||
if (timing) { | if (timing) { | ||||
tpp = (struct tv32 *)(icp + 1); | tpp = (struct tv32 *)(icp + 1); | ||||
tp.tv_sec = ntohl(tpp->tv32_sec); | tp.tv_sec = ntohl(tpp->tv32_sec); | ||||
tp.tv_usec = ntohl(tpp->tv32_usec); | tp.tv_nsec = ntohl(tpp->tv32_nsec); | ||||
tvsub(&tv, &tp); | timespecsub(&tv, &tp, &tv); | ||||
triptime = ((double)tv.tv_sec) * 1000.0 + | triptime = ((double)tv.tv_sec) * 1000.0 + | ||||
((double)tv.tv_usec) / 1000.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; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 629 Lines • ▼ Show 20 Lines | if (cm->cmsg_level == IPPROTO_IPV6 && | ||||
return(0); | return(0); | ||||
/* notification for our destination. return the MTU. */ | /* notification for our destination. return the MTU. */ | ||||
return((int)mtuctl->ip6m_mtu); | return((int)mtuctl->ip6m_mtu); | ||||
} | } | ||||
} | } | ||||
#endif | #endif | ||||
return(0); | return(0); | ||||
} | |||||
/* | |||||
* tvsub -- | |||||
* Subtract 2 timeval structs: out = out - in. Out is assumed to | |||||
* be >= in. | |||||
*/ | |||||
static void | |||||
tvsub(struct timeval *out, struct timeval *in) | |||||
{ | |||||
if ((out->tv_usec -= in->tv_usec) < 0) { | |||||
--out->tv_sec; | |||||
out->tv_usec += 1000000; | |||||
} | |||||
out->tv_sec -= in->tv_sec; | |||||
} | } | ||||
/* | /* | ||||
Not Done Inline ActionsYou should eliminate this function and use timespecsub(3) instead. asomers: You should eliminate this function and use `timespecsub(3)` instead. | |||||
Done Inline ActionsFixed. jansucan: Fixed. | |||||
* onint -- | * onint -- | ||||
* SIGINT handler. | * SIGINT handler. | ||||
*/ | */ | ||||
/* ARGSUSED */ | /* ARGSUSED */ | ||||
static void | static void | ||||
onint(int notused __unused) | onint(int notused __unused) | ||||
{ | { | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 586 Lines • Show Last 20 Lines |
These 10 lines can be replaced by timespecadd.