Changeset View
Changeset View
Standalone View
Standalone View
sbin/ping6/ping6.c
Show First 20 Lines • Show All 136 Lines • ▼ Show 20 Lines | |||||
#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> | ||||
#include "options.h" | |||||
struct tv32 { | struct tv32 { | ||||
u_int32_t tv32_sec; | u_int32_t tv32_sec; | ||||
u_int32_t tv32_nsec; | 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 */ | ||||
Show All 10 Lines | |||||
#define MAXALARM (60 * 60) /* max seconds for alarm timeout */ | #define MAXALARM (60 * 60) /* max seconds for alarm timeout */ | ||||
#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ | #define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ | ||||
#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ | #define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ | ||||
#define SET(bit) (A(bit) |= B(bit)) | #define SET(bit) (A(bit) |= B(bit)) | ||||
#define CLR(bit) (A(bit) &= (~B(bit))) | #define CLR(bit) (A(bit) &= (~B(bit))) | ||||
#define TST(bit) (A(bit) & B(bit)) | #define TST(bit) (A(bit) & B(bit)) | ||||
#define F_FLOOD 0x0001 | |||||
#define F_INTERVAL 0x0002 | |||||
#define F_PINGFILLED 0x0008 | |||||
#define F_QUIET 0x0010 | |||||
#define F_RROUTE 0x0020 | |||||
#define F_SO_DEBUG 0x0040 | |||||
#define F_VERBOSE 0x0100 | |||||
#ifdef IPSEC | |||||
#ifdef IPSEC_POLICY_IPSEC | |||||
#define F_POLICY 0x0400 | |||||
#else | |||||
#define F_AUTHHDR 0x0200 | |||||
#define F_ENCRYPT 0x0400 | |||||
#endif /*IPSEC_POLICY_IPSEC*/ | |||||
#endif /*IPSEC*/ | |||||
#define F_NODEADDR 0x0800 | |||||
#define F_FQDN 0x1000 | |||||
#define F_INTERFACE 0x2000 | |||||
#define F_SRCADDR 0x4000 | |||||
#define F_HOSTNAME 0x10000 | |||||
#define F_FQDNOLD 0x20000 | |||||
#define F_NIGROUP 0x40000 | |||||
#define F_SUPTYPES 0x80000 | |||||
#define F_NOMINMTU 0x100000 | |||||
#define F_ONCE 0x200000 | |||||
#define F_AUDIBLE 0x400000 | |||||
#define F_MISSED 0x800000 | |||||
#define F_DONTFRAG 0x1000000 | |||||
#define F_NOUSERDATA (F_NODEADDR | F_FQDN | F_FQDNOLD | F_SUPTYPES) | |||||
#define F_WAITTIME 0x2000000 | |||||
static u_int options; | static u_int options; | ||||
#define IN6LEN sizeof(struct in6_addr) | #define IN6LEN sizeof(struct in6_addr) | ||||
#define SA6LEN sizeof(struct sockaddr_in6) | #define SA6LEN sizeof(struct sockaddr_in6) | ||||
#define DUMMY_PORT 10101 | #define DUMMY_PORT 10101 | ||||
#define SIN6(s) ((struct sockaddr_in6 *)(s)) | #define SIN6(s) ((struct sockaddr_in6 *)(s)) | ||||
▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | |||||
int | int | ||||
main(int argc, char *argv[]) | main(int argc, char *argv[]) | ||||
{ | { | ||||
struct timespec 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; | ||||
struct options_processed opts; | |||||
int cc, i; | int cc, i; | ||||
int almost_done, ch, hold, packlen, preload, optval, error; | int almost_done, 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; | ||||
int ip6optlen = 0; | int ip6optlen = 0; | ||||
struct cmsghdr *scmsgp = NULL; | struct cmsghdr *scmsgp = NULL; | ||||
/* For control (ancillary) data received from recvmsg() */ | /* For control (ancillary) data received from recvmsg() */ | ||||
u_char cm[CONTROLLEN]; | u_char cm[CONTROLLEN]; | ||||
#if defined(SO_SNDBUF) && defined(SO_RCVBUF) | #if defined(SO_SNDBUF) && defined(SO_RCVBUF) | ||||
Show All 24 Lines | #endif | ||||
memset(&pktinfo, 0, sizeof(pktinfo)); | memset(&pktinfo, 0, sizeof(pktinfo)); | ||||
intvl.tv_sec = interval / 1000; | intvl.tv_sec = interval / 1000; | ||||
intvl.tv_nsec = interval % 1000 * 1000000; | intvl.tv_nsec = interval % 1000 * 1000000; | ||||
alarmtimeout = preload = 0; | alarmtimeout = preload = 0; | ||||
datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN]; | datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN]; | ||||
capdns = capdns_setup(); | capdns = capdns_setup(); | ||||
#ifndef IPSEC | |||||
#define ADDOPTS | if (!options_parse(argc, argv, &opts, &options)) | ||||
#else | usage(); | ||||
#ifdef IPSEC_POLICY_IPSEC | /* NOTREACHED */ | ||||
#define ADDOPTS "P:" | |||||
#else | if ((options & F_NODEADDR) != 0) { | ||||
#define ADDOPTS "ZE" | |||||
#endif /*IPSEC_POLICY_IPSEC*/ | |||||
#endif | |||||
while ((ch = getopt(argc, argv, | |||||
"k:b:c:DdfHe:m:I:i:l:unNop:qaAS:s:OvyYW:t:" ADDOPTS)) != -1) { | |||||
#undef ADDOPTS | |||||
switch (ch) { | |||||
case 'k': | |||||
{ | |||||
char *cp; | char *cp; | ||||
options &= ~F_NOUSERDATA; | for (cp = opts.arg_addrtype; *cp != '\0'; cp++) { | ||||
options |= F_NODEADDR; | |||||
for (cp = optarg; *cp != '\0'; cp++) { | |||||
switch (*cp) { | switch (*cp) { | ||||
case 'a': | case 'a': | ||||
naflags |= NI_NODEADDR_FLAG_ALL; | naflags |= NI_NODEADDR_FLAG_ALL; | ||||
break; | break; | ||||
case 'c': | case 'c': | ||||
case 'C': | case 'C': | ||||
naflags |= NI_NODEADDR_FLAG_COMPAT; | naflags |= NI_NODEADDR_FLAG_COMPAT; | ||||
break; | break; | ||||
case 'l': | case 'l': | ||||
case 'L': | case 'L': | ||||
naflags |= NI_NODEADDR_FLAG_LINKLOCAL; | naflags |= NI_NODEADDR_FLAG_LINKLOCAL; | ||||
break; | break; | ||||
case 's': | case 's': | ||||
case 'S': | case 'S': | ||||
naflags |= NI_NODEADDR_FLAG_SITELOCAL; | naflags |= NI_NODEADDR_FLAG_SITELOCAL; | ||||
break; | break; | ||||
case 'g': | case 'g': | ||||
case 'G': | case 'G': | ||||
naflags |= NI_NODEADDR_FLAG_GLOBAL; | naflags |= NI_NODEADDR_FLAG_GLOBAL; | ||||
break; | break; | ||||
case 'A': /* experimental. not in the spec */ | case 'A': /* experimental. not in the spec */ | ||||
#ifdef NI_NODEADDR_FLAG_ANYCAST | #ifdef NI_NODEADDR_FLAG_ANYCAST | ||||
naflags |= NI_NODEADDR_FLAG_ANYCAST; | naflags |= NI_NODEADDR_FLAG_ANYCAST; | ||||
break; | break; | ||||
#else | #else | ||||
errx(1, | errx(1, | ||||
"-a A is not supported on the platform"); | "-a A is not supported on the platform"); | ||||
/*NOTREACHED*/ | /*NOTREACHED*/ | ||||
#endif | #endif | ||||
default: | default: | ||||
usage(); | usage(); | ||||
/*NOTREACHED*/ | /*NOTREACHED*/ | ||||
} | } | ||||
} | } | ||||
break; | |||||
} | } | ||||
case 'b': | if (opts.arg_sock_buff_size != NULL) { | ||||
#if defined(SO_SNDBUF) && defined(SO_RCVBUF) | |||||
errno = 0; | errno = 0; | ||||
e = NULL; | e = NULL; | ||||
lsockbufsize = strtoul(optarg, &e, 10); | lsockbufsize = strtoul(opts.arg_sock_buff_size, &e, 10); | ||||
sockbufsize = (int)lsockbufsize; | sockbufsize = (int)lsockbufsize; | ||||
if (errno || !*optarg || *e || | if (errno || !*opts.arg_sock_buff_size || *e || | ||||
lsockbufsize > INT_MAX) | lsockbufsize > INT_MAX) | ||||
errx(1, "invalid socket buffer size"); | errx(1, "invalid socket buffer size"); | ||||
#else | } | ||||
if (opts.arg_packet_count != NULL) { | |||||
npackets = strtol(opts.arg_packet_count, &e, 10); | |||||
if (npackets <= 0 || *opts.arg_packet_count == '\0' || | |||||
*e != '\0') | |||||
errx(1, | errx(1, | ||||
"-b option ignored: SO_SNDBUF/SO_RCVBUF socket options not supported"); | "illegal number of packets -- %s", | ||||
#endif | opts.arg_packet_count); | ||||
break; | } | ||||
case 'c': | if ((options & F_FLOOD) != 0) { | ||||
npackets = strtol(optarg, &e, 10); | |||||
if (npackets <= 0 || *optarg == '\0' || *e != '\0') | |||||
errx(1, | |||||
"illegal number of packets -- %s", optarg); | |||||
break; | |||||
case 'D': | |||||
options |= F_DONTFRAG; | |||||
break; | |||||
case 'd': | |||||
options |= F_SO_DEBUG; | |||||
break; | |||||
case 'f': | |||||
if (getuid()) { | if (getuid()) { | ||||
errno = EPERM; | errno = EPERM; | ||||
errx(1, "Must be superuser to flood ping"); | errx(1, "Must be superuser to flood ping"); | ||||
} | } | ||||
asomers: This check is redundant with the one in options.c | |||||
Done Inline ActionsThanks. Fixed. jansucan: Thanks. Fixed. | |||||
options |= F_FLOOD; | |||||
setbuf(stdout, (char *)NULL); | setbuf(stdout, (char *)NULL); | ||||
break; | } | ||||
case 'e': | if (opts.arg_gateway != NULL) | ||||
gateway = optarg; | gateway = opts.arg_gateway; | ||||
break; | if (opts.arg_hoplimit != NULL) { | ||||
case 'H': | hoplimit = strtol(opts.arg_hoplimit, &e, 10); | ||||
options |= F_HOSTNAME; | if (*opts.arg_hoplimit == '\0' || *e != '\0') | ||||
break; | errx(1, "illegal hoplimit %s", opts.arg_hoplimit); | ||||
case 'm': /* hoplimit */ | |||||
hoplimit = strtol(optarg, &e, 10); | |||||
if (*optarg == '\0' || *e != '\0') | |||||
errx(1, "illegal hoplimit %s", optarg); | |||||
if (255 < hoplimit || hoplimit < -1) | if (255 < hoplimit || hoplimit < -1) | ||||
errx(1, | errx(1, | ||||
"illegal hoplimit -- %s", optarg); | "illegal hoplimit -- %s", opts.arg_hoplimit); | ||||
break; | } | ||||
case 'I': | if ((options & F_INTERFACE) != 0) { | ||||
ifname = optarg; | ifname = opts.arg_interface; | ||||
options |= F_INTERFACE; | |||||
#ifndef USE_SIN6_SCOPE_ID | #ifndef USE_SIN6_SCOPE_ID | ||||
usepktinfo++; | usepktinfo += opts.count_interface; | ||||
#endif | #endif | ||||
break; | } | ||||
case 'i': /* wait between sending packets */ | if ((options & F_INTERVAL) != 0) { | ||||
t = strtod(optarg, &e); | t = strtod(opts.arg_interval, &e); | ||||
if (*optarg == '\0' || *e != '\0') | if (*opts.arg_interval == '\0' || *e != '\0') | ||||
errx(1, "illegal timing interval %s", optarg); | errx(1, "illegal timing interval %s", opts.arg_interval); | ||||
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 = (time_t)t; | intvl.tv_sec = (time_t)t; | ||||
intvl.tv_nsec = | intvl.tv_nsec = | ||||
(long)((t - intvl.tv_sec) * 1000000000); | (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", opts.arg_interval); | ||||
/* less than 1/hz does not make sense */ | /* less than 1/hz does not make sense */ | ||||
if (intvl.tv_sec == 0 && intvl.tv_nsec < 1000) { | 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_nsec = 1000; | intvl.tv_nsec = 1000; | ||||
} | } | ||||
options |= F_INTERVAL; | } | ||||
break; | if (opts.arg_preload != NULL) { | ||||
case 'l': | |||||
if (getuid()) { | if (getuid()) { | ||||
errno = EPERM; | errno = EPERM; | ||||
errx(1, "Must be superuser to preload"); | errx(1, "Must be superuser to preload"); | ||||
} | } | ||||
preload = strtol(optarg, &e, 10); | preload = strtol(opts.arg_preload, &e, 10); | ||||
if (preload < 0 || *optarg == '\0' || *e != '\0') | if (preload < 0 || *opts.arg_preload == '\0' || *e != '\0') | ||||
errx(1, "illegal preload value -- %s", optarg); | errx(1, "illegal preload value -- %s", | ||||
break; | opts.arg_preload); | ||||
case 'u': | } | ||||
#ifdef IPV6_USE_MIN_MTU | mflag += opts.count_use_min_mtu; | ||||
mflag++; | nig_oldmcprefix += opts.count_nigroup; | ||||
break; | if ((options & F_PINGFILLED) != 0) | ||||
#else | fill((char *)datap, opts.arg_pattern); | ||||
errx(1, "-%c is not supported on this platform", ch); | if ((options & F_SRCADDR) != 0) { | ||||
/*NOTREACHED*/ | |||||
#endif | |||||
case 'n': | |||||
options &= ~F_HOSTNAME; | |||||
break; | |||||
case 'N': | |||||
options |= F_NIGROUP; | |||||
nig_oldmcprefix++; | |||||
break; | |||||
case 'o': | |||||
options |= F_ONCE; | |||||
break; | |||||
case 'p': /* fill buffer with user pattern */ | |||||
options |= F_PINGFILLED; | |||||
fill((char *)datap, optarg); | |||||
break; | |||||
case 'q': | |||||
options |= F_QUIET; | |||||
break; | |||||
case 'a': | |||||
options |= F_AUDIBLE; | |||||
break; | |||||
case 'A': | |||||
options |= F_MISSED; | |||||
break; | |||||
case 'S': | |||||
memset(&hints, 0, sizeof(struct addrinfo)); | memset(&hints, 0, sizeof(struct addrinfo)); | ||||
hints.ai_flags = AI_NUMERICHOST; /* allow hostname? */ | hints.ai_flags = AI_NUMERICHOST; /* allow hostname? */ | ||||
hints.ai_family = AF_INET6; | hints.ai_family = AF_INET6; | ||||
hints.ai_socktype = SOCK_RAW; | hints.ai_socktype = SOCK_RAW; | ||||
hints.ai_protocol = IPPROTO_ICMPV6; | hints.ai_protocol = IPPROTO_ICMPV6; | ||||
error = cap_getaddrinfo(capdns, optarg, NULL, &hints, &res); | error = cap_getaddrinfo(capdns, opts.arg_source_address, NULL, | ||||
&hints, &res); | |||||
if (error) { | if (error) { | ||||
errx(1, "invalid source address: %s", | errx(1, "invalid source address: %s", | ||||
gai_strerror(error)); | gai_strerror(error)); | ||||
} | } | ||||
/* | /* | ||||
* res->ai_family must be AF_INET6 and res->ai_addrlen | * res->ai_family must be AF_INET6 and res->ai_addrlen | ||||
* must be sizeof(src). | * must be sizeof(src). | ||||
*/ | */ | ||||
memcpy(&src, res->ai_addr, res->ai_addrlen); | memcpy(&src, res->ai_addr, res->ai_addrlen); | ||||
srclen = res->ai_addrlen; | srclen = res->ai_addrlen; | ||||
freeaddrinfo(res); | freeaddrinfo(res); | ||||
options |= F_SRCADDR; | } | ||||
break; | if (opts.arg_packet_size != NULL) { | ||||
case 's': /* size of packet to send */ | datalen = strtol(opts.arg_packet_size, &e, 10); | ||||
datalen = strtol(optarg, &e, 10); | if (datalen <= 0 || *opts.arg_packet_size == '\0' || *e != '\0') | ||||
if (datalen <= 0 || *optarg == '\0' || *e != '\0') | errx(1, "illegal datalen value -- %s", | ||||
errx(1, "illegal datalen value -- %s", optarg); | opts.arg_packet_size); | ||||
if (datalen > MAXDATALEN) { | if (datalen > MAXDATALEN) { | ||||
errx(1, | errx(1, | ||||
"datalen value too large, maximum is %d", | "datalen value too large, maximum is %d", | ||||
MAXDATALEN); | MAXDATALEN); | ||||
} | } | ||||
break; | } | ||||
case 'O': | if ((options & F_WAITTIME) != 0) { | ||||
options &= ~F_NOUSERDATA; | t = strtod(opts.arg_wait_time, &e); | ||||
options |= F_SUPTYPES; | if (*e || e == opts.arg_wait_time || t > (double)INT_MAX) | ||||
break; | |||||
case 'v': | |||||
options |= F_VERBOSE; | |||||
break; | |||||
case 'y': | |||||
options &= ~F_NOUSERDATA; | |||||
options |= F_FQDN; | |||||
break; | |||||
case 'Y': | |||||
options &= ~F_NOUSERDATA; | |||||
options |= F_FQDNOLD; | |||||
break; | |||||
case 'W': | |||||
t = strtod(optarg, &e); | |||||
if (*e || e == optarg || t > (double)INT_MAX) | |||||
err(EX_USAGE, "invalid timing interval: `%s'", | err(EX_USAGE, "invalid timing interval: `%s'", | ||||
optarg); | opts.arg_wait_time); | ||||
options |= F_WAITTIME; | |||||
waittime = (int)t; | waittime = (int)t; | ||||
break; | } | ||||
case 't': | if (opts.arg_timeout != NULL) { | ||||
alarmtimeout = strtoul(optarg, &e, 0); | alarmtimeout = strtoul(opts.arg_timeout, &e, 0); | ||||
if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX)) | if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX)) | ||||
errx(EX_USAGE, "invalid timeout: `%s'", | errx(EX_USAGE, "invalid timeout: `%s'", | ||||
optarg); | opts.arg_timeout); | ||||
if (alarmtimeout > MAXALARM) | if (alarmtimeout > MAXALARM) | ||||
errx(EX_USAGE, "invalid timeout: `%s' > %d", | errx(EX_USAGE, "invalid timeout: `%s' > %d", | ||||
optarg, MAXALARM); | opts.arg_timeout, MAXALARM); | ||||
alarm((int)alarmtimeout); | alarm((int)alarmtimeout); | ||||
break; | } | ||||
#ifdef IPSEC | #ifdef IPSEC | ||||
#ifdef IPSEC_POLICY_IPSEC | #ifdef IPSEC_POLICY_IPSEC | ||||
case 'P': | if ((options & F_POLICY) != 0) { | ||||
options |= F_POLICY; | if (!strncmp("in", opts.arg_ipsec_policy, 2)) { | ||||
if (!strncmp("in", optarg, 2)) { | if ((policy_in = strdup(opts.arg_ipsec_policy)) == NULL) | ||||
if ((policy_in = strdup(optarg)) == NULL) | |||||
errx(1, "strdup"); | errx(1, "strdup"); | ||||
} else if (!strncmp("out", optarg, 3)) { | } else if (!strncmp("out", opts.arg_ipsec_policy, 3)) { | ||||
if ((policy_out = strdup(optarg)) == NULL) | if ((policy_out = strdup(opts.arg_ipsec_policy)) == NULL) | ||||
errx(1, "strdup"); | errx(1, "strdup"); | ||||
} else | } else | ||||
errx(1, "invalid security policy"); | errx(1, "invalid security policy"); | ||||
break; | } | ||||
#else | |||||
case 'Z': | |||||
options |= F_AUTHHDR; | |||||
break; | |||||
case 'E': | |||||
options |= F_ENCRYPT; | |||||
break; | |||||
#endif /*IPSEC_POLICY_IPSEC*/ | #endif /*IPSEC_POLICY_IPSEC*/ | ||||
#endif /*IPSEC*/ | #endif /*IPSEC*/ | ||||
default: | |||||
usage(); | |||||
/*NOTREACHED*/ | |||||
} | |||||
} | |||||
argc -= optind; | argc -= optind; | ||||
argv += optind; | argv += optind; | ||||
if (argc < 1) { | if (argc < 1) { | ||||
usage(); | usage(); | ||||
/*NOTREACHED*/ | /*NOTREACHED*/ | ||||
} | } | ||||
▲ Show 20 Lines • Show All 2,243 Lines • Show Last 20 Lines |
This check is redundant with the one in options.c