summaryrefslogtreecommitdiffstats
path: root/sbin/ipfw/tables.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/ipfw/tables.c')
-rw-r--r--sbin/ipfw/tables.c203
1 files changed, 110 insertions, 93 deletions
diff --git a/sbin/ipfw/tables.c b/sbin/ipfw/tables.c
index 4829fec..b3473fc 100644
--- a/sbin/ipfw/tables.c
+++ b/sbin/ipfw/tables.c
@@ -35,6 +35,7 @@
#include <netinet/in.h>
#include <netinet/ip_fw.h>
#include <arpa/inet.h>
+#include <netdb.h>
#include "ipfw2.h"
@@ -714,6 +715,7 @@ table_print_valheader(char *buf, size_t bufsize, uint32_t vmask)
return;
}
+ memset(buf, 0, bufsize);
print_flags_buffer(buf, bufsize, tablevaltypes, vmask);
}
@@ -1308,6 +1310,63 @@ tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type,
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)
@@ -1315,7 +1374,6 @@ tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
uint8_t type, tflags;
uint32_t vmask;
int error;
- char *del;
type = 0;
tflags = 0;
@@ -1327,10 +1385,24 @@ tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
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",
@@ -1339,24 +1411,16 @@ tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
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);
@@ -1384,6 +1448,7 @@ static void
tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
uint8_t type, uint32_t vmask)
{
+ struct addrinfo hints, *res;
uint32_t a4, flag, val, vm;
ipfw_table_value *v;
uint32_t i;
@@ -1494,9 +1559,19 @@ tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
}
break;
case IPFW_VTYPE_NH6:
- if (strchr(n, ':') != NULL &&
- inet_pton(AF_INET6, n, &v->nh6) == 1)
- break;
+ if (strchr(n, ':') != NULL) {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET6;
+ hints.ai_flags = AI_NUMERICHOST;
+ if (getaddrinfo(n, NULL, &hints, &res) == 0) {
+ v->nh6 = ((struct sockaddr_in6 *)
+ res->ai_addr)->sin6_addr;
+ v->zoneid = ((struct sockaddr_in6 *)
+ res->ai_addr)->sin6_scope_id;
+ freeaddrinfo(res);
+ break;
+ }
+ }
etype = "ipv6";
break;
}
@@ -1643,10 +1718,11 @@ static void
table_show_value(char *buf, size_t bufsize, ipfw_table_value *v,
uint32_t vmask, int print_ip)
{
+ char abuf[INET6_ADDRSTRLEN + IF_NAMESIZE + 2];
+ struct sockaddr_in6 sa6;
uint32_t flag, i, l;
size_t sz;
struct in_addr a4;
- char abuf[INET6_ADDRSTRLEN];
sz = bufsize;
@@ -1702,8 +1778,15 @@ table_show_value(char *buf, size_t bufsize, ipfw_table_value *v,
l = snprintf(buf, sz, "%d,", v->dscp);
break;
case IPFW_VTYPE_NH6:
- inet_ntop(AF_INET6, &v->nh6, abuf, sizeof(abuf));
- l = snprintf(buf, sz, "%s,", abuf);
+ sa6.sin6_family = AF_INET6;
+ sa6.sin6_len = sizeof(sa6);
+ sa6.sin6_addr = v->nh6;
+ sa6.sin6_port = 0;
+ sa6.sin6_scope_id = v->zoneid;
+ if (getnameinfo((const struct sockaddr *)&sa6,
+ sa6.sin6_len, abuf, sizeof(abuf), NULL, 0,
+ NI_NUMERICHOST) == 0)
+ l = snprintf(buf, sz, "%s,", abuf);
break;
}
@@ -1862,11 +1945,12 @@ struct _table_value {
uint32_t nat; /* O_NAT */
uint32_t nh4;
uint8_t dscp;
- uint8_t spare0[3];
+ uint8_t spare0;
+ uint16_t spare1;
/* -- 32 bytes -- */
struct in6_addr nh6;
uint32_t limit; /* O_LIMIT */
- uint32_t spare1;
+ uint32_t zoneid;
uint64_t refcnt; /* Number of references */
};
@@ -1916,73 +2000,6 @@ ipfw_list_values(int ac, char *av[])
}
int
-compare_ntlv(const void *_a, const void *_b)
-{
- ipfw_obj_ntlv *a, *b;
-
- a = (ipfw_obj_ntlv *)_a;
- b = (ipfw_obj_ntlv *)_b;
-
- if (a->set < b->set)
- return (-1);
- else if (a->set > b->set)
- return (1);
-
- if (a->idx < b->idx)
- return (-1);
- else if (a->idx > b->idx)
- return (1);
-
- return (0);
-}
-
-int
-compare_kntlv(const void *k, const void *v)
-{
- ipfw_obj_ntlv *ntlv;
- uint16_t key;
-
- key = *((uint16_t *)k);
- ntlv = (ipfw_obj_ntlv *)v;
-
- if (key < ntlv->idx)
- return (-1);
- else if (key > ntlv->idx)
- return (1);
-
- return (0);
-}
-
-/*
- * Finds table name in @ctlv by @idx.
- * Uses the following facts:
- * 1) All TLVs are the same size
- * 2) Kernel implementation provides already sorted list.
- *
- * Returns table name or NULL.
- */
-char *
-table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx)
-{
- ipfw_obj_ntlv *ntlv;
-
- ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize,
- compare_kntlv);
-
- if (ntlv != 0)
- return (ntlv->name);
-
- return (NULL);
-}
-
-void
-table_sort_ctlv(ipfw_obj_ctlv *ctlv)
-{
-
- qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv);
-}
-
-int
table_check_name(char *tablename)
{
int c, i, l;
OpenPOWER on IntegriCloud