Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 6 Jul 2014 18:16:05 +0000 (UTC)
From:      "Alexander V. Chernikov" <melifaro@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r268329 - in projects/ipfw: sbin/ipfw sys/netinet sys/netpfil/ipfw
Message-ID:  <201407061816.s66IG5xg037994@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: melifaro
Date: Sun Jul  6 18:16:04 2014
New Revision: 268329
URL: http://svnweb.freebsd.org/changeset/base/268329

Log:
  * Add "lookup" table functionality to permit userland entry lookups.
  * Bump table dump format preserving old ABI.
  
  Kernel size:
  * Add IP_FW_TABLE_XFIND to handle "lookup" request from userland.
  * Add ta_find_tentry() algorithm callbacks/handlers to support lookups.
  * Fully switch to ipfw_obj_tentry for various table dumps:
    algorithms are now required to support the latest (ipfw_obj_tentry) entry
      dump format, the rest is handled by generic dump code.
    IP_FW_TABLE_XLIST opcode version bumped (0 -> 1).
  * Eliminate legacy ta_dump_entry algo handler:
    dump_table_entry() converts data from current to legacy format.
  
  Userland side:
  * Add "lookup" table parameter.
  * Change the way table type is guessed: call table_get_info() first,
    and check value for IPv4/IPv6 type IFF table does not exist.
  * Fix table_get_list(): do more tries if supplied buffer is not enough.
  * Sparate table_show_entry() from table_show_list().

Modified:
  projects/ipfw/sbin/ipfw/tables.c
  projects/ipfw/sys/netinet/ip_fw.h
  projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c
  projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
  projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h
  projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c

Modified: projects/ipfw/sbin/ipfw/tables.c
==============================================================================
--- projects/ipfw/sbin/ipfw/tables.c	Sun Jul  6 17:57:59 2014	(r268328)
+++ projects/ipfw/sbin/ipfw/tables.c	Sun Jul  6 18:16:04 2014	(r268329)
@@ -55,6 +55,7 @@ static int table_flush(ipfw_obj_header *
 static int table_destroy(ipfw_obj_header *oh);
 static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i);
 static void table_create(ipfw_obj_header *oh, int ac, char *av[]);
+static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]);
 static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i);
 static int table_show_info(ipfw_xtable_info *i, void *arg);
 static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set,
@@ -64,9 +65,10 @@ static int table_flush_one(ipfw_xtable_i
 static int table_show_one(ipfw_xtable_info *i, void *arg);
 static int table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh);
 static void table_show_list(ipfw_obj_header *oh, int need_header);
+static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent);
 
 static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
-    char *key, uint8_t *ptype, uint8_t *pvtype);
+    char *key, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi);
 static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
     char *arg, uint8_t type, uint8_t vtype);
 
@@ -99,6 +101,7 @@ static struct _s_x tablecmds[] = {
       { "flush",	TOK_FLUSH },
       { "info",		TOK_INFO },
       { "list",		TOK_LIST },
+      { "lookup",	TOK_LOOKUP },
       { NULL, 0 }
 };
 
@@ -147,7 +150,6 @@ ipfw_table_handler(int ac, char *av[])
 
 	if (table_check_name(tablename) == 0) {
 		table_fill_ntlv(&oh.ntlv, *av, set, 1);
-		//oh->set = set;
 		oh.idx = 1;
 	} else {
 		if (strcmp(tablename, "all") == 0)
@@ -220,6 +222,10 @@ ipfw_table_handler(int ac, char *av[])
 				err(EX_OSERR, "failed to request tables list");
 		}
 		break;
+	case TOK_LOOKUP:
+		ac--; av++;
+		table_lookup(&oh, ac, av);
+		break;
 	}
 }
 
@@ -238,9 +244,8 @@ static void
 table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i)
 {
 
-	oh->set = i->set;
 	oh->idx = 1;
-	table_fill_ntlv(&oh->ntlv, i->tablename, oh->set, 1);
+	table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
 }
 
 static struct _s_x tablenewcmds[] = {
@@ -284,7 +289,6 @@ table_create(ipfw_obj_header *oh, int ac
 			NEED1("table type required");
 			val = match_token(tabletypes, *av);
 			if (val != -1) {
-				printf("av %s type %d\n", *av, xi.type);
 				xi.type = val;
 				ac--; av++;
 				break;
@@ -429,12 +433,17 @@ static int
 table_show_one(ipfw_xtable_info *i, void *arg)
 {
 	ipfw_obj_header *oh;
+	int error;
 
 	if ((oh = calloc(1, i->size)) == NULL)
 		return (ENOMEM);
 
-	if (table_get_list(i, oh) == 0)
-		table_show_list(oh, 1);
+	if ((error = table_get_list(i, oh)) != 0) {
+		err(EX_OSERR, "Error requesting table %s list", i->tablename);
+		return (error);
+	}
+
+	table_show_list(oh, 1);
 
 	free(oh);
 	return (0);	
@@ -467,7 +476,7 @@ table_do_modify_record(int cmd, ipfw_obj
 	memcpy(oh + 1, tent, sizeof(*tent));
 	tent = (ipfw_obj_tentry *)(oh + 1);
 	if (update != 0)
-		tent->flags |= IPFW_TF_UPDATE;
+		tent->head.flags |= IPFW_TF_UPDATE;
 	tent->head.length = sizeof(ipfw_obj_tentry);
 
 	error = do_set3(cmd, &oh->opheader, sizeof(xbuf));
@@ -479,6 +488,7 @@ static void
 table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update)
 {
 	ipfw_obj_tentry tent;
+	ipfw_xtable_info xi;
 	uint8_t type, vtype;
 	int cmd;
 	char *texterr;
@@ -490,7 +500,7 @@ table_modify_record(ipfw_obj_header *oh,
 	tent.head.length = sizeof(tent);
 	tent.idx = 1;
 
-	tentry_fill_key(oh, &tent, *av, &type, &vtype);
+	tentry_fill_key(oh, &tent, *av, &type, &vtype, &xi);
 	oh->ntlv.type = type;
 	ac--; av++;
 
@@ -508,6 +518,67 @@ table_modify_record(ipfw_obj_header *oh,
 		err(EX_OSERR, "%s", texterr);
 }
 
+static int
+table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi,
+    ipfw_obj_tentry *xtent)
+{
+	char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
+	ipfw_obj_tentry *tent;
+	uint8_t type, vtype;
+	int error;
+	size_t sz;
+
+	memcpy(xbuf, oh, sizeof(*oh));
+	oh = (ipfw_obj_header *)xbuf;
+	tent = (ipfw_obj_tentry *)(oh + 1);
+
+	memset(tent, 0, sizeof(*tent));
+	tent->head.length = sizeof(*tent);
+	tent->idx = 1;
+
+	tentry_fill_key(oh, tent, key, &type, &vtype, xi);
+	oh->ntlv.type = type;
+
+	sz = sizeof(xbuf);
+	if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0)
+		return (error);
+
+	if (sz < sizeof(xbuf))
+		return (EINVAL);
+
+	*xtent = *tent;
+
+	return (0);
+}
+
+static void
+table_lookup(ipfw_obj_header *oh, int ac, char *av[])
+{
+	ipfw_obj_tentry xtent;
+	ipfw_xtable_info xi;
+	int error;
+
+	if (ac == 0)
+		errx(EX_USAGE, "address required");
+
+	error = table_do_lookup(oh, *av, &xi, &xtent);
+
+	switch (error) {
+	case 0:
+		break;
+	case ESRCH:
+		errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name);
+	case ENOENT:
+		errx(EX_UNAVAILABLE, "Entry %s not found", *av);
+	case ENOTSUP:
+		errx(EX_UNAVAILABLE, "Table %s algo does not support "
+		    "\"lookup\" method", oh->ntlv.name);
+	default:
+		err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)");
+	}
+
+	table_show_entry(&xi, &xtent);
+}
 
 static void
 tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type)
@@ -584,39 +655,43 @@ tentry_fill_key_type(char *arg, ipfw_obj
 
 static void
 tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
-    uint8_t *ptype, uint8_t *pvtype)
+    uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi)
 {
-	ipfw_xtable_info xi;
 	uint8_t type, vtype;
 	int error;
 
 	type = 0;
 	vtype = 0;
 
-	/*
-	 * Compability layer. Try to interpret data as CIDR first.
-	 */
-	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_CIDR;
-	} else {
+	error = table_get_info(oh, xi);
 
+	if (error == 0) {
+		/* Table found. */
+		type = xi->type;
+		vtype = xi->vtype;
+	} else {
+		if (error != ESRCH)
+			errx(EX_OSERR, "Error requesting table %s info",
+			    oh->ntlv.name);
 		/*
-		 * Non-CIDR of FQDN hostname. Ask kernel
-		 * about given table.
+		 * Table does not exist.
+		 * Compability layer: try to interpret data as CIDR
+		 * before failing.
 		 */
-		error = table_get_info(oh, &xi);
-		if (error == ESRCH)
-			errx(EX_USAGE, "Table %s does not exist, cannot intuit "
+		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_CIDR;
+			/*
+			 * XXX: Value type is forced to be u32.
+			 * This should be changed for MFC.
+			 */
+			vtype = IPFW_VTYPE_U32;
+		} else {
+			/* Inknown key */
+			errx(EX_USAGE, "Table %s does not exist, cannot guess "
 			    "key type", oh->ntlv.name);
-		else if (error != 0)
-			errx(EX_OSERR, "Error requesting table %s info",
-			    oh->ntlv.name);
-
-		/* Table found. */
-		type = xi.type;
-		vtype = xi.vtype;
+		}
 	}
 
 	tentry_fill_key_type(key, tent, type);
@@ -629,29 +704,9 @@ static void
 tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
     uint8_t type, uint8_t vtype)
 {
-	ipfw_xtable_info xi;
-	int error;
 	int code;
 	char *p;
 
-	if (vtype == 0) {
-		/* Format type is unknown, ask kernel */
-		error = table_get_info(oh, &xi);
-		if (error == ESRCH) {
-
-			/*
-			 * XXX: This one may break some scripts.
-			 * Change this behavior for MFC.
-			 */
-			errx(EX_USAGE, "Table %s does not exist. Unable to "
-			    "guess value format.",  oh->ntlv.name);
-		} else if (error != 0)
-			errx(EX_OSERR, "Error requesting table %s info",
-			    oh->ntlv.name);
-
-		vtype = xi.vtype;
-	}
-
 	switch (vtype) {
 	case IPFW_VTYPE_U32:
 		tent->value = strtoul(arg, &p, 0);
@@ -758,17 +813,22 @@ static int
 table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh)
 {
 	size_t sz;
-	int error;
+	int error, c;
 
-	table_fill_objheader(oh, i);
-	sz = i->size;
+	sz = 0;
+	for (c = 0; c < 3; c++) {
+		table_fill_objheader(oh, i);
+		if (sz < i->size)
+			sz = i->size;
 
-	oh->opheader.version = 1; /* Current version */
+		oh->opheader.version = 1; /* Current version */
+		error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz);
 
-	if ((error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz)) != 0)
-		return (errno);
+		if (error != ENOMEM)
+			return (errno);
+	}
 
-	return (0);
+	return (ENOMEM);
 }
 
 /*
@@ -777,56 +837,52 @@ table_get_list(ipfw_xtable_info *i, ipfw
 static void
 table_show_list(ipfw_obj_header *oh, int need_header)
 {
-	ipfw_table_xentry *xent;
-	uint32_t count, tval;
-	char tbuf[128];
-	struct in6_addr *addr6;
+	ipfw_obj_tentry *tent;
+	uint32_t count;
 	ipfw_xtable_info *i;
 
 	i = (ipfw_xtable_info *)(oh + 1);
-	xent = (ipfw_table_xentry *)(i + 1);
+	tent = (ipfw_obj_tentry *)(i + 1);
 
 	if (need_header)
 		printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
 
 	count = i->count;
 	while (count > 0) {
-		switch (i->type) {
-		case IPFW_TABLE_CIDR:
-			/* IPv4 or IPv6 prefixes */
-			tval = xent->value;
-			addr6 = &xent->k.addr6;
+		table_show_entry(i, tent);
+		tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length);
+		count--;
+	}
+}
 
+static void
+table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
+{
+	char tbuf[128];
+	uint32_t tval;
 
-			if ((xent->flags & IPFW_TCF_INET) != 0) {
-				/* IPv4 address */
-				inet_ntop(AF_INET, &addr6->s6_addr32[3], tbuf,
-				    sizeof(tbuf));
-			} else {
-				/* IPv6 address */
-				inet_ntop(AF_INET6, addr6, tbuf, sizeof(tbuf));
-			}
+	tval = tent->value;
 
-			if (co.do_value_as_ip) {
-				tval = htonl(tval);
-				printf("%s/%u %s\n", tbuf, xent->masklen,
-				    inet_ntoa(*(struct in_addr *)&tval));
-			} else
-				printf("%s/%u %u\n", tbuf, xent->masklen, tval);
-			break;
-		case IPFW_TABLE_INTERFACE:
-			/* Interface names */
-			tval = xent->value;
-			if (co.do_value_as_ip) {
-				tval = htonl(tval);
-				printf("%s %s\n", xent->k.iface,
-				    inet_ntoa(*(struct in_addr *)&tval));
-			} else
-				printf("%s %u\n", xent->k.iface, tval);
-		}
+	switch (i->type) {
+	case IPFW_TABLE_CIDR:
+		/* IPv4 or IPv6 prefixes */
+		inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
 
-		xent = (ipfw_table_xentry *)((caddr_t)xent + xent->len);
-		count--;
+		if (co.do_value_as_ip) {
+			tval = htonl(tval);
+			printf("%s/%u %s\n", tbuf, tent->masklen,
+			    inet_ntoa(*(struct in_addr *)&tval));
+		} else
+			printf("%s/%u %u\n", tbuf, tent->masklen, tval);
+		break;
+	case IPFW_TABLE_INTERFACE:
+		/* Interface names */
+		if (co.do_value_as_ip) {
+			tval = htonl(tval);
+			printf("%s %s\n", tent->k.iface,
+			    inet_ntoa(*(struct in_addr *)&tval));
+		} else
+			printf("%s %u\n", tent->k.iface, tval);
 	}
 }
 

Modified: projects/ipfw/sys/netinet/ip_fw.h
==============================================================================
--- projects/ipfw/sys/netinet/ip_fw.h	Sun Jul  6 17:57:59 2014	(r268328)
+++ projects/ipfw/sys/netinet/ip_fw.h	Sun Jul  6 18:16:04 2014	(r268329)
@@ -89,6 +89,7 @@ typedef struct _ip_fw3_opheader {
 //#define	IP_FW_TABLE_XMODIFY	96	/* modify existing table */
 #define	IP_FW_XGET		97	/* Retrieve configuration */
 #define	IP_FW_XADD		98	/* add entry */
+#define	IP_FW_TABLE_XFIND	99	/* finds an entry */
 
 /*
  * Usage guidelines:
@@ -713,10 +714,8 @@ typedef struct	_ipfw_obj_tentry {
 	uint8_t		subtype;	/* subtype (IPv4,IPv6)		*/
 	uint8_t		masklen;	/* mask length			*/
 	uint16_t	idx;		/* Table name index		*/
-	uint16_t	flags;		/* Entry flags			*/
-	uint16_t	spare0;
-	uint32_t	spare1;
 	uint32_t	value;		/* value			*/
+	uint64_t	spare;
 	union {
 		/* Longest field needs to be aligned by 8-byte boundary	*/
 		struct in_addr addr;	/* IPv4 address			*/
@@ -751,7 +750,7 @@ typedef struct _ipfw_xtable_info {
 #define	IPFW_OBJTYPE_TABLE	1
 typedef struct _ipfw_obj_header {
 	ip_fw3_opheader	opheader;	/* IP_FW3 opcode		*/
-	uint32_t	set;		/* Set we're operating		*/
+	uint32_t	spare;
 	uint16_t	idx;		/* object name index		*/
 	uint8_t		objtype;	/* object type			*/
 	uint8_t		objsubtype;	/* object subtype		*/

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c	Sun Jul  6 17:57:59 2014	(r268328)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c	Sun Jul  6 18:16:04 2014	(r268329)
@@ -1726,6 +1726,9 @@ ipfw_ctl(struct sockopt *sopt)
 	case IP_FW_TABLE_XDEL: /* IP_FW3 */
 		error = ipfw_modify_table(chain, op3, &sdata);
 		break;
+	case IP_FW_TABLE_XFIND: /* IP_FW3 */
+		error = ipfw_find_table_entry(chain, op3, &sdata);
+		break;
 
 	/*--- LEGACY API ---*/
 	case IP_FW_TABLE_ADD:

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c	Sun Jul  6 17:57:59 2014	(r268328)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c	Sun Jul  6 18:16:04 2014	(r268329)
@@ -105,6 +105,7 @@ static int export_tables(struct ip_fw_ch
     struct sockopt_data *sd);
 static void export_table_info(struct ip_fw_chain *ch, struct table_config *tc,
     ipfw_xtable_info *i);
+static int dump_table_tentry(void *e, void *arg);
 static int dump_table_xentry(void *e, void *arg);
 
 static int ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd);
@@ -406,19 +407,18 @@ ipfw_modify_table_v1(struct ip_fw_chain 
 	    tent->head.length + read > sd->valsize)
 		return (EINVAL);
 
+	/* Convert data into kernel request objects */
 	memset(&tei, 0, sizeof(tei));
 	tei.paddr = &tent->k;
 	tei.subtype = tent->subtype;
 	tei.masklen = tent->masklen;
-	if (tent->flags & IPFW_TF_UPDATE)
+	if (tent->head.flags & IPFW_TF_UPDATE)
 		tei.flags |= TEI_FLAGS_UPDATE;
 	tei.value = tent->value;
 
-	memset(&ti, 0, sizeof(ti));
-	ti.uidx = tent->idx;
+	objheader_to_ti(oh, &ti);
 	ti.type = oh->ntlv.type;
-	ti.tlvs = &oh->ntlv;
-	ti.tlen = oh->ntlv.head.length;
+	ti.uidx = tent->idx;
 
 	error = (oh->opheader.opcode == IP_FW_TABLE_XADD) ?
 	    add_table_entry(ch, &ti, &tei) :
@@ -427,6 +427,101 @@ ipfw_modify_table_v1(struct ip_fw_chain 
 	return (error);
 }
 
+/*
+ * Looks up an entry in given table.
+ * Data layout (v0)(current):
+ * Request: [ ipfw_obj_header ipfw_obj_tentry ]
+ * Reply: [ ipfw_obj_header ipfw_obj_tentry ]
+ *
+ * Returns 0 on success
+ */
+int
+ipfw_find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+    struct sockopt_data *sd)
+{
+	ipfw_obj_tentry *tent;
+	ipfw_obj_header *oh;
+	struct tid_info ti;
+	struct table_config *tc;
+	struct table_algo *ta;
+	struct table_info *kti;
+	struct namedobj_instance *ni;
+	int error, plen;
+	void *paddr;
+	size_t sz;
+
+	/* Check minimum header size */
+	sz = sizeof(*oh) + sizeof(*tent);
+	if (sd->valsize != sz)
+		return (EINVAL);
+
+	oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
+	tent = (ipfw_obj_tentry *)(oh + 1);
+
+	/* Basic length checks for TLVs */
+	if (oh->ntlv.head.length != sizeof(oh->ntlv))
+		return (EINVAL);
+
+	objheader_to_ti(oh, &ti);
+	ti.type = oh->ntlv.type;
+	ti.uidx = tent->idx;
+
+	IPFW_UH_RLOCK(ch);
+	ni = CHAIN_TO_NI(ch);
+
+	/*
+	 * Find existing table and check its type .
+	 */
+	ta = NULL;
+	if ((tc = find_table(ni, &ti)) == NULL) {
+		IPFW_UH_RUNLOCK(ch);
+		return (ESRCH);
+	}
+
+	/* check table type */
+	if (tc->no.type != ti.type) {
+		IPFW_UH_RUNLOCK(ch);
+		return (EINVAL);
+	}
+
+	/* Check lookup key for validness */
+	plen = 0;
+	paddr = &tent->k;
+	switch (ti.type)
+	{
+	case IPFW_TABLE_CIDR:
+		if (tent->subtype == AF_INET)
+			plen = sizeof(struct in_addr);
+		else if (tent->subtype == AF_INET6)
+			plen = sizeof(struct in6_addr);
+		else {
+			IPFW_UH_RUNLOCK(ch);
+			return (EINVAL);
+		}
+		break;
+	case IPFW_TABLE_INTERFACE:
+		/* Check key first */
+		plen = sizeof(tent->k.iface);
+		if (strnlen(tent->k.iface, plen) == plen) {
+			IPFW_UH_RUNLOCK(ch);
+			return (EINVAL);
+		}
+
+		break;
+	default:
+		IPFW_UH_RUNLOCK(ch);
+		return (ENOTSUP);
+	}
+	kti = KIDX_TO_TI(ch, tc->no.kidx);
+	ta = tc->ta;
+
+	error = ta->find_tentry(tc->astate, kti, paddr, plen, tent);
+
+	IPFW_UH_RUNLOCK(ch);
+
+	return (error);
+}
+
 int
 ipfw_flush_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
     struct sockopt_data *sd)
@@ -807,8 +902,10 @@ struct dump_args {
 	struct sockopt_data *sd;
 	uint32_t cnt;
 	uint16_t uidx;
+	int error;
 	ipfw_table_entry *ent;
 	uint32_t size;
+	ipfw_obj_tentry tent;
 };
 
 int
@@ -835,7 +932,7 @@ ipfw_dump_table(struct ip_fw_chain *ch, 
  * Dumps all table data
  * Data layout (v1)(current):
  * Request: [ ipfw_obj_header ], size = ipfw_xtable_info.size
- * Reply: [ ipfw_obj_header ipfw_xtable_info ipfw_table_xentry x N ]
+ * Reply: [ ipfw_obj_header ipfw_xtable_info ipfw_obj_tentry x N ]
  *
  * Returns 0 on success
  */
@@ -866,7 +963,7 @@ ipfw_dump_table_v1(struct ip_fw_chain *c
 	export_table_info(ch, tc, i);
 	sz = tc->count;
 
-	if (sd->valsize < sz + tc->count * sizeof(ipfw_table_xentry)) {
+	if (sd->valsize < sz + tc->count * sizeof(ipfw_obj_tentry)) {
 
 		/*
 		 * Submitted buffer size is not enough.
@@ -888,10 +985,10 @@ ipfw_dump_table_v1(struct ip_fw_chain *c
 
 	ta = tc->ta;
 
-	ta->foreach(tc->astate, da.ti, dump_table_xentry, &da);
+	ta->foreach(tc->astate, da.ti, dump_table_tentry, &da);
 	IPFW_UH_RUNLOCK(ch);
 
-	return (0);
+	return (da.error);
 }
 
 /*
@@ -1045,7 +1142,7 @@ objheader_to_ti(struct _ipfw_obj_header 
 {
 
 	memset(ti, 0, sizeof(struct tid_info));
-	ti->set = oh->set;
+	ti->set = oh->ntlv.set;
 	ti->uidx = oh->idx;
 	ti->tlvs = &oh->ntlv;
 	ti->tlen = oh->ntlv.head.length;
@@ -1088,7 +1185,7 @@ export_table_info(struct ip_fw_chain *ch
 	i->kidx = tc->no.kidx;
 	i->refcnt = tc->no.refcnt;
 	i->count = tc->count;
-	i->size = tc->count * sizeof(ipfw_table_xentry);
+	i->size = tc->count * sizeof(ipfw_obj_tentry);
 	i->size += sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info);
 	strlcpy(i->tablename, tc->tablename, sizeof(i->tablename));
 	if (tc->ta->print_config != NULL) {
@@ -1155,6 +1252,9 @@ export_tables(struct ip_fw_chain *ch, ip
 	return (0);
 }
 
+/*
+ * Legacy IP_FW_TABLE_GETSIZE handler
+ */
 int
 ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt)
 {
@@ -1167,6 +1267,9 @@ ipfw_count_table(struct ip_fw_chain *ch,
 }
 
 
+/*
+ * Legacy IP_FW_TABLE_XGETSIZE handler
+ */
 int
 ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt)
 {
@@ -1189,6 +1292,7 @@ dump_table_entry(void *e, void *arg)
 	struct table_config *tc;
 	struct table_algo *ta;
 	ipfw_table_entry *ent;
+	int error;
 
 	da = (struct dump_args *)arg;
 
@@ -1202,7 +1306,15 @@ dump_table_entry(void *e, void *arg)
 	ent->tbl = da->uidx;
 	da->cnt++;
 
-	return (ta->dump_entry(tc->astate, da->ti, e, ent));
+	error = ta->dump_tentry(tc->astate, da->ti, e, &da->tent);
+	if (error != 0)
+		return (error);
+
+	ent->addr = da->tent.k.addr.s_addr;
+	ent->masklen = da->tent.masklen;
+	ent->value = da->tent.value;
+
+	return (0);
 }
 
 /*
@@ -1223,8 +1335,9 @@ ipfw_dump_table_legacy(struct ip_fw_chai
 
 	ta = tc->ta;
 
-	if (ta->dump_entry == NULL)
-		return (0);	/* Legacy dump support is not necessary */
+	/* This dump format supports IPv4 only */
+	if (tc->no.type != IPFW_TABLE_CIDR)
+		return (0);
 
 	memset(&da, 0, sizeof(da));
 	da.ti = KIDX_TO_TI(ch, tc->no.kidx);
@@ -1240,7 +1353,35 @@ ipfw_dump_table_legacy(struct ip_fw_chai
 }
 
 /*
- * Dumps table entry in eXtended format (current).
+ * Dumps table entry in eXtended format (v1)(current).
+ */
+static int
+dump_table_tentry(void *e, void *arg)
+{
+	struct dump_args *da;
+	struct table_config *tc;
+	struct table_algo *ta;
+	ipfw_obj_tentry *tent;
+
+	da = (struct dump_args *)arg;
+
+	tc = da->tc;
+	ta = tc->ta;
+
+	tent = (ipfw_obj_tentry *)ipfw_get_sopt_space(da->sd, sizeof(*tent));
+	/* Out of memory, returning */
+	if (tent == NULL) {
+		da->error = ENOMEM;
+		return (1);
+	}
+	tent->head.length = sizeof(ipfw_obj_tentry);
+	tent->idx = da->uidx;
+
+	return (ta->dump_tentry(tc->astate, da->ti, e, tent));
+}
+
+/*
+ * Dumps table entry in eXtended format (v0).
  */
 static int
 dump_table_xentry(void *e, void *arg)
@@ -1249,6 +1390,8 @@ dump_table_xentry(void *e, void *arg)
 	struct table_config *tc;
 	struct table_algo *ta;
 	ipfw_table_xentry *xent;
+	ipfw_obj_tentry *tent;
+	int error;
 
 	da = (struct dump_args *)arg;
 
@@ -1262,7 +1405,23 @@ dump_table_xentry(void *e, void *arg)
 	xent->len = sizeof(ipfw_table_xentry);
 	xent->tbl = da->uidx;
 
-	return (ta->dump_xentry(tc->astate, da->ti, e, xent));
+	memset(&da->tent, 0, sizeof(da->tent));
+	tent = &da->tent;
+	error = ta->dump_tentry(tc->astate, da->ti, e, tent);
+	if (error != 0)
+		return (error);
+
+	/* Convert current format to previous one */
+	xent->masklen = tent->masklen;
+	xent->value = tent->value;
+	/* Apply some hacks */
+	if (tc->no.type == IPFW_TABLE_CIDR && tent->subtype == AF_INET) {
+		xent->k.addr6.s6_addr32[3] = tent->k.addr.s_addr;
+		xent->flags = IPFW_TCF_INET;
+	} else
+		memcpy(&xent->k, &tent->k, sizeof(xent->k));
+
+	return (0);
 }
 
 /*

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h	Sun Jul  6 17:57:59 2014	(r268328)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h	Sun Jul  6 18:16:04 2014	(r268329)
@@ -77,10 +77,10 @@ typedef void (ta_print_config)(void *ta_
 typedef int ta_foreach_f(void *node, void *arg);
 typedef void ta_foreach(void *ta_state, struct table_info *ti, ta_foreach_f *f,
   void *arg);
-typedef int ta_dump_entry(void *ta_state, struct table_info *ti, void *e,
-    ipfw_table_entry *ent);
-typedef int ta_dump_xentry(void *ta_state, struct table_info *ti, void *e,
-    ipfw_table_xentry *xent);
+typedef int ta_dump_tentry(void *ta_state, struct table_info *ti, void *e,
+    ipfw_obj_tentry *tent);
+typedef int ta_find_tentry(void *ta_state, struct table_info *ti, void *key,
+    uint32_t keylen, ipfw_obj_tentry *tent);
 
 struct table_algo {
 	char		name[16];
@@ -94,9 +94,9 @@ struct table_algo {
 	ta_del		*del;
 	ta_flush_entry	*flush_entry;
 	ta_foreach	*foreach;
-	ta_dump_entry	*dump_entry;
-	ta_dump_xentry	*dump_xentry;
+	ta_dump_tentry	*dump_tentry;
 	ta_print_config	*print_config;
+	ta_find_tentry	*find_tentry;
 };
 void ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta);
 extern struct table_algo radix_cidr, radix_iface;
@@ -112,6 +112,8 @@ int ipfw_dump_table(struct ip_fw_chain *
     struct sockopt_data *sd);
 int ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt_data *sd);
 
+int ipfw_find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+    struct sockopt_data *sd);
 int ipfw_create_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
     struct sockopt_data *sd);
 int ipfw_modify_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c	Sun Jul  6 17:57:59 2014	(r268328)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c	Sun Jul  6 18:16:04 2014	(r268329)
@@ -208,30 +208,8 @@ ta_destroy_radix(void *ta_state, struct 
 }
 
 static int
-ta_dump_radix_entry(void *ta_state, struct table_info *ti, void *e,
-    ipfw_table_entry *ent)
-{
-	struct table_entry *n;
-
-	n = (struct table_entry *)e;
-
-	/* Guess IPv4/IPv6 radix by sockaddr family */
-	if (n->addr.sin_family != AF_INET)
-		return (0);
-
-	if (in_nullhost(n->mask.sin_addr))
-		ent->masklen = 0;
-	else
-		ent->masklen = 33 - ffs(ntohl(n->mask.sin_addr.s_addr));
-	ent->addr = n->addr.sin_addr.s_addr;
-	ent->value = n->value;
-
-	return (0);
-}
-
-static int
-ta_dump_radix_xentry(void *ta_state, struct table_info *ti, void *e,
-    ipfw_table_xentry *xent)
+ta_dump_radix_tentry(void *ta_state, struct table_info *ti, void *e,
+    ipfw_obj_tentry *tent)
 {
 	struct table_entry *n;
 	struct table_xentry *xn;
@@ -245,28 +223,59 @@ ta_dump_radix_xentry(void *ta_state, str
 	/* Guess IPv4/IPv6 radix by sockaddr family */
 	if (n->addr.sin_family == AF_INET) {
 		if (in_nullhost(n->mask.sin_addr))
-			xent->masklen = 0;
+			tent->masklen = 0;
 		else
-			xent->masklen = 33-ffs(ntohl(n->mask.sin_addr.s_addr));
+			tent->masklen = 33-ffs(ntohl(n->mask.sin_addr.s_addr));
 		/* Save IPv4 address as deprecated IPv6 compatible */
-		xent->k.addr6.s6_addr32[3] = n->addr.sin_addr.s_addr;
-		xent->flags = IPFW_TCF_INET;
-		xent->value = n->value;
+		tent->k.addr.s_addr = n->addr.sin_addr.s_addr;
+		tent->subtype = AF_INET;
+		tent->value = n->value;
 #ifdef INET6
 	} else {
 		xn = (struct table_xentry *)e;
 		/* Count IPv6 mask */
 		v = (uint32_t *)&xn->m.mask6.sin6_addr;
 		for (i = 0; i < sizeof(struct in6_addr) / 4; i++, v++)
-			xent->masklen += bitcount32(*v);
-		memcpy(&xent->k, &xn->a.addr6.sin6_addr, sizeof(struct in6_addr));
-		xent->value = xn->value;
+			tent->masklen += bitcount32(*v);
+		memcpy(&tent->k, &xn->a.addr6.sin6_addr, sizeof(struct in6_addr));
+		tent->subtype = AF_INET6;
+		tent->value = xn->value;
 #endif
 	}
 
 	return (0);
 }
 
+static int
+ta_find_radix_tentry(void *ta_state, struct table_info *ti, void *key,
+    uint32_t keylen, ipfw_obj_tentry *tent)
+{
+	struct radix_node_head *rnh;
+	void *e;
+
+	e = NULL;
+	if (keylen == sizeof(in_addr_t)) {
+		struct sockaddr_in sa;
+		KEY_LEN(sa) = KEY_LEN_INET;
+		sa.sin_addr.s_addr = *((in_addr_t *)key);
+		rnh = (struct radix_node_head *)ti->state;
+		e = rnh->rnh_matchaddr(&sa, rnh);
+	} else {
+		struct sockaddr_in6 sa6;
+		KEY_LEN(sa6) = KEY_LEN_INET6;
+		memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr));
+		rnh = (struct radix_node_head *)ti->xstate;
+		e = rnh->rnh_matchaddr(&sa6, rnh);
+	}
+
+	if (e != NULL) {
+		ta_dump_radix_tentry(ta_state, ti, e, tent);
+		return (0);
+	}
+
+	return (ENOENT);
+}
+
 static void
 ta_foreach_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f,
     void *arg)
@@ -495,7 +504,7 @@ ta_del_cidr(void *ta_state, struct table
 	tb->ent_ptr = rn;
 	
 	if (rn == NULL)
-		return (ESRCH);
+		return (ENOENT);
 
 	return (0);
 }
@@ -522,8 +531,8 @@ struct table_algo radix_cidr = {
 	.del		= ta_del_cidr,
 	.flush_entry	= ta_flush_cidr_entry,
 	.foreach	= ta_foreach_radix,
-	.dump_entry	= ta_dump_radix_entry,
-	.dump_xentry	= ta_dump_radix_xentry,
+	.dump_tentry	= ta_dump_radix_tentry,
+	.find_tentry	= ta_find_radix_tentry,
 };
 
 
@@ -724,7 +733,7 @@ ta_del_iface(void *ta_state, struct tabl
 	tb->ent_ptr = rn;
 	
 	if (rn == NULL)
-		return (ESRCH);
+		return (ENOENT);
 
 	return (0);
 }
@@ -741,19 +750,42 @@ ta_flush_iface_entry(struct tentry_info 
 }
 
 static int
-ta_dump_iface_xentry(void *ta_state, struct table_info *ti, void *e,
-    ipfw_table_xentry *xent)
+ta_dump_iface_tentry(void *ta_state, struct table_info *ti, void *e,
+    ipfw_obj_tentry *tent)
 {
 	struct table_xentry *xn;
 
 	xn = (struct table_xentry *)e;
-	xent->masklen = 8 * IF_NAMESIZE;
-	memcpy(&xent->k, &xn->a.iface.ifname, IF_NAMESIZE);
-	xent->value = xn->value;
+	tent->masklen = 8 * IF_NAMESIZE;
+	memcpy(&tent->k, &xn->a.iface.ifname, IF_NAMESIZE);
+	tent->value = xn->value;
 
 	return (0);
 }
 
+static int
+ta_find_iface_tentry(void *ta_state, struct table_info *ti, void *key,
+    uint32_t keylen, ipfw_obj_tentry *tent)
+{
+	struct radix_node_head *rnh;
+	struct xaddr_iface iface;
+	void *e;
+	e = NULL;
+
+	KEY_LEN(iface) = KEY_LEN_IFACE +
+	    strlcpy(iface.ifname, (char *)key, IF_NAMESIZE) + 1;
+
+	rnh = (struct radix_node_head *)ti->xstate;
+	e = rnh->rnh_matchaddr(&iface, rnh);
+
+	if (e != NULL) {
+		ta_dump_iface_tentry(ta_state, ti, e, tent);
+		return (0);
+	}
+
+	return (ENOENT);
+}
+
 static void
 ta_foreach_iface(void *ta_state, struct table_info *ti, ta_foreach_f *f,
     void *arg)
@@ -775,7 +807,8 @@ struct table_algo radix_iface = {
 	.del		= ta_del_iface,
 	.flush_entry	= ta_flush_iface_entry,
 	.foreach		= ta_foreach_iface,
-	.dump_xentry	= ta_dump_iface_xentry,
+	.dump_tentry	= ta_dump_iface_tentry,
+	.find_tentry	= ta_find_iface_tentry,
 };
 
 void



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