Index: sbin/ping6/options.h =================================================================== --- /dev/null +++ sbin/ping6/options.h @@ -0,0 +1,412 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (C) 2019 Jan Sucan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $KAME: ping6.c,v 1.169 2003/07/25 06:01:47 itojun Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* BSDI ping.c,v 2.3 1996/01/21 17:56:50 jch Exp */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Muuss. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $FreeBSD$ */ + +#ifndef OPTIONS_H +#define OPTIONS_H 1 + +#if 0 +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93"; +#endif /* not lint */ +#endif + +#include + +#include +#include + +#include + +#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 + +#ifndef IPSEC +#define ADDOPTS +#else +#ifdef IPSEC_POLICY_IPSEC +#define ADDOPTS "P:" +#else +#define ADDOPTS "ZE" +#endif /*IPSEC_POLICY_IPSEC*/ +#endif + +/* Options that are counted or have an argument. */ +struct options { + char *arg_addrtype; + char *arg_gateway; + char *arg_interface; + char *arg_ipsec_policy; + char *arg_pattern; + char *arg_source_address; + double interval; + double wait_time; + long hoplimit; + long packet_count; + long packet_size; + long preload; + unsigned long sock_buff_size; + unsigned long timeout; + unsigned int count_interface; + unsigned int count_nigroup; + unsigned int count_use_min_mtu; + bool f_hoplimit; + bool f_packet_count; + bool f_packet_size; + bool f_preload; + bool f_sock_buff_size; + bool f_timeout; +}; + +#endif /* OPTIONS_H */ + +#undef OPT_FLAG_AUTHHDR +#undef OPT_FLAG_MISSED +#undef OPT_FLAG_FQDNOLD +#undef OPT_FLAG_TIMEOUT +#undef OPT_FLAG_ADDRTYPE +#undef OPT_FLAG_GATEWAY +#undef OPT_FLAG_HOPLIMIT +#undef OPT_FLAG_USE_MIN_MTU +#undef OPT_FLAG_AUDIBLE +#undef OPT_FLAG_SUPTYPES +#undef OPT_FLAG_FQDN +#undef OPT_FLAG_WAITTIME +#undef GETOPT_STRING + +#ifdef OPTIONS_COMPAT +#define OPT_FLAG_AUTHHDR 'A' +#define OPT_FLAG_MISSED 'R' +#define OPT_FLAG_FQDNOLD 'W' +#define OPT_FLAG_TIMEOUT 'X' +#define OPT_FLAG_ADDRTYPE 'a' +#define OPT_FLAG_GATEWAY 'g' +#define OPT_FLAG_HOPLIMIT 'h' +#define OPT_FLAG_USE_MIN_MTU 'm' +#define OPT_FLAG_AUDIBLE 'r' +#define OPT_FLAG_SUPTYPES 't' +#define OPT_FLAG_FQDN 'w' +#define OPT_FLAG_WAITTIME 'x' +#define GETOPT_STRING "a:b:c:DdfHg:h:I:i:l:mnNop:qrRS:s:tvwWx:X:" + +bool options_parse_compat(int argc, char *argv[], struct options *const opts, + u_int *const flags); +#else /* !OPTIONS_COMPAT */ +#define OPT_FLAG_AUTHHDR 'Z' +#define OPT_FLAG_MISSED 'A' +#define OPT_FLAG_FQDNOLD 'Y' +#define OPT_FLAG_TIMEOUT 't' +#define OPT_FLAG_ADDRTYPE 'k' +#define OPT_FLAG_GATEWAY 'e' +#define OPT_FLAG_HOPLIMIT 'm' +#define OPT_FLAG_USE_MIN_MTU 'u' +#define OPT_FLAG_AUDIBLE 'a' +#define OPT_FLAG_SUPTYPES 'O' +#define OPT_FLAG_FQDN 'y' +#define OPT_FLAG_WAITTIME 'W' +#define GETOPT_STRING "k:b:c:DdfHe:m:I:i:l:unNop:qaAS:s:OvyYW:t:" + +bool options_parse(int argc, char *argv[], struct options *const opts, + u_int *const flags); +#endif /* OPTIONS_COMPAT */ + +#ifdef OPTIONS_COMPAT +bool options_parse_compat(int argc, char *argv[], struct options *const opts, + u_int *const flags) +#else /* !OPTIONS_COMPAT */ +bool options_parse(int argc, char *argv[], struct options *const opts, + u_int *const flags) +#endif /* OPTIONS_COMPAT */ +{ + int ch; + char *e; + + memset(opts, 0, sizeof(*opts)); + + while ((ch = getopt(argc, argv, GETOPT_STRING ADDOPTS)) != -1) { + switch (ch) { + case OPT_FLAG_ADDRTYPE: + *flags &= ~F_NOUSERDATA; + *flags |= F_NODEADDR; + opts->arg_addrtype = optarg; + break; + case 'b': +#if defined(SO_SNDBUF) && defined(SO_RCVBUF) + errno = 0; + e = NULL; + opts->sock_buff_size = strtoul(optarg, &e, 10); + if (errno || !*optarg || *e) + errx(1, "invalid socket buffer size"); + opts->f_sock_buff_size = true; + break; +#else + errx(1, "-b option ignored: SO_SNDBUF/SO_RCVBUF socket" + "options not supported"); + /*NOTREACHED*/ +#endif + case 'c': + opts->packet_count = strtol(optarg, &e, 10); + if (*optarg == '\0' || *e != '\0') + errx(1, "illegal number of packets -- %s", + optarg); + opts->f_packet_count = true; + break; + case 'D': + *flags |= F_DONTFRAG; + break; + case 'd': + *flags |= F_SO_DEBUG; + break; + case 'f': + *flags |= F_FLOOD; + break; + case OPT_FLAG_GATEWAY: + opts->arg_gateway = optarg; + break; + case 'H': + *flags |= F_HOSTNAME; + break; + case OPT_FLAG_HOPLIMIT: + opts->hoplimit = strtol(optarg, &e, 10); + if (*optarg == '\0' || *e != '\0') + errx(1, "illegal hoplimit %s", optarg); + opts->f_hoplimit = true; + break; + case 'I': + *flags |= F_INTERFACE; + opts->arg_interface = optarg; + (opts->count_interface)++; + break; + case 'i': + opts->interval = strtod(optarg, &e); + if (*optarg == '\0' || *e != '\0') + errx(1, "illegal timing interval %s", optarg); + *flags |= F_INTERVAL; + break; + case 'l': + opts->preload = strtol(optarg, &e, 10); + if (*optarg == '\0' || *e != '\0') + errx(1, "illegal preload value -- %s", optarg); + opts->f_preload = true; + break; + case OPT_FLAG_USE_MIN_MTU: +#ifdef IPV6_USE_MIN_MTU + (opts->count_use_min_mtu)++; + break; +#else + errx(1, "-u is not supported on this platform"); + /*NOTREACHED*/ +#endif + case 'n': + *flags &= ~F_HOSTNAME; + break; + case 'N': + *flags |= F_NIGROUP; + (opts->count_nigroup)++; + break; + case 'o': + *flags |= F_ONCE; + break; + case 'p': + *flags |= F_PINGFILLED; + opts->arg_pattern = optarg; + break; + case 'q': + *flags |= F_QUIET; + break; + case OPT_FLAG_AUDIBLE: + *flags |= F_AUDIBLE; + break; + case OPT_FLAG_MISSED: + *flags |= F_MISSED; + break; + case 'S': + *flags |= F_SRCADDR; + opts->arg_source_address = optarg; + break; + case 's': + opts->packet_size = strtol(optarg, &e, 10); + if (*optarg == '\0' || *e != '\0') + errx(1, "illegal datalen value -- %s", optarg); + opts->f_packet_size = true; + break; + case OPT_FLAG_SUPTYPES: + *flags &= ~F_NOUSERDATA; + *flags |= F_SUPTYPES; + break; + case 'v': + *flags |= F_VERBOSE; + break; + case OPT_FLAG_FQDN: + *flags &= ~F_NOUSERDATA; + *flags |= F_FQDN; + break; + case OPT_FLAG_FQDNOLD: + *flags &= ~F_NOUSERDATA; + *flags |= F_FQDNOLD; + break; + case OPT_FLAG_WAITTIME: + opts->wait_time = strtod(optarg, &e); + if (*e || e == optarg) + err(EX_USAGE, "invalid timing interval: `%s'", + optarg); + *flags |= F_WAITTIME; + break; + case OPT_FLAG_TIMEOUT: + errno = 0; + e = NULL; + opts->timeout = strtoul(optarg, &e, 0); + if (errno || !*optarg || *e) + errx(EX_USAGE, "invalid timeout: `%s'", + optarg); + opts->f_timeout = true; + break; +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC + case 'P': + *flags |= F_POLICY; + opts->arg_ipsec_policy = optarg; + break; +#else + case OPT_FLAG_AUTHHDR: + *flags |= F_AUTHHDR; + break; + case 'E': + *flags |= F_ENCRYPT; + break; +#endif /*IPSEC_POLICY_IPSEC*/ +#endif /*IPSEC*/ + default: + return (false); + } + } + + return (true); +} Index: sbin/ping6/ping6.c =================================================================== --- sbin/ping6/ping6.c +++ sbin/ping6/ping6.c @@ -142,6 +142,9 @@ #include +#undef OPTIONS_COMPAT +#include "options.h" + struct tv32 { u_int32_t tv32_sec; u_int32_t tv32_nsec; @@ -168,36 +171,6 @@ #define CLR(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; #define IN6LEN sizeof(struct in6_addr) @@ -299,17 +272,17 @@ struct sockaddr_in6 from, *sin6; struct addrinfo hints, *res; struct sigaction si_sa; + struct options opts; int cc, i; - int almost_done, ch, hold, packlen, preload, optval, error; + int almost_done, hold, packlen, preload, optval, error; int nig_oldmcprefix = -1; u_char *datap; - char *e, *target, *ifname = NULL, *gateway = NULL; + char *target, *ifname = NULL, *gateway = NULL; int ip6optlen = 0; struct cmsghdr *scmsgp = NULL; /* For control (ancillary) data received from recvmsg() */ u_char cm[CONTROLLEN]; #if defined(SO_SNDBUF) && defined(SO_RCVBUF) - u_long lsockbufsize; int sockbufsize = 0; #endif int usepktinfo = 0; @@ -320,7 +293,6 @@ char *policy_in = NULL; char *policy_out = NULL; #endif - double t; u_long alarmtimeout; size_t rthlen; #ifdef IPV6_USE_MIN_MTU @@ -341,276 +313,179 @@ alarmtimeout = preload = 0; datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN]; capdns = capdns_setup(); -#ifndef IPSEC -#define ADDOPTS -#else -#ifdef IPSEC_POLICY_IPSEC -#define ADDOPTS "P:" -#else -#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; - - options &= ~F_NOUSERDATA; - options |= F_NODEADDR; - for (cp = optarg; *cp != '\0'; cp++) { - switch (*cp) { - case 'a': - naflags |= NI_NODEADDR_FLAG_ALL; - break; - case 'c': - case 'C': - naflags |= NI_NODEADDR_FLAG_COMPAT; - break; - case 'l': - case 'L': - naflags |= NI_NODEADDR_FLAG_LINKLOCAL; - break; - case 's': - case 'S': - naflags |= NI_NODEADDR_FLAG_SITELOCAL; - break; - case 'g': - case 'G': - naflags |= NI_NODEADDR_FLAG_GLOBAL; - break; - case 'A': /* experimental. not in the spec */ + + if (!options_parse(argc, argv, &opts, &options)) + usage(); + /* NOTREACHED */ + + if ((options & F_NODEADDR) != 0) { + char *cp; + + for (cp = opts.arg_addrtype; *cp != '\0'; cp++) { + switch (*cp) { + case 'a': + naflags |= NI_NODEADDR_FLAG_ALL; + break; + case 'c': + case 'C': + naflags |= NI_NODEADDR_FLAG_COMPAT; + break; + case 'l': + case 'L': + naflags |= NI_NODEADDR_FLAG_LINKLOCAL; + break; + case 's': + case 'S': + naflags |= NI_NODEADDR_FLAG_SITELOCAL; + break; + case 'g': + case 'G': + naflags |= NI_NODEADDR_FLAG_GLOBAL; + break; + case 'A': /* experimental. not in the spec */ #ifdef NI_NODEADDR_FLAG_ANYCAST - naflags |= NI_NODEADDR_FLAG_ANYCAST; - break; + naflags |= NI_NODEADDR_FLAG_ANYCAST; + break; #else - errx(1, -"-a A is not supported on the platform"); - /*NOTREACHED*/ + errx(1, + "-a A is not supported on the platform"); + /*NOTREACHED*/ #endif - default: - usage(); - /*NOTREACHED*/ - } + default: + usage(); + /*NOTREACHED*/ } - break; } - case 'b': -#if defined(SO_SNDBUF) && defined(SO_RCVBUF) - errno = 0; - e = NULL; - lsockbufsize = strtoul(optarg, &e, 10); - sockbufsize = (int)lsockbufsize; - if (errno || !*optarg || *e || - lsockbufsize > INT_MAX) - errx(1, "invalid socket buffer size"); -#else - errx(1, -"-b option ignored: SO_SNDBUF/SO_RCVBUF socket options not supported"); -#endif - break; - case 'c': - 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()) { - errno = EPERM; - errx(1, "Must be superuser to flood ping"); - } - options |= F_FLOOD; - setbuf(stdout, (char *)NULL); - break; - case 'e': - gateway = optarg; - break; - case 'H': - options |= F_HOSTNAME; - break; - case 'm': /* hoplimit */ - hoplimit = strtol(optarg, &e, 10); - if (*optarg == '\0' || *e != '\0') - errx(1, "illegal hoplimit %s", optarg); - if (255 < hoplimit || hoplimit < -1) - errx(1, - "illegal hoplimit -- %s", optarg); - break; - case 'I': - ifname = optarg; - options |= F_INTERFACE; + } + if (opts.f_sock_buff_size) { + if (opts.sock_buff_size > INT_MAX) + errx(1, "invalid socket buffer size"); + sockbufsize = (int)opts.sock_buff_size; + } + if (opts.f_packet_count) { + if (opts.packet_count <= 0) + errx(1, "illegal number of packets -- %ld", + opts.packet_count); + npackets = opts.packet_count; + } + if ((options & F_FLOOD) != 0) { + if (getuid()) { + errno = EPERM; + errx(1, "Must be superuser to flood ping"); + } + setbuf(stdout, (char *)NULL); + } + if (opts.arg_gateway != NULL) + gateway = opts.arg_gateway; + if (opts.f_hoplimit) { + if (255 < opts.hoplimit || opts.hoplimit < -1) + errx(1, "illegal hoplimit -- %ld", opts.hoplimit); + hoplimit = opts.hoplimit; + + } + if ((options & F_INTERFACE) != 0) { + ifname = opts.arg_interface; #ifndef USE_SIN6_SCOPE_ID - usepktinfo++; + usepktinfo += opts.count_interface; #endif - break; - case 'i': /* wait between sending packets */ - t = strtod(optarg, &e); - if (*optarg == '\0' || *e != '\0') - errx(1, "illegal timing interval %s", optarg); - if (t < 1 && getuid()) { - errx(1, "%s: only root may use interval < 1s", - strerror(EPERM)); - } - intvl.tv_sec = (time_t)t; - intvl.tv_nsec = - (long)((t - intvl.tv_sec) * 1000000000); - if (intvl.tv_sec < 0) - errx(1, "illegal timing interval %s", optarg); - /* less than 1/hz does not make sense */ - if (intvl.tv_sec == 0 && intvl.tv_nsec < 1000) { - warnx("too small interval, raised to .000001"); - intvl.tv_nsec = 1000; - } - options |= F_INTERVAL; - break; - case 'l': - if (getuid()) { - errno = EPERM; - errx(1, "Must be superuser to preload"); - } - preload = strtol(optarg, &e, 10); - if (preload < 0 || *optarg == '\0' || *e != '\0') - errx(1, "illegal preload value -- %s", optarg); - break; - case 'u': -#ifdef IPV6_USE_MIN_MTU - mflag++; - break; -#else - errx(1, "-%c is not supported on this platform", ch); - /*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)); - hints.ai_flags = AI_NUMERICHOST; /* allow hostname? */ - hints.ai_family = AF_INET6; - hints.ai_socktype = SOCK_RAW; - hints.ai_protocol = IPPROTO_ICMPV6; + } + if ((options & F_INTERVAL) != 0) { + if (opts.interval < 1 && getuid()) { + errx(1, "%s: only root may use interval < 1s", + strerror(EPERM)); + } + intvl.tv_sec = (time_t)(opts.interval); + intvl.tv_nsec = + (long)((opts.interval - intvl.tv_sec) * 1000000000); + if (intvl.tv_sec < 0) + errx(1, "illegal timing interval %f", opts.interval); + /* less than 1/hz does not make sense */ + if (intvl.tv_sec == 0 && intvl.tv_nsec < 1000) { + warnx("too small interval, raised to .000001"); + intvl.tv_nsec = 1000; + } + } + if (opts.f_preload) { + if (getuid()) { + errno = EPERM; + errx(1, "Must be superuser to preload"); + } + if (preload < 0) + errx(1, "illegal preload value -- %ld", opts.preload); + preload = opts.preload; + } + mflag += opts.count_use_min_mtu; + nig_oldmcprefix += opts.count_nigroup; + if ((options & F_PINGFILLED) != 0) + fill((char *)datap, opts.arg_pattern); + if ((options & F_SRCADDR) != 0) { + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags = AI_NUMERICHOST; /* allow hostname? */ + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_RAW; + hints.ai_protocol = IPPROTO_ICMPV6; - error = cap_getaddrinfo(capdns, optarg, NULL, &hints, &res); - if (error) { - errx(1, "invalid source address: %s", - gai_strerror(error)); - } - /* - * res->ai_family must be AF_INET6 and res->ai_addrlen - * must be sizeof(src). - */ - memcpy(&src, res->ai_addr, res->ai_addrlen); - srclen = res->ai_addrlen; - freeaddrinfo(res); - options |= F_SRCADDR; - break; - case 's': /* size of packet to send */ - datalen = strtol(optarg, &e, 10); - if (datalen <= 0 || *optarg == '\0' || *e != '\0') - errx(1, "illegal datalen value -- %s", optarg); - if (datalen > MAXDATALEN) { - errx(1, - "datalen value too large, maximum is %d", - MAXDATALEN); - } - break; - case 'O': - options &= ~F_NOUSERDATA; - options |= F_SUPTYPES; - 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'", - optarg); - options |= F_WAITTIME; - waittime = (int)t; - break; - case 't': - alarmtimeout = strtoul(optarg, &e, 0); - if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX)) - errx(EX_USAGE, "invalid timeout: `%s'", - optarg); - if (alarmtimeout > MAXALARM) - errx(EX_USAGE, "invalid timeout: `%s' > %d", - optarg, MAXALARM); - { - struct itimerval itv; - - timerclear(&itv.it_interval); - timerclear(&itv.it_value); - itv.it_value.tv_sec = (time_t)alarmtimeout; - if (setitimer(ITIMER_REAL, &itv, NULL) != 0) - err(1, "setitimer"); - } - break; + error = cap_getaddrinfo(capdns, opts.arg_source_address, NULL, + &hints, &res); + if (error) { + errx(1, "invalid source address: %s", + gai_strerror(error)); + } + /* + * res->ai_family must be AF_INET6 and res->ai_addrlen + * must be sizeof(src). + */ + memcpy(&src, res->ai_addr, res->ai_addrlen); + srclen = res->ai_addrlen; + freeaddrinfo(res); + } + if (opts.f_packet_size) { + if (opts.packet_size <= 0) + errx(1, "illegal datalen value -- %ld", + opts.packet_size); + if (opts.packet_size > MAXDATALEN) { + errx(1, + "datalen value too large, maximum is %d", + MAXDATALEN); + } + datalen = opts.packet_size; + } + if ((options & F_WAITTIME) != 0) { + if (opts.wait_time > (double)INT_MAX) + err(EX_USAGE, "invalid timing interval: `%f'", + opts.wait_time); + waittime = (int)opts.wait_time; + } + if (opts.f_timeout) { + if ((opts.timeout < 1) || (opts.timeout == ULONG_MAX)) + errx(EX_USAGE, "invalid timeout: `%lu'", opts.timeout); + if (opts.timeout > MAXALARM) + errx(EX_USAGE, "invalid timeout: `%lu' > %d", + opts.timeout, MAXALARM); + { + struct itimerval itv; + + timerclear(&itv.it_interval); + timerclear(&itv.it_value); + itv.it_value.tv_sec = (time_t)alarmtimeout; + if (setitimer(ITIMER_REAL, &itv, NULL) != 0) + err(1, "setitimer"); + } + } #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC - case 'P': - options |= F_POLICY; - if (!strncmp("in", optarg, 2)) { - if ((policy_in = strdup(optarg)) == NULL) - errx(1, "strdup"); - } else if (!strncmp("out", optarg, 3)) { - if ((policy_out = strdup(optarg)) == NULL) - errx(1, "strdup"); - } else - errx(1, "invalid security policy"); - break; -#else - case 'Z': - options |= F_AUTHHDR; - break; - case 'E': - options |= F_ENCRYPT; - break; + if ((options & F_POLICY) != 0) { + if (!strncmp("in", opts.arg_ipsec_policy, 2)) { + if ((policy_in = strdup(opts.arg_ipsec_policy)) == NULL) + errx(1, "strdup"); + } else if (!strncmp("out", opts.arg_ipsec_policy, 3)) { + if ((policy_out = strdup(opts.arg_ipsec_policy)) == NULL) + errx(1, "strdup"); + } else + errx(1, "invalid security policy"); + } #endif /*IPSEC_POLICY_IPSEC*/ #endif /*IPSEC*/ - default: - usage(); - /*NOTREACHED*/ - } - } argc -= optind; argv += optind;