Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 19 May 2015 18:29:14 +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: r283118 - head/sbin/ipfw
Message-ID:  <201505191829.t4JITEWl001068@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: melifaro
Date: Tue May 19 18:29:13 2015
New Revision: 283118
URL: https://svnweb.freebsd.org/changeset/base/283118

Log:
  Bring back support for checking tables via "ipfw -n".
  
  Currently we have different table key types which can easily interfere
  with each other (numbers and IPv4 address, interface names and hostnames,
    flows and hostnames/addresses).
  This conflicts are solved by [auto-]creating _typed_ tables, so after
  table is created, only keys of given type can be inserted to that table.
  ipfw(8) consults with kernel about key/value type for particular table so
  it knows key/value interpretation.
  However, we have 2 cases (adding entries to non-existing table and
    parsing configuration file via `ipfw -n`) when kernel is unable to
    provide us table info we need. Fix the latter case by partially importing
    old `table_fill_xentry()` parse function responsible for guessing key type.
  
  Sponsored by:	Yandex LLC

Modified:
  head/sbin/ipfw/tables.c

Modified: head/sbin/ipfw/tables.c
==============================================================================
--- head/sbin/ipfw/tables.c	Tue May 19 17:14:27 2015	(r283117)
+++ head/sbin/ipfw/tables.c	Tue May 19 18:29:13 2015	(r283118)
@@ -1310,6 +1310,63 @@ tentry_fill_key_type(char *arg, ipfw_obj
 	tentry->masklen = masklen;
 }
 
+/*
+ * Tries to guess table key type.
+ * This procedure is used in legacy table auto-create
+ * code AND in `ipfw -n` ruleset checking.
+ *
+ * Imported from old table_fill_xentry() parse code.
+ */
+static int
+guess_key_type(char *key, uint8_t *ptype)
+{
+	char *p;
+	struct in6_addr addr;
+	uint32_t kv;
+
+	if (ishexnumber(*key) != 0 || *key == ':') {
+		/* Remove / if exists */
+		if ((p = strchr(key, '/')) != NULL)
+			*p = '\0';
+
+		if ((inet_pton(AF_INET, key, &addr) == 1) ||
+		    (inet_pton(AF_INET6, key, &addr) == 1)) {
+			*ptype = IPFW_TABLE_CIDR;
+			if (p != NULL)
+				*p = '/';
+			return (0);
+		} else {
+			/* Port or any other key */
+			/* Skip non-base 10 entries like 'fa1' */
+			kv = strtol(key, &p, 10);
+			if (*p == '\0') {
+				*ptype = IPFW_TABLE_NUMBER;
+				return (0);
+			} else if ((p != key) && (*p == '.')) {
+				/*
+				 * Warn on IPv4 address strings
+				 * which are "valid" for inet_aton() but not
+				 * in inet_pton().
+				 *
+				 * Typical examples: '10.5' or '10.0.0.05'
+				 */
+				return (1);
+			}
+		}
+	}
+
+	if (strchr(key, '.') == NULL) {
+		*ptype = IPFW_TABLE_INTERFACE;
+		return (0);
+	}
+
+	if (lookup_host(key, (struct in_addr *)&addr) != 0)
+		return (1);
+
+	*ptype = IPFW_TABLE_CIDR;
+	return (0);
+}
+
 static void
 tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
     int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi)
@@ -1317,7 +1374,6 @@ tentry_fill_key(ipfw_obj_header *oh, ipf
 	uint8_t type, tflags;
 	uint32_t vmask;
 	int error;
-	char *del;
 
 	type = 0;
 	tflags = 0;
@@ -1329,10 +1385,24 @@ tentry_fill_key(ipfw_obj_header *oh, ipf
 		error = 0;
 
 	if (error == 0) {
-		/* Table found. */
-		type = xi->type;
-		tflags = xi->tflags;
-		vmask = xi->vmask;
+		if (co.test_only == 0) {
+			/* Table found */
+			type = xi->type;
+			tflags = xi->tflags;
+			vmask = xi->vmask;
+		} else {
+			/*
+			 * we're running `ipfw -n`
+			 * Compability layer: try to guess key type
+			 * before failing.
+			 */
+			if (guess_key_type(key, &type) != 0) {
+				/* Inknown key */
+				errx(EX_USAGE, "Cannot guess "
+				    "key '%s' type", key);
+			}
+			vmask = IPFW_VTYPE_LEGACY;
+		}
 	} else {
 		if (error != ESRCH)
 			errx(EX_OSERR, "Error requesting table %s info",
@@ -1341,24 +1411,16 @@ tentry_fill_key(ipfw_obj_header *oh, ipf
 			errx(EX_DATAERR, "Table %s does not exist",
 			    oh->ntlv.name);
 		/*
-		 * Table does not exist.
-		 * Compability layer: try to interpret data as ADDR
-		 * before failing.
+		 * Table does not exist
+		 * Compability layer: try to guess key type before failing.
 		 */
-		if ((del = strchr(key, '/')) != NULL)
-			*del = '\0';
-		if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 ||
-		    inet_pton(AF_INET6, key, &tent->k.addr6) == 1) {
-			/* OK Prepare and send */
-			type = IPFW_TABLE_ADDR;
-			vmask = IPFW_VTYPE_LEGACY;
-		} else {
+		if (guess_key_type(key, &type) != 0) {
 			/* Inknown key */
 			errx(EX_USAGE, "Table %s does not exist, cannot guess "
 			    "key '%s' type", oh->ntlv.name, key);
 		}
-		if (del != NULL)
-			*del = '/';
+
+		vmask = IPFW_VTYPE_LEGACY;
 	}
 
 	tentry_fill_key_type(key, tent, type, tflags);



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