svn commit: r267509 - in projects/ipfw: sbin/ipfw sys/netinet sys/netpfil/ipfw

Alexander V. Chernikov melifaro at FreeBSD.org
Sun Jun 15 13:40:29 UTC 2014


Author: melifaro
Date: Sun Jun 15 13:40:27 2014
New Revision: 267509
URL: http://svnweb.freebsd.org/changeset/base/267509

Log:
  Simplify opcode handling.
  
  * Use one u16 from op3 header to implement opcode versioning.
  * IP_FW_TABLE_XLIST has now 2 handlers, for ver.0 (old) and ver.1 (current).
  * Every getsockopt request is now handled in ip_fw_table.c
  * Rename new opcodes:
  IP_FW_OBJ_DEL -> IP_FW_TABLE_XDESTROY
  IP_FW_OBJ_LISTSIZE -> IP_FW_TABLES_XGETSIZE
  IP_FW_OBJ_LIST -> IP_FW_TABLES_XLIST
  IP_FW_OBJ_INFO -> IP_FW_TABLE_XINFO
  IP_FW_OBJ_INFO -> IP_FW_TABLE_XFLUSH
  
  * Add some docs about using given opcodes.
  * Group some legacy opcode/handlers.

Modified:
  projects/ipfw/sbin/ipfw/tables.c
  projects/ipfw/sys/netinet/ip_fw.h
  projects/ipfw/sys/netpfil/ipfw/ip_fw_private.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

Modified: projects/ipfw/sbin/ipfw/tables.c
==============================================================================
--- projects/ipfw/sbin/ipfw/tables.c	Sun Jun 15 12:21:06 2014	(r267508)
+++ projects/ipfw/sbin/ipfw/tables.c	Sun Jun 15 13:40:27 2014	(r267509)
@@ -317,7 +317,6 @@ table_fill_objheader(ipfw_obj_header *oh
 
 	oh->set = i->set;
 	oh->idx = 1;
-	oh->objtype = IPFW_OBJTYPE_TABLE;
 	table_fill_ntlv(&oh->ntlv, i->tablename, 1);
 }
 
@@ -332,9 +331,8 @@ table_destroy(char *name, uint32_t set)
 
 	memset(&oh, 0, sizeof(oh));
 	oh.idx = 1;
-	oh.objtype = IPFW_OBJTYPE_TABLE;
 	table_fill_ntlv(&oh.ntlv, name, 1);
-	if (do_set3(IP_FW_OBJ_DEL, &oh.opheader, sizeof(oh)) != 0)
+	if (do_set3(IP_FW_TABLE_XDESTROY, &oh.opheader, sizeof(oh)) != 0)
 		return (-1);
 
 	return (0);
@@ -351,9 +349,8 @@ table_flush(char *name, uint32_t set)
 
 	memset(&oh, 0, sizeof(oh));
 	oh.idx = 1;
-	oh.objtype = IPFW_OBJTYPE_TABLE;
 	table_fill_ntlv(&oh.ntlv, name, 1);
-	if (do_set3(IP_FW_OBJ_FLUSH, &oh.opheader, sizeof(oh)) != 0)
+	if (do_set3(IP_FW_TABLE_XFLUSH, &oh.opheader, sizeof(oh)) != 0)
 		return (-1);
 
 	return (0);
@@ -380,7 +377,7 @@ table_get_info(char *name, uint32_t set,
 
 	table_fill_objheader(oh, i);
 
-	if (do_get3(IP_FW_OBJ_INFO, &oh->opheader, &sz) < 0)
+	if (do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz) < 0)
 		return (-1);
 
 	if (sz < sizeof(tbuf))
@@ -486,17 +483,15 @@ tables_foreach(table_cb_t *f, void *arg,
 	memset(&req, 0, sizeof(req));
 	sz = sizeof(req);
 
-	req.objtype = IPFW_OBJTYPE_TABLE;
-	if ((error = do_get3(IP_FW_OBJ_LISTSIZE, &req.opheader, &sz)) != 0)
+	if ((error = do_get3(IP_FW_TABLES_XGETSIZE, &req.opheader, &sz)) != 0)
 		return (errno);
 
 	sz = req.size;
 	if ((olh = calloc(1, sz)) == NULL)
 		return (ENOMEM);
 
-	olh->objtype = IPFW_OBJTYPE_TABLE;
 	olh->size = sz;
-	if ((error = do_get3(IP_FW_OBJ_LIST, &olh->opheader, &sz)) != 0) {
+	if ((error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz)) != 0) {
 		free(olh);
 		return (errno);
 	}
@@ -517,7 +512,8 @@ tables_foreach(table_cb_t *f, void *arg,
 
 /*
  * Retrieves all entries for given table @i in
- * eXtended format, returning  pointer vi @ooh.
+ * eXtended format. Assumes buffer of size
+ * @i->size has already been allocated by caller.
  *
  * Returns 0 on success.
  */
@@ -530,7 +526,9 @@ table_get_list(ipfw_xtable_info *i, ipfw
 	table_fill_objheader(oh, i);
 	sz = i->size;
 
-	if ((error = do_get3(IP_FW_OBJ_DUMP, &oh->opheader, &sz)) != 0)
+	oh->opheader.version = 1; /* Current version */
+
+	if ((error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz)) != 0)
 		return (errno);
 
 	return (0);

Modified: projects/ipfw/sys/netinet/ip_fw.h
==============================================================================
--- projects/ipfw/sys/netinet/ip_fw.h	Sun Jun 15 12:21:06 2014	(r267508)
+++ projects/ipfw/sys/netinet/ip_fw.h	Sun Jun 15 13:40:27 2014	(r267509)
@@ -70,21 +70,47 @@
 /* IP_FW3 header/opcodes */
 typedef struct _ip_fw3_opheader {
 	uint16_t opcode;	/* Operation opcode */
-	uint16_t reserved[3];	/* Align to 64-bit boundary */
+	uint16_t version;	/* Opcode version */
+	uint16_t reserved[2];	/* Align to 64-bit boundary */
 } ip_fw3_opheader;
 
 
 /* IPFW extented tables support */
 #define	IP_FW_TABLE_XADD	86	/* add entry */
 #define	IP_FW_TABLE_XDEL	87	/* delete entry */
-#define	IP_FW_TABLE_XGETSIZE	88	/* get table size */
+#define	IP_FW_TABLE_XGETSIZE	88	/* get table size (deprecated) */
 #define	IP_FW_TABLE_XLIST	89	/* list table contents */
-#define	IP_FW_OBJ_DEL		90	/* del table/pipe/etc */
-#define	IP_FW_OBJ_LISTSIZE	91	/* get size for table/etc list */
-#define	IP_FW_OBJ_LIST		92	/* list all objects of given type */
-#define	IP_FW_OBJ_INFO		93	/* request info for one object */
-#define	IP_FW_OBJ_FLUSH		94	/* flush data for given object */
-#define	IP_FW_OBJ_DUMP		95	/* dump all data for given object */
+#define	IP_FW_TABLE_XDESTROY	90	/* destroy table */
+#define	IP_FW_TABLES_XGETSIZE	91	/* get size for table/etc list */
+#define	IP_FW_TABLES_XLIST	92	/* list all objects of given type */
+#define	IP_FW_TABLE_XINFO	93	/* request info for one object */
+#define	IP_FW_TABLE_XFLUSH	94	/* flush data for given object */
+
+/*
+ * Usage guidelines:
+ *
+ * IP_FW_TABLE_XLIST(ver 1): Dumps all table data
+ *   Request(getsockopt): [ ipfw_obj_lheader ], size = ipfw_xtable_info.size
+ *   Reply: [ ipfw_obj_lheader ipfw_xtable_info ipfw_table_xentry x N ]
+ *
+ * IP_FW_TABLE_XDESTROY: Destroys given table
+ *   Request(setsockopt): [ ipfw_obj_header ]
+ *
+ * IP_FW_TABLES_XGETSIZE: Get buffer size needed to list info for all tables.
+ *   Request(getsockopt): [ empty ], size = sizeof(ipfw_obj_lheader)
+ *   Reply: [ ipfw_obj_lheader ]
+ *
+ * IP_FW_TABLES_XLIST: Lists all tables currently available in kernel.
+ *   Request(getsockopt): [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size
+ *   Reply: [ ipfw_obj_lheader ipfw_xtable_info x N ]
+ *
+ * IP_FW_TABLE_XINFO: Store table info to buffer.
+ *   Request(getsockopt): [ ipfw_obj_header ipfw_xtable_info(empty)]
+ *   Reply: [ ipfw_obj_header ipfw_xtable_info ]
+ *
+ * IP_FW_TABLE_XFLUSH: Removes all data from given table leaving type etc..
+ *   Request(setsockopt): [ ipfw_obj_header ]
+ */
 
 /*
  * The kernel representation of ipfw rules is made of a list of
@@ -679,10 +705,6 @@ typedef struct _ipfw_xtable_info {
 } ipfw_xtable_info;
 
 #define	IPFW_OBJTYPE_TABLE	1
-/*
- * IP_FW_OBJ_DEL, IP_FW_OBJ_INFO (followed by ipfw_xtable_info),
- * IP_FW_OBJ_DUMP (followed by ipfw_xtable_info and ipfw_table_xentry'xN )
- */
 typedef struct _ipfw_obj_header {
 	ip_fw3_opheader	opheader;	/* IP_FW3 opcode		*/
 	uint32_t	set;		/* Set we're operating		*/
@@ -692,12 +714,9 @@ typedef struct _ipfw_obj_header {
 	ipfw_obj_ntlv	ntlv;		/* object name tlv		*/
 } ipfw_obj_header;
 
-/* IP_FW_OBJ_LISTSIZE, IP_FW_OBJ_LIST (followd by ipfw_xtable_info) */
 typedef struct _ipfw_obj_lheader {
 	ip_fw3_opheader	opheader;	/* IP_FW3 opcode		*/
-	uint8_t		objtype;	/* object type			*/
-	uint8_t		spare0;
-	uint16_t	spare1;
+	uint32_t	spare;
 	uint32_t	count;		/* Total objects count		*/
 	uint32_t	size;		/* Total objects size		*/
 	uint32_t	objsize;	/* Size of one object		*/

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h	Sun Jun 15 12:21:06 2014	(r267508)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h	Sun Jun 15 13:40:27 2014	(r267509)
@@ -327,15 +327,6 @@ struct rule_check_info {
 	struct obj_idx	obuf[8];	/* table references storage */
 };
 
-struct tentry_info {
-	void		*paddr;
-	int		plen;		/* Total entry length		*/
-	uint8_t		masklen;	/* mask length			*/
-	uint8_t		spare;
-	uint16_t	flags;		/* record flags			*/
-	uint32_t	value;		/* value			*/
-};
-
 /* In ip_fw_sockopt.c */
 int ipfw_find_rule(struct ip_fw_chain *chain, uint32_t key, uint32_t id);
 int ipfw_ctl(struct sockopt *sopt);

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c	Sun Jun 15 12:21:06 2014	(r267508)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c	Sun Jun 15 13:40:27 2014	(r267509)
@@ -1171,10 +1171,9 @@ ipfw_ctl(struct sockopt *sopt)
 			sopt->sopt_name == IP_FW_RESETLOG);
 		break;
 
-	/*--- TABLE manipulations are protected by the IPFW_LOCK ---*/
-	case IP_FW_OBJ_DEL: /* IP_FW3 */
-	case IP_FW_OBJ_INFO: /* IP_FW3 */
-	case IP_FW_OBJ_FLUSH: /* IP_FW3 */
+	/*--- TABLE opcodes ---*/
+	case IP_FW_TABLE_XDESTROY: /* IP_FW3 */
+	case IP_FW_TABLE_XFLUSH: /* IP_FW3 */
 		{
 			struct _ipfw_obj_header *oh;
 			struct tid_info ti;
@@ -1186,64 +1185,31 @@ ipfw_ctl(struct sockopt *sopt)
 
 			oh = (struct _ipfw_obj_header *)op3;
 
-			switch (oh->objtype) {
-			case IPFW_OBJTYPE_TABLE:
-				memset(&ti, 0, sizeof(ti));
-				ti.set = oh->set;
-				ti.uidx = oh->idx;
-				ti.tlvs = &oh->ntlv;
-				ti.tlen = oh->ntlv.head.length;
-				if (opt == IP_FW_OBJ_DEL)
-					error = ipfw_destroy_table(chain, &ti);
-				else if (opt == IP_FW_OBJ_FLUSH)
-					error = ipfw_flush_table(chain, &ti);
-				else {
-					/* IP_FW_OBJ_INFO */
-					if (sopt->sopt_valsize < sizeof(*oh) +
-					    sizeof(ipfw_xtable_info)) {
-						error = EINVAL;
-						break;
-					}
-
-					error = ipfw_describe_table(chain, &ti,
-					    (ipfw_xtable_info *)(oh + 1));
-					if (error == 0)
-						error = sooptcopyout(sopt, oh,
-						    sopt->sopt_valsize);
-				}
-				break;
-			default:
+			objheader_to_ti(oh, &ti);
+
+			if (opt == IP_FW_TABLE_XDESTROY)
+				error = ipfw_destroy_table(chain, &ti);
+			else if (opt == IP_FW_TABLE_XFLUSH)
+				error = ipfw_flush_table(chain, &ti);
+			else
 				error = ENOTSUP;
-				break;
-			}
 			break;
 		}
-	case IP_FW_TABLE_ADD:
-	case IP_FW_TABLE_DEL:
-		{
-			ipfw_table_entry ent;
-			struct tentry_info tei;
-			struct tid_info ti;
 
-			error = sooptcopyin(sopt, &ent,
-			    sizeof(ent), sizeof(ent));
-			if (error)
-				break;
+	case IP_FW_TABLE_XINFO: /* IP_FW3 */
+		error = ipfw_describe_table(chain, sopt, op3, valsize);
+		break;
 
-			memset(&tei, 0, sizeof(tei));
-			tei.paddr = &ent.addr;
-			tei.plen = sizeof(ent.addr);
-			tei.masklen = ent.masklen;
-			tei.value = ent.value;
-			memset(&ti, 0, sizeof(ti));
-			ti.set = RESVD_SET;
-			ti.uidx = ent.tbl;
-			ti.type = IPFW_TABLE_CIDR;
+	case IP_FW_TABLES_XGETSIZE: /* IP_FW3 */
+		error = ipfw_listsize_tables(chain, sopt, op3, valsize);
+		break;
 
-			error = (opt == IP_FW_TABLE_ADD) ?
-			    ipfw_add_table_entry(chain, &ti, &tei) :
-			    ipfw_del_table_entry(chain, &ti, &tei);
-		}
+	case IP_FW_TABLES_XLIST: /* IP_FW3 */
+		error = ipfw_list_tables(chain, sopt, op3, valsize);
+		break;
+
+	case IP_FW_TABLE_XLIST: /* IP_FW3 */
+		error = ipfw_dump_table(chain, sopt, op3, valsize);
 		break;
 
 	case IP_FW_TABLE_XADD: /* IP_FW3 */
@@ -1283,6 +1249,36 @@ ipfw_ctl(struct sockopt *sopt)
 		}
 		break;
 
+	/*--- LEGACY API ---*/
+	case IP_FW_TABLE_ADD:
+	case IP_FW_TABLE_DEL:
+		{
+			ipfw_table_entry ent;
+			struct tentry_info tei;
+			struct tid_info ti;
+
+			error = sooptcopyin(sopt, &ent,
+			    sizeof(ent), sizeof(ent));
+			if (error)
+				break;
+
+			memset(&tei, 0, sizeof(tei));
+			tei.paddr = &ent.addr;
+			tei.plen = sizeof(ent.addr);
+			tei.masklen = ent.masklen;
+			tei.value = ent.value;
+			memset(&ti, 0, sizeof(ti));
+			ti.set = RESVD_SET;
+			ti.uidx = ent.tbl;
+			ti.type = IPFW_TABLE_CIDR;
+
+			error = (opt == IP_FW_TABLE_ADD) ?
+			    ipfw_add_table_entry(chain, &ti, &tei) :
+			    ipfw_del_table_entry(chain, &ti, &tei);
+		}
+		break;
+
+
 	case IP_FW_TABLE_FLUSH:
 		{
 			u_int16_t tbl;
@@ -1375,110 +1371,6 @@ ipfw_ctl(struct sockopt *sopt)
 			error = sooptcopyout(sopt, op3, sopt->sopt_valsize);
 		}
 		break;
-
-	case IP_FW_TABLE_XLIST: /* IP_FW3 */
-		{
-			ipfw_xtable *tbl;
-			struct tid_info ti;
-
-			if ((size = valsize) < sizeof(ipfw_xtable)) {
-				error = EINVAL;
-				break;
-			}
-
-			tbl = malloc(size, M_TEMP, M_ZERO | M_WAITOK);
-			memcpy(tbl, op3, sizeof(ipfw_xtable));
-
-			/* Get maximum number of entries we can store */
-			tbl->size = (size - sizeof(ipfw_xtable)) /
-			    sizeof(ipfw_table_xentry);
-			memset(&ti, 0, sizeof(ti));
-			ti.set = 0; /* XXX: No way to specify set */
-			ti.uidx = tbl->tbl;
-			IPFW_UH_RLOCK(chain);
-			error = ipfw_dump_xtable(chain, &ti, tbl);
-			IPFW_UH_RUNLOCK(chain);
-			if (error) {
-				free(tbl, M_TEMP);
-				break;
-			}
-
-			/* Revert size field back to bytes */
-			tbl->size = tbl->size * sizeof(ipfw_table_xentry) +
-				sizeof(ipfw_table);
-			/* 
-			 * Since we call sooptcopyin() with small buffer, sopt_valsize is
-			 * decreased to reflect supplied buffer size. Set it back to original value
-			 */
-			sopt->sopt_valsize = valsize;
-			error = sooptcopyout(sopt, tbl, size);
-			free(tbl, M_TEMP);
-		}
-		break;
-	case IP_FW_OBJ_LISTSIZE: /* IP_FW3 */
-		{
-			struct _ipfw_obj_lheader *olh;
-
-			if (sopt->sopt_valsize < sizeof(*olh)) {
-				error = EINVAL;
-				break;
-			}
-
-			olh = (struct _ipfw_obj_lheader *)op3;
-
-			switch (olh->objtype) {
-			case IPFW_OBJTYPE_TABLE:
-				error = ipfw_listsize_tables(chain, sopt, op3,
-				    valsize);
-				break;
-			default:
-				error = ENOTSUP;
-				break;
-			}
-			break;
-		}
-	case IP_FW_OBJ_LIST: /* IP_FW3 */
-		{
-			struct _ipfw_obj_lheader *olh;
-
-			if (sopt->sopt_valsize < sizeof(*olh)) {
-				error = EINVAL;
-				break;
-			}
-
-			olh = (struct _ipfw_obj_lheader *)op3;
-			switch (olh->objtype) {
-			case IPFW_OBJTYPE_TABLE:
-				error = ipfw_list_tables(chain, sopt, op3,
-				    valsize);
-				break;
-			default:
-				error = ENOTSUP;
-				break;
-			}
-			break;
-		}
-	case IP_FW_OBJ_DUMP: /* IP_FW3 */
-		{
-			struct _ipfw_obj_header *oh;
-
-			if (sopt->sopt_valsize < sizeof(*oh)) {
-				error = EINVAL;
-				break;
-			}
-
-			oh = (struct _ipfw_obj_header *)op3;
-			switch (oh->objtype) {
-			case IPFW_OBJTYPE_TABLE:
-				error = ipfw_dump_table(chain, sopt, op3,
-				    valsize);
-				break;
-			default:
-				error = ENOTSUP;
-				break;
-			}
-			break;
-		}
 	/*--- NAT operations are protected by the IPFW_LOCK ---*/
 	case IP_FW_NAT_CFG:
 		if (IPFW_NAT_LOADED)

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c	Sun Jun 15 12:21:06 2014	(r267508)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c	Sun Jun 15 13:40:27 2014	(r267509)
@@ -105,6 +105,14 @@ static int export_tables(struct ip_fw_ch
 static void export_table_info(struct table_config *tc, ipfw_xtable_info *i);
 static int dump_table_xentry(void *e, void *arg);
 
+static int check_buffer(size_t items, size_t item_size, size_t header,
+    size_t bufsize);
+
+static int ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt *sopt,
+    ip_fw3_opheader *op3, size_t valsize);
+static int ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt *sopt,
+    ip_fw3_opheader *op3, size_t valsize);
+
 static struct table_algo *find_table_algo(struct tables_config *tableconf,
     struct tid_info *ti);
 
@@ -538,7 +546,16 @@ ipfw_lookup_table_extended(struct ip_fw_
  */
 
 /*
- * High-level handlers for setsockopt
+ * High-level 'get' cmds sysctl handlers
+ */
+
+/*
+ * Get buffer size needed to list info for all tables.
+ * Data layout:
+ * Request: [ empty ], size = sizeof(ipfw_obj_lheader)
+ * Reply: [ ipfw_obj_lheader ]
+ *
+ * Returns 0 on success
  */
 int
 ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt *sopt,
@@ -546,6 +563,9 @@ ipfw_listsize_tables(struct ip_fw_chain 
 {
 	struct _ipfw_obj_lheader *olh;
 
+	if (sopt->sopt_valsize < sizeof(*olh))
+		return (EINVAL);
+
 	olh = (struct _ipfw_obj_lheader *)op3;
 	
 	olh->size = sizeof(*olh); /* Make export_table store needed size */
@@ -558,15 +578,25 @@ ipfw_listsize_tables(struct ip_fw_chain 
 	return (sooptcopyout(sopt, olh, sopt->sopt_valsize));
 }
 
-
+/*
+ * Lists all tables currently available in kernel.
+ * Data layout:
+ * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size
+ * Reply: [ ipfw_obj_lheader ipfw_xtable_info x N ]
+ *
+ * Returns 0 on success
+ */
 int
 ipfw_list_tables(struct ip_fw_chain *ch, struct sockopt *sopt,
     ip_fw3_opheader *op3, size_t valsize)
 {
 	struct _ipfw_obj_lheader *olh;
-	uint32_t sz, sz_min, sz_max;
+	uint32_t sz;
 	int error;
 
+	if (sopt->sopt_valsize < sizeof(*olh))
+		return (EINVAL);
+
 	olh = (struct _ipfw_obj_lheader *)op3;
 
 	if (valsize != olh->size)
@@ -580,11 +610,9 @@ ipfw_list_tables(struct ip_fw_chain *ch,
 	IPFW_UH_RLOCK(ch);
 	sz = ipfw_objhash_count(CHAIN_TO_NI(ch));
 	IPFW_UH_RUNLOCK(ch);
-	
-	sz_min = sz * sizeof(ipfw_xtable_info) + sizeof(*olh);
-	sz_max = sz_min + (sz + 1) * sizeof(ipfw_xtable_info);
 
-	if (valsize < sz_min || valsize > sz_max)
+	if (check_buffer(sz, sizeof(ipfw_xtable_info),
+	    sizeof(*olh), valsize) != 0)
 		return (EINVAL);
 	
 	olh = malloc(valsize, M_TEMP, M_ZERO | M_WAITOK);
@@ -612,6 +640,46 @@ ipfw_list_tables(struct ip_fw_chain *ch,
 	return (0);
 }
 
+/*
+ * Store table info to buffer provided by @op3.
+ * Data layout:
+ * Request: [ ipfw_obj_header ipfw_xtable_info(empty)]
+ * Reply: [ ipfw_obj_header ipfw_xtable_info ]
+ *
+ * Returns 0 on success.
+ */
+int
+ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt *sopt,
+    ip_fw3_opheader *op3, size_t valsize)
+{
+	struct _ipfw_obj_header *oh;
+	struct table_config *tc;
+	struct tid_info ti;
+	size_t sz;
+	int error;
+
+	sz = sizeof(*oh) + sizeof(ipfw_xtable_info);
+	if (sopt->sopt_valsize < sz)
+		return (EINVAL);
+
+	oh = (struct _ipfw_obj_header *)op3;
+
+	objheader_to_ti(oh, &ti);
+
+	IPFW_UH_RLOCK(ch);
+	if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
+		IPFW_UH_RUNLOCK(ch);
+		return (ESRCH);
+	}
+
+	export_table_info(tc, (ipfw_xtable_info *)(oh + 1));
+	IPFW_UH_RUNLOCK(ch);
+
+	error = sooptcopyout(sopt, oh, sz);
+
+	return (error);
+}
+
 struct dump_args {
 	struct table_info *ti;
 	struct table_config *tc;
@@ -626,22 +694,49 @@ int
 ipfw_dump_table(struct ip_fw_chain *ch, struct sockopt *sopt,
     ip_fw3_opheader *op3, size_t valsize)
 {
+	int error;
+
+	switch (op3->version) {
+	case 0:
+		error = ipfw_dump_table_v0(ch, sopt, op3, valsize);
+		break;
+	case 1:
+		error = ipfw_dump_table_v1(ch, sopt, op3, valsize);
+		break;
+	default:
+		error = ENOTSUP;
+	}
+
+	return (error);
+}
+
+/*
+ * Dumps all table data
+ * Data layout (version 1):
+ * Request: [ ipfw_obj_lheader ], size = ipfw_xtable_info.size
+ * Reply: [ ipfw_obj_lheader ipfw_xtable_info ipfw_table_xentry x N ]
+ *
+ * Returns 0 on success
+ */
+static int
+ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt *sopt,
+    ip_fw3_opheader *op3, size_t valsize)
+{
 	struct _ipfw_obj_header *oh;
 	ipfw_xtable_info *i;
 	struct tid_info ti;
 	struct table_config *tc;
 	struct table_algo *ta;
 	struct dump_args da;
-	uint32_t sz, sz_min, sz_max;
+	uint32_t sz;
 	int error;
 
+	if (sopt->sopt_valsize < sizeof(*oh))
+		return (EINVAL);
+
 	oh = (struct _ipfw_obj_header *)op3;
 
-	memset(&ti, 0, sizeof(ti));
-	ti.set = oh->set;
-	ti.uidx = oh->idx;
-	ti.tlvs = &oh->ntlv;
-	ti.tlen = oh->ntlv.head.length;
+	objheader_to_ti(oh, &ti);
 
 	IPFW_UH_RLOCK(ch);
 	if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
@@ -651,20 +746,10 @@ ipfw_dump_table(struct ip_fw_chain *ch, 
 	sz = tc->count;
 	IPFW_UH_RUNLOCK(ch);
 
-	/*
-	 * Check if array size is "reasonable":
-	 * Permit valsize between current size and
-	 * 2x current size + 1
-	 */
-	
-	sz_min = sz * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable_info) +
-	    sizeof(*oh);
-
-	sz_max = sz_min + (sz + 1) * sizeof(ipfw_table_xentry);
-
-	if (valsize < sz_min || valsize > sz_max)
+	if (check_buffer(sz, sizeof(ipfw_table_xentry),
+	    sizeof(ipfw_xtable_info) + sizeof(*oh), valsize) != 0)
 		return (EINVAL);
-	
+
 	oh = malloc(valsize, M_TEMP, M_ZERO | M_WAITOK);
 	i = (ipfw_xtable_info *)(oh + 1);
 	/* Copy header to new storage */
@@ -689,6 +774,7 @@ ipfw_dump_table(struct ip_fw_chain *ch, 
 	/*
 	 * Do the actual dump in eXtended format
 	 */
+	memset(&da, 0, sizeof(da));
 	da.ti = KIDX_TO_TI(ch, tc->no.kidx);
 	da.tc = tc;
 	da.xent = (ipfw_table_xentry *)(i + 1);
@@ -712,6 +798,122 @@ ipfw_dump_table(struct ip_fw_chain *ch, 
 	return (0);
 }
 
+/*
+ * Dumps all table data
+ * Data layout (version 0):
+ * Request: [ ipfw_xtable ], size = IP_FW_TABLE_XGETSIZE()
+ * Reply: [ ipfw_xtable ipfw_table_xentry x N ]
+ *
+ * Returns 0 on success
+ */
+static int
+ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt *sopt,
+    ip_fw3_opheader *op3, size_t valsize)
+{
+	ipfw_xtable *xtbl;
+	struct tid_info ti;
+	struct table_config *tc;
+	struct table_algo *ta;
+	struct dump_args da;
+	int error;
+	size_t sz;
+
+	if (valsize < sizeof(ipfw_xtable))
+		return (EINVAL);
+
+	xtbl = (ipfw_xtable *)op3;
+
+	memset(&ti, 0, sizeof(ti));
+	ti.set = 0; /* XXX: No way to specify set */
+	ti.uidx = xtbl->tbl;
+	
+	IPFW_UH_RLOCK(ch);
+	if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
+		IPFW_UH_RUNLOCK(ch);
+		return (0);
+	}
+	sz = tc->count;
+	IPFW_UH_RUNLOCK(ch);
+
+	if (check_buffer(sz, sizeof(ipfw_table_xentry),
+	    sizeof(ipfw_xtable) - sizeof(ipfw_table_xentry), valsize) != 0)
+		return (EINVAL);
+
+	xtbl = malloc(valsize, M_TEMP, M_ZERO | M_WAITOK);
+	memcpy(xtbl, op3, sizeof(ipfw_xtable));
+
+	IPFW_UH_RLOCK(ch);
+	if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
+		IPFW_UH_RUNLOCK(ch);
+		free(xtbl, M_TEMP);
+		return (0);
+	}
+
+	/* Check size another time */
+	sz = tc->count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable);
+	if (sz > valsize) {
+		IPFW_UH_RUNLOCK(ch);
+		free(xtbl, M_TEMP);
+		return (EINVAL);
+	}
+
+	/* Do the actual dump in eXtended format */
+	memset(&da, 0, sizeof(da));
+	da.ti = KIDX_TO_TI(ch, tc->no.kidx);
+	da.tc = tc;
+	da.xent = &xtbl->xent[0];
+	da.size = tc->count;
+	xtbl->type = tc->no.type;
+	xtbl->tbl = ti.uidx;
+	ta = tc->ta;
+
+	ta->foreach(tc->astate, da.ti, dump_table_xentry, &da);
+	xtbl->cnt = da.cnt;
+	xtbl->size = sz;
+
+	IPFW_UH_RUNLOCK(ch);
+
+	/* 
+	 * Since we call sooptcopyin() with small buffer, sopt_valsize is
+	 * decreased to reflect supplied buffer size. Set it back to original value
+	 */
+	sopt->sopt_valsize = valsize;
+	error = sooptcopyout(sopt, xtbl, sz);
+	free(xtbl, M_TEMP);
+
+	return (error);
+}
+
+/*
+ * Checks if supplied buffer size is "reasonable".
+ * Permit valsize between current needed size and
+ * 2x  needed size + 1
+ */
+static int
+check_buffer(size_t items, size_t item_size, size_t header, size_t bufsize)
+{
+	size_t sz_min, sz_max;
+
+	sz_min = items * item_size + header;
+	sz_max = (2 * items + 1) * item_size + header;
+
+	if (bufsize < sz_min || bufsize > sz_max)
+		return (EINVAL);
+
+	return (0);	
+}
+
+void
+objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti)
+{
+
+	memset(ti, 0, sizeof(struct tid_info));
+	ti->set = oh->set;
+	ti->uidx = oh->idx;
+	ti->tlvs = &oh->ntlv;
+	ti->tlen = oh->ntlv.head.length;
+}
+
 static void
 export_table_info(struct table_config *tc, ipfw_xtable_info *i)
 {
@@ -728,34 +930,6 @@ export_table_info(struct table_config *t
 	strlcpy(i->tablename, tc->tablename, sizeof(i->tablename));
 }
 
-int
-ipfw_count_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh)
-{
-	uint32_t count;
-
-	count = ipfw_objhash_count(CHAIN_TO_NI(ch));
-
-	olh->count = count;
-	olh->size = count * sizeof(ipfw_xtable_info) + sizeof(ipfw_obj_lheader);
-	olh->objsize = sizeof(ipfw_xtable_info);
-
-	return (0);
-}
-
-int
-ipfw_describe_table(struct ip_fw_chain *ch, struct tid_info *ti,
-    ipfw_xtable_info *i)
-{
-	struct table_config *tc;
-
-	if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL)
-		return (ESRCH);
-
-	export_table_info(tc, i);
-
-	return (0);
-}
-
 static void
 export_table_internal(struct namedobj_instance *ni, struct named_object *no,
     void *arg)
@@ -818,8 +992,10 @@ ipfw_count_xtable(struct ip_fw_chain *ch
 {
 	struct table_config *tc;
 
-	if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL)
+	if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) {
+		*cnt = 0;
 		return (0); /* 'table all list' requires success */
+	}
 	*cnt = tc->count * sizeof(ipfw_table_xentry);
 	if (tc->count > 0)
 		*cnt += sizeof(ipfw_xtable);
@@ -870,10 +1046,10 @@ ipfw_dump_table_legacy(struct ip_fw_chai
 	if (ta->dump_entry == NULL)
 		return (0);	/* Legacy dump support is not necessary */
 
+	memset(&da, 0, sizeof(da));
 	da.ti = KIDX_TO_TI(ch, tc->no.kidx);
 	da.tc = tc;
 	da.ent = &tbl->ent[0];
-	da.cnt = 0;
 	da.size = tbl->size;
 
 	tbl->cnt = 0;
@@ -921,11 +1097,11 @@ ipfw_dump_xtable(struct ip_fw_chain *ch,
 	if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL)
 		return (0);	/* XXX: We should return ESRCH */
 
+	memset(&da, 0, sizeof(da));
 	da.ti = KIDX_TO_TI(ch, tc->no.kidx);
 	da.tc = tc;
 	da.xent = &xtbl->xent[0];
 	da.size = xtbl->size;
-	da.cnt = 0;
 	xtbl->type = tc->no.type;
 	xtbl->tbl = ti->uidx;
 	ta = tc->ta;

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h	Sun Jun 15 12:21:06 2014	(r267508)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h	Sun Jun 15 13:40:27 2014	(r267509)
@@ -41,6 +41,15 @@ struct table_info {
 	u_long		data;		/* Hints for given func */
 };
 
+struct tentry_info {
+	void		*paddr;
+	int		plen;		/* Total entry length		*/
+	uint8_t		masklen;	/* mask length			*/
+	uint8_t		spare;
+	uint16_t	flags;		/* record flags			*/
+	uint32_t	value;		/* value			*/
+};
+
 typedef int (ta_init)(void **ta_state, struct table_info *ti);
 typedef void (ta_destroy)(void *ta_state, struct table_info *ti);
 typedef int (ta_prepare_add)(struct tentry_info *tei, void *ta_buf);
@@ -77,6 +86,10 @@ struct table_algo {
 void ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta);
 extern struct table_algo radix_cidr, radix_iface;
 
+void ipfw_table_algo_init(struct ip_fw_chain *chain);
+void ipfw_table_algo_destroy(struct ip_fw_chain *chain);
+
+
 /* direct ipfw_ctl handlers */
 int ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt *sopt,
     ip_fw3_opheader *op3, size_t valsize);
@@ -84,6 +97,8 @@ int ipfw_list_tables(struct ip_fw_chain 
     ip_fw3_opheader *op3, size_t valsize);
 int ipfw_dump_table(struct ip_fw_chain *ch, struct sockopt *sopt,
     ip_fw3_opheader *op3, size_t valsize);
+int ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt *sopt,
+    ip_fw3_opheader *op3, size_t valsize);
 
 int ipfw_destroy_table(struct ip_fw_chain *ch, struct tid_info *ti);
 int ipfw_flush_table(struct ip_fw_chain *ch, struct tid_info *ti);
@@ -91,6 +106,16 @@ int ipfw_add_table_entry(struct ip_fw_ch
     struct tentry_info *tei);
 int ipfw_del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
     struct tentry_info *tei);
+int ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
+    struct rule_check_info *ci);
+int ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule);
+void ipfw_unbind_table_rule(struct ip_fw_chain *chain, struct ip_fw *rule);
+void ipfw_unbind_table_list(struct ip_fw_chain *chain, struct ip_fw *head);
+
+/* utility functions  */
+void objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti);
+
+/* Legacy interfaces */
 int ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti,
     uint32_t *cnt);
 int ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti,
@@ -99,17 +124,6 @@ int ipfw_dump_table_legacy(struct ip_fw_
     ipfw_table *tbl);
 int ipfw_dump_xtable(struct ip_fw_chain *ch, struct tid_info *ti,
     ipfw_xtable *tbl);
-int ipfw_describe_table(struct ip_fw_chain *ch, struct tid_info *ti,
-    ipfw_xtable_info *i);
-int ipfw_count_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh);
-int ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
-    struct rule_check_info *ci);
-int ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule);
-void ipfw_unbind_table_rule(struct ip_fw_chain *chain, struct ip_fw *rule);
-void ipfw_unbind_table_list(struct ip_fw_chain *chain, struct ip_fw *head);
-
-void ipfw_table_algo_init(struct ip_fw_chain *chain);
-void ipfw_table_algo_destroy(struct ip_fw_chain *chain);
 
 
 #endif /* _KERNEL */


More information about the svn-src-projects mailing list