ping: fix parsing of options including '4' and '6'

ping uses a two-pass option parser.  The first pass determines whether
ipv4 or ipv6 is desired, and the second parses the rest of the options.
But the first pass wrongly detects a '4' or '6' in an option's value as
a request to use ipv6 or ipv6 respectively, for example in an invocation
like "ping -c6 1.2.3.4".

Fix this confusion by including all options in the first round of
parsing, but ignoring those unrelated to ipv4/ipv6 selection.

PR:		258048
Reported by:	ghuckriede@blackberry.com
Submitted by:	ghuckriede@blackberry.com
MFC after:	2 weeks
Reviewed by:	emaste
Differential Revision: https://reviews.freebsd.org/D32344
This commit is contained in:
Alan Somers 2021-10-06 16:54:59 -06:00
parent 5c5340108e
commit 9ce201f2ee
5 changed files with 84 additions and 38 deletions

View File

@ -52,13 +52,11 @@ __FBSDID("$FreeBSD$");
#endif
#if defined(INET) && defined(INET6)
#define OPTSTR ":46"
#define OPTSTR PING6OPTS PING4OPTS
#elif defined(INET)
#define OPTSTR ":4"
#define OPTSTR PING4OPTS
#elif defined(INET6)
#define OPTSTR ":6"
#else
#define OPTSTR ""
#define OPTSTR PING6OPTS
#endif
int
@ -82,7 +80,7 @@ main(int argc, char *argv[])
ipv6 = true;
#endif
while ((ch = getopt(argc, argv, OPTSTR)) != -1) {
while ((ch = getopt(argc, argv, ":" OPTSTR)) != -1) {
switch(ch) {
#ifdef INET
case '4':
@ -170,7 +168,7 @@ usage(void)
"[-G sweepmaxsize]\n"
" [-g sweepminsize] [-h sweepincrsize] [-i wait] "
"[-l preload]\n"
" [-M mask | time] [-m ttl]"
" [-M mask | time] [-m ttl] "
#ifdef IPSEC
"[-P policy] "
#endif
@ -188,7 +186,7 @@ usage(void)
" [-z tos] IPv4-mcast-group\n"
#endif /* INET */
#ifdef INET6
"\tping [-6aADd"
"\tping [-6AaDd"
#if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC)
"E"
#endif

View File

@ -31,6 +31,26 @@
#ifndef MAIN_H
#define MAIN_H 1
#ifdef IPSEC
#include <netipsec/ipsec.h>
#endif /*IPSEC*/
#if defined(INET) && defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
#define PING4ADDOPTS "P:"
#else
#define PING4ADDOPTS
#endif
#define PING4OPTS "4AaC:c:DdfG:g:Hh:I:i:Ll:M:m:nop:QqRrS:s:T:t:vW:z:" PING4ADDOPTS
#if defined(INET6) && defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
#define PING6ADDOPTS "P:"
#elif defined(INET6) && defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC)
#define PING6ADDOPTS "ZE"
#else
#define PING6ADDOPTS
#endif
#define PING6OPTS "6Aab:C:c:Dde:fHI:i:k:l:m:nNoOp:qS:s:t:uvyYW:z:" PING6ADDOPTS
void usage(void) __dead2;
#endif

View File

@ -301,15 +301,7 @@ ping(int argc, char *const *argv)
alarmtimeout = df = preload = tos = pcp = 0;
outpack = outpackhdr + sizeof(struct ip);
while ((ch = getopt(argc, argv,
"4AaC:c:DdfG:g:Hh:I:i:Ll:M:m:nop:QqRrS:s:T:t:vW:z:"
#ifdef IPSEC
#ifdef IPSEC_POLICY_IPSEC
"P:"
#endif /*IPSEC_POLICY_IPSEC*/
#endif /*IPSEC*/
)) != -1)
{
while ((ch = getopt(argc, argv, PING4OPTS)) != -1) {
switch(ch) {
case '4':
/* This option is processed in main(). */

View File

@ -293,7 +293,11 @@ static void pr_rthdr(void *, size_t);
static int pr_bitrange(u_int32_t, int, int);
static void pr_retip(struct ip6_hdr *, u_char *);
static void summary(void);
#ifdef IPSEC
#ifdef IPSEC_POLICY_IPSEC
static int setpolicy(int, char *);
#endif
#endif
static char *nigroup(char *, int);
int
@ -345,18 +349,8 @@ ping6(int argc, char *argv[])
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,
"6k:b:C:c:DdfHe:m:I:i:l:unNop:qaAS:s:OvyYW:t:z:" ADDOPTS)) != -1) {
#undef ADDOPTS
while ((ch = getopt(argc, argv, PING6OPTS)) != -1) {
switch (ch) {
case '6':
/* This option is processed in main(). */
@ -2667,7 +2661,9 @@ pr_retip(struct ip6_hdr *ip6, u_char *end)
nh = ip6->ip6_nxt;
cp += hlen;
while (end - cp >= 8) {
#ifdef IPSEC
struct ah ah;
#endif
switch (nh) {
case IPPROTO_HOPOPTS:

View File

@ -27,14 +27,23 @@
#
# $FreeBSD$
require_ipv4() {
if ! getaddrinfo -f inet localhost 1>/dev/null 2>&1; then
atf_skip "IPv4 is not configured"
fi
}
require_ipv6() {
if ! getaddrinfo -f inet6 localhost 1>/dev/null 2>&1; then
atf_skip "IPv6 is not configured"
fi
}
atf_test_case ping_c1_s56_t1
ping_c1_s56_t1_head() {
atf_set "descr" "Stop after receiving 1 ECHO_RESPONSE packet"
}
ping_c1_s56_t1_body() {
if ! getaddrinfo -f inet localhost 1>/dev/null 2>&1; then
atf_skip "IPv4 is not configured"
fi
require_ipv4
atf_check -s exit:0 -o save:std.out -e empty \
ping -4 -c 1 -s 56 -t 1 localhost
check_ping_statistics std.out $(atf_get_srcdir)/ping_c1_s56_t1.out
@ -45,9 +54,7 @@ ping_6_c1_s8_t1_head() {
atf_set "descr" "Stop after receiving 1 ECHO_RESPONSE packet"
}
ping_6_c1_s8_t1_body() {
if ! getaddrinfo -f inet6 localhost 1>/dev/null 2>&1; then
atf_skip "IPv6 is not configured"
fi
require_ipv6
atf_check -s exit:0 -o save:std.out -e empty \
ping -6 -c 1 -s 8 -t 1 localhost
check_ping_statistics std.out $(atf_get_srcdir)/ping_6_c1_s8_t1.out
@ -58,18 +65,51 @@ ping6_c1_s8_t1_head() {
atf_set "descr" "Use IPv6 when invoked as ping6"
}
ping6_c1_s8_t1_body() {
if ! getaddrinfo -f inet6 localhost 1>/dev/null 2>&1; then
atf_skip "IPv6 is not configured"
fi
require_ipv6
atf_check -s exit:0 -o save:std.out -e empty \
ping6 -c 1 -s 8 -t 1 localhost
check_ping_statistics std.out $(atf_get_srcdir)/ping_6_c1_s8_t1.out
}
ping_c1t6_head() {
atf_set "descr" "-t6 is not interpreted as -t -6 by ping"
}
ping_c1t6_body() {
require_ipv4
atf_check -s exit:0 -o ignore -e empty ping -c1 -t6 127.0.0.1
}
ping6_c1t4_head() {
atf_set "descr" "-t4 is not interpreted as -t -4 by ping6"
}
ping6_c1t4_body() {
require_ipv6
atf_check -s exit:0 -o ignore -e empty ping6 -c1 -t4 ::1
}
ping_46_head() {
atf_set "descr" "-4 and -6 may not be used together"
}
ping_46_body() {
atf_check -s exit:1 -e ignore ping -4 -6
}
ping6_46_head() {
atf_set "descr" "-4 and -6 may not be used together"
}
ping6_46_body() {
atf_check -s exit:1 -e ignore ping6 -4 -6
}
atf_init_test_cases() {
atf_add_test_case ping_c1_s56_t1
atf_add_test_case ping_6_c1_s8_t1
atf_add_test_case ping6_c1_s8_t1
atf_add_test_case ping_c1t6
atf_add_test_case ping6_c1t4
atf_add_test_case ping_46
atf_add_test_case ping6_46
}
check_ping_statistics() {