aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Somers <asomers@FreeBSD.org>2021-10-06 22:54:59 +0000
committerAlan Somers <asomers@FreeBSD.org>2021-10-21 00:05:43 +0000
commit9ce201f2ee3ca340032d9cc71d91a36b3b45a4c3 (patch)
treee64276853b0fb7d55268dce1c691c4b39b6494c7
parent5c5340108e9c2e384ca646720e17d037c69acc4c (diff)
downloadsrc-9ce201f2ee3ca340032d9cc71d91a36b3b45a4c3.tar.gz
src-9ce201f2ee3ca340032d9cc71d91a36b3b45a4c3.zip
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
-rw-r--r--sbin/ping/main.c14
-rw-r--r--sbin/ping/main.h20
-rw-r--r--sbin/ping/ping.c10
-rw-r--r--sbin/ping/ping6.c20
-rw-r--r--sbin/ping/tests/ping_test.sh58
5 files changed, 84 insertions, 38 deletions
diff --git a/sbin/ping/main.c b/sbin/ping/main.c
index 01442679efff..c021e2c26b14 100644
--- a/sbin/ping/main.c
+++ b/sbin/ping/main.c
@@ -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
diff --git a/sbin/ping/main.h b/sbin/ping/main.h
index f9707ccfb5ff..0f987e9a20ae 100644
--- a/sbin/ping/main.h
+++ b/sbin/ping/main.h
@@ -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
diff --git a/sbin/ping/ping.c b/sbin/ping/ping.c
index fe197928085e..be535f72146a 100644
--- a/sbin/ping/ping.c
+++ b/sbin/ping/ping.c
@@ -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(). */
diff --git a/sbin/ping/ping6.c b/sbin/ping/ping6.c
index 4cbeae770372..76a96f0631ff 100644
--- a/sbin/ping/ping6.c
+++ b/sbin/ping/ping6.c
@@ -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:
diff --git a/sbin/ping/tests/ping_test.sh b/sbin/ping/tests/ping_test.sh
index ed95594abbd2..54af89f4a22b 100644
--- a/sbin/ping/tests/ping_test.sh
+++ b/sbin/ping/tests/ping_test.sh
@@ -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() {