Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 4 May 2020 15:00:20 +0000 (UTC)
From:      "Alexander V. Chernikov" <melifaro@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r360630 - head/sys/net/route
Message-ID:  <202005041500.044F0KMA044259@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: melifaro
Date: Mon May  4 15:00:19 2020
New Revision: 360630
URL: https://svnweb.freebsd.org/changeset/base/360630

Log:
  Simplify address parsing in DDB show route command.
  
  Use db_get_line() to overcome parser limitation.
  
  Differential Revision:	https://reviews.freebsd.org/D24662

Modified:
  head/sys/net/route/route_ddb.c

Modified: head/sys/net/route/route_ddb.c
==============================================================================
--- head/sys/net/route/route_ddb.c	Mon May  4 14:31:45 2020	(r360629)
+++ head/sys/net/route/route_ddb.c	Mon May  4 15:00:19 2020	(r360630)
@@ -30,6 +30,7 @@ __FBSDID("$FreeBSD$");
 #include "opt_inet.h"
 #include "opt_inet6.h"
 
+#include <sys/ctype.h>
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/malloc.h>
@@ -206,239 +207,45 @@ DB_SHOW_COMMAND(routetable, db_show_routetable_cmd)
 
 _DB_FUNC(_show, route, db_show_route_cmd, db_show_table, CS_OWN, NULL)
 {
-	char buf[INET6_ADDRSTRLEN], *bp;
-	const void *dst_addrp;
-	struct sockaddr *dstp;
+	char abuf[INET6_ADDRSTRLEN], *buf, *end;
+	void *dst_addrp;
 	struct rtentry *rt;
 	union {
 		struct sockaddr_in dest_sin;
 		struct sockaddr_in6 dest_sin6;
 	} u;
-	uint16_t hextets[8];
-	unsigned i, tets;
-	int t, af, exp, tokflags;
+	int af;
 
-	/*
-	 * Undecoded address family.  No double-colon expansion seen yet.
-	 */
-	af = -1;
-	exp = -1;
-	/* Assume INET6 to start; we can work back if guess was wrong. */
-	tokflags = DRT_WSPACE | DRT_HEX | DRT_HEXADECIMAL;
+	buf = db_get_line();
 
-	/*
-	 * db_command has lexed 'show route' for us.
-	 */
-	t = db_read_token_flags(tokflags);
-	if (t == tWSPACE)
-		t = db_read_token_flags(tokflags);
+	/* Remove whitespaces from both ends */
+	end = buf + strlen(buf) - 1;
+	for (; (end >= buf) && (*end=='\n' || isspace(*end)); end--)
+		*end = '\0';
+	while (isspace(*buf))
+		buf++;
 
-	/*
-	 * tEOL: Just 'show route' isn't a valid mode.
-	 * tMINUS: It's either '-h' or some invalid option.  Regardless, usage.
-	 */
-	if (t == tEOL || t == tMINUS)
-		goto usage;
-
-	db_unread_token(t);
-
-	tets = nitems(hextets);
-
-	/*
-	 * Each loop iteration, we expect to read one octet (v4) or hextet
-	 * (v6), followed by an appropriate field separator ('.' or ':' or
-	 * '::').
-	 *
-	 * At the start of each loop, we're looking for a number (octet or
-	 * hextet).
-	 *
-	 * INET6 addresses have a special case where they may begin with '::'.
-	 */
-	for (i = 0; i < tets; i++) {
-		t = db_read_token_flags(tokflags);
-
-		if (t == tCOLONCOLON) {
-			/* INET6 with leading '::' or invalid. */
-			if (i != 0) {
-				db_printf("Parse error: unexpected extra "
-				    "colons.\n");
-				goto exit;
-			}
-
-			af = AF_INET6;
-			exp = i;
-			hextets[i] = 0;
-			continue;
-		} else if (t == tNUMBER) {
-			/*
-			 * Lexer separates out '-' as tMINUS, but make the
-			 * assumption explicit here.
-			 */
-			MPASS(db_tok_number >= 0);
-
-			if (af == AF_INET && db_tok_number > UINT8_MAX) {
-				db_printf("Not a valid v4 octet: %ld\n",
-				    (long)db_tok_number);
-				goto exit;
-			}
-			hextets[i] = db_tok_number;
-		} else if (t == tEOL) {
-			/*
-			 * We can only detect the end of an IPv6 address in
-			 * compact representation with EOL.
-			 */
-			if (af != AF_INET6 || exp < 0) {
-				db_printf("Parse failed.  Got unexpected EOF "
-				    "when the address is not a compact-"
-				    "representation IPv6 address.\n");
-				goto exit;
-			}
-			break;
-		} else {
-			db_printf("Parse failed.  Unexpected token %d.\n", t);
-			goto exit;
-		}
-
-		/* Next, look for a separator, if appropriate. */
-		if (i == tets - 1)
-			continue;
-
-		t = db_read_token_flags(tokflags);
-		if (af < 0) {
-			if (t == tCOLON) {
-				af = AF_INET6;
-				continue;
-			}
-			if (t == tCOLONCOLON) {
-				af = AF_INET6;
-				i++;
-				hextets[i] = 0;
-				exp = i;
-				continue;
-			}
-			if (t == tDOT) {
-				unsigned hn, dn;
-
-				af = AF_INET;
-				/* Need to fixup the first parsed number. */
-				if (hextets[0] > 0x255 ||
-				    (hextets[0] & 0xf0) > 0x90 ||
-				    (hextets[0] & 0xf) > 9) {
-					db_printf("Not a valid v4 octet: %x\n",
-					    hextets[0]);
-					goto exit;
-				}
-
-				hn = hextets[0];
-				dn = (hn >> 8) * 100 +
-				    ((hn >> 4) & 0xf) * 10 +
-				    (hn & 0xf);
-
-				hextets[0] = dn;
-
-				/* Switch to decimal for remaining octets. */
-				tokflags &= ~DRT_RADIX_MASK;
-				tokflags |= DRT_DECIMAL;
-
-				tets = 4;
-				continue;
-			}
-
-			db_printf("Parse error.  Unexpected token %d.\n", t);
-			goto exit;
-		} else if (af == AF_INET) {
-			if (t == tDOT)
-				continue;
-			db_printf("Expected '.' (%d) between octets but got "
-			    "(%d).\n", tDOT, t);
-			goto exit;
-
-		} else if (af == AF_INET6) {
-			if (t == tCOLON)
-				continue;
-			if (t == tCOLONCOLON) {
-				if (exp < 0) {
-					i++;
-					hextets[i] = 0;
-					exp = i;
-					continue;
-				}
-				db_printf("Got bogus second '::' in v6 "
-				    "address.\n");
-				goto exit;
-			}
-			if (t == tEOL) {
-				/*
-				 * Handle in the earlier part of the loop
-				 * because we need to handle trailing :: too.
-				 */
-				db_unread_token(t);
-				continue;
-			}
-
-			db_printf("Expected ':' (%d) or '::' (%d) between "
-			    "hextets but got (%d).\n", tCOLON, tCOLONCOLON, t);
-			goto exit;
-		}
-	}
-
-	/* Check for trailing garbage. */
-	if (i == tets) {
-		t = db_read_token_flags(tokflags);
-		if (t != tEOL) {
-			db_printf("Got unexpected garbage after address "
-			    "(%d).\n", t);
-			goto exit;
-		}
-	}
-
-	/*
-	 * Need to expand compact INET6 addresses.
-	 *
-	 * Technically '::' for a single ':0:' is MUST NOT but just in case,
-	 * don't bother expanding that form (exp >= 0 && i == tets case).
-	 */
-	if (af == AF_INET6 && exp >= 0 && i < tets) {
-		if (exp + 1 < i) {
-			memmove(&hextets[exp + 1 + (nitems(hextets) - i)],
-			    &hextets[exp + 1],
-			    (i - (exp + 1)) * sizeof(hextets[0]));
-		}
-		memset(&hextets[exp + 1], 0, (nitems(hextets) - i) *
-		    sizeof(hextets[0]));
-	}
-
-	memset(&u, 0, sizeof(u));
-	if (af == AF_INET) {
-		u.dest_sin.sin_family = AF_INET;
-		u.dest_sin.sin_len = sizeof(u.dest_sin);
-		u.dest_sin.sin_addr.s_addr = htonl(
-		    ((uint32_t)hextets[0] << 24) |
-		    ((uint32_t)hextets[1] << 16) |
-		    ((uint32_t)hextets[2] << 8) |
-		    (uint32_t)hextets[3]);
-		dstp = (void *)&u.dest_sin;
-		dst_addrp = &u.dest_sin.sin_addr;
-	} else if (af == AF_INET6) {
-		u.dest_sin6.sin6_family = AF_INET6;
-		u.dest_sin6.sin6_len = sizeof(u.dest_sin6);
-		for (i = 0; i < nitems(hextets); i++)
-			u.dest_sin6.sin6_addr.s6_addr16[i] = htons(hextets[i]);
-		dstp = (void *)&u.dest_sin6;
+	/* Determine AF */
+	if (strchr(buf, ':') != NULL) {
+		af = AF_INET6;
+		u.dest_sin6.sin6_family = af;
+		u.dest_sin6.sin6_len = sizeof(struct sockaddr_in6);
 		dst_addrp = &u.dest_sin6.sin6_addr;
 	} else {
-		MPASS(false);
-		/* UNREACHABLE */
-		/* Appease Clang false positive: */
-		dstp = NULL;
+		af = AF_INET;
+		u.dest_sin.sin_family = af;
+		u.dest_sin.sin_len = sizeof(struct sockaddr_in);
+		dst_addrp = &u.dest_sin.sin_addr;
 	}
 
-	bp = inet_ntop(af, dst_addrp, buf, sizeof(buf));
-	if (bp != NULL)
-		db_printf("Looking up route to destination '%s'\n", bp);
+	if (inet_pton(af, buf, dst_addrp) != 1)
+		goto usage;
 
+	if (inet_ntop(af, dst_addrp, abuf, sizeof(abuf)) != NULL)
+		db_printf("Looking up route to destination '%s'\n", abuf);
+
 	CURVNET_SET(vnet0);
-	rt = rtalloc1(dstp, 0, RTF_RNH_LOCKED);
+	rt = rtalloc1((struct sockaddr *)&u, 0, RTF_RNH_LOCKED);
 	CURVNET_RESTORE();
 
 	if (rt == NULL) {
@@ -452,9 +259,7 @@ _DB_FUNC(_show, route, db_show_route_cmd, db_show_tabl
 	return;
 usage:
 	db_printf("Usage: 'show route <address>'\n"
-	    "  Currently accepts only dotted-decimal INET or colon-separated\n"
-	    "  hextet INET6 addresses.\n");
-exit:
+	    "  Currently accepts only IPv4 and IPv6 addresses\n");
 	db_skip_to_eol();
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202005041500.044F0KMA044259>