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);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to