Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 7 Sep 2014 18:30:29 +0000 (UTC)
From:      "Alexander V. Chernikov" <melifaro@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r271231 - in projects/ipfw: sbin/ipfw sys/netinet sys/netpfil/ipfw
Message-ID:  <201409071830.s87IUT4f031688@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: melifaro
Date: Sun Sep  7 18:30:29 2014
New Revision: 271231
URL: http://svnweb.freebsd.org/changeset/base/271231

Log:
  Make ipfw_nat module use IP_FW3 codes.
  
  Kernel changes:
  * Split kernel/userland nat structures eliminating IPFW_INTERNAL hack.
  * Add IP_FW_NAT44_* codes resemblin old ones.
  * Assume that instances can be named (no kernel support currently).
  * Use both UH+WLOCK locks for all configuration changes.
  * Provide full ABI support for old sockopts.
  
  Userland changes:
  * Use IP_FW_NAT44_* codes for nat operations.
  * Remove undocumented ability to show ranges of nat "log" entries.

Modified:
  projects/ipfw/sbin/ipfw/nat.c
  projects/ipfw/sys/netinet/ip_fw.h
  projects/ipfw/sys/netpfil/ipfw/ip_fw_nat.c

Modified: projects/ipfw/sbin/ipfw/nat.c
==============================================================================
--- projects/ipfw/sbin/ipfw/nat.c	Sun Sep  7 18:05:37 2014	(r271230)
+++ projects/ipfw/sbin/ipfw/nat.c	Sun Sep  7 18:30:29 2014	(r271231)
@@ -30,14 +30,13 @@
 
 #include <ctype.h>
 #include <err.h>
+#include <errno.h>
 #include <netdb.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sysexits.h>
 
-#define IPFW_INTERNAL	/* Access to protected structures in ip_fw.h. */
-
 #include <net/if.h>
 #include <net/if_dl.h>
 #include <net/route.h> /* def. of struct route */
@@ -46,6 +45,14 @@
 #include <arpa/inet.h>
 #include <alias.h>
 
+typedef int (nat_cb_t)(struct nat44_cfg_nat *cfg, void *arg);
+static void nat_show_cfg(struct nat44_cfg_nat *n, void *arg);
+static void nat_show_log(struct nat44_cfg_nat *n, void *arg);
+static int nat_show_data(struct nat44_cfg_nat *cfg, void *arg);
+static int natname_cmp(const void *a, const void *b);
+static int nat_foreach(nat_cb_t *f, void *arg, int sort);
+static int nat_get_cmd(char *name, uint16_t cmd, ipfw_obj_header **ooh);
+
 static struct _s_x nat_params[] = {
 	{ "ip",			TOK_IP },
 	{ "if",			TOK_IF },
@@ -71,7 +78,7 @@ static struct _s_x nat_params[] = {
  * n->if_name   copy of interface name "ifn"
  */
 static void
-set_addr_dynamic(const char *ifn, struct cfg_nat *n)
+set_addr_dynamic(const char *ifn, struct nat44_cfg_nat *n)
 {
 	size_t needed;
 	int mib[6];
@@ -288,15 +295,15 @@ StrToAddrAndPortRange (const char* str, 
  * and SetupProtoRedirect() from natd.c.
  *
  * Every setup_* function fills at least one redirect entry
- * (struct cfg_redir) and zero or more server pool entry (struct cfg_spool)
- * in buf.
+ * (struct nat44_cfg_redir) and zero or more server pool entry
+ * (struct nat44_cfg_spool) in buf.
  *
  * The format of data in buf is:
  *
- *     cfg_nat    cfg_redir    cfg_spool    ......  cfg_spool
+ *  nat44_cfg_nat nat44_cfg_redir nat44_cfg_spool    ......  nat44_cfg_spool
  *
  *    -------------------------------------        ------------
- *   |          | .....X ... |          |         |           |  .....
+ *   |           | .....X ..... |          |         |           |  .....
  *    ------------------------------------- ...... ------------
  *                     ^
  *                spool_cnt       n=0       ......   n=(X-1)
@@ -314,7 +321,7 @@ StrToAddrAndPortRange (const char* str, 
 static int
 estimate_redir_addr(int *ac, char ***av)
 {
-	size_t space = sizeof(struct cfg_redir);
+	size_t space = sizeof(struct nat44_cfg_redir);
 	char *sep = **av;
 	u_int c = 0;
 
@@ -327,7 +334,7 @@ estimate_redir_addr(int *ac, char ***av)
 	if (c > 0)
 		c++;
 
-	space += c * sizeof(struct cfg_spool);
+	space += c * sizeof(struct nat44_cfg_spool);
 
 	return (space);
 }
@@ -335,31 +342,31 @@ estimate_redir_addr(int *ac, char ***av)
 static int
 setup_redir_addr(char *buf, int *ac, char ***av)
 {
-	struct cfg_redir *r;
+	struct nat44_cfg_redir *r;
 	char *sep;
 	size_t space;
 
-	r = (struct cfg_redir *)buf;
+	r = (struct nat44_cfg_redir *)buf;
 	r->mode = REDIR_ADDR;
-	/* Skip cfg_redir at beginning of buf. */
-	buf = &buf[sizeof(struct cfg_redir)];
-	space = sizeof(struct cfg_redir);
+	/* Skip nat44_cfg_redir at beginning of buf. */
+	buf = &buf[sizeof(struct nat44_cfg_redir)];
+	space = sizeof(struct nat44_cfg_redir);
 
 	/* Extract local address. */
 	if (strchr(**av, ',') != NULL) {
-		struct cfg_spool *spool;
+		struct nat44_cfg_spool *spool;
 
 		/* Setup LSNAT server pool. */
 		r->laddr.s_addr = INADDR_NONE;
 		sep = strtok(**av, ",");
 		while (sep != NULL) {
-			spool = (struct cfg_spool *)buf;
-			space += sizeof(struct cfg_spool);
+			spool = (struct nat44_cfg_spool *)buf;
+			space += sizeof(struct nat44_cfg_spool);
 			StrToAddr(sep, &spool->addr);
 			spool->port = ~0;
 			r->spool_cnt++;
-			/* Point to the next possible cfg_spool. */
-			buf = &buf[sizeof(struct cfg_spool)];
+			/* Point to the next possible nat44_cfg_spool. */
+			buf = &buf[sizeof(struct nat44_cfg_spool)];
 			sep = strtok(NULL, ",");
 		}
 	} else
@@ -376,7 +383,7 @@ setup_redir_addr(char *buf, int *ac, cha
 static int
 estimate_redir_port(int *ac, char ***av)
 {
-	size_t space = sizeof(struct cfg_redir);
+	size_t space = sizeof(struct nat44_cfg_redir);
 	char *sep = **av;
 	u_int c = 0;
 
@@ -389,7 +396,7 @@ estimate_redir_port(int *ac, char ***av)
 	if (c > 0)
 		c++;
 
-	space += c * sizeof(struct cfg_spool);
+	space += c * sizeof(struct nat44_cfg_spool);
 
 	return (space);
 }
@@ -397,7 +404,7 @@ estimate_redir_port(int *ac, char ***av)
 static int
 setup_redir_port(char *buf, int *ac, char ***av)
 {
-	struct cfg_redir *r;
+	struct nat44_cfg_redir *r;
 	char *sep, *protoName, *lsnat = NULL;
 	size_t space;
 	u_short numLocalPorts;
@@ -405,11 +412,11 @@ setup_redir_port(char *buf, int *ac, cha
 
 	numLocalPorts = 0;
 
-	r = (struct cfg_redir *)buf;
+	r = (struct nat44_cfg_redir *)buf;
 	r->mode = REDIR_PORT;
-	/* Skip cfg_redir at beginning of buf. */
-	buf = &buf[sizeof(struct cfg_redir)];
-	space = sizeof(struct cfg_redir);
+	/* Skip nat44_cfg_redir at beginning of buf. */
+	buf = &buf[sizeof(struct nat44_cfg_redir)];
+	space = sizeof(struct nat44_cfg_redir);
 
 	/*
 	 * Extract protocol.
@@ -516,12 +523,12 @@ setup_redir_port(char *buf, int *ac, cha
 
 	/* Setup LSNAT server pool. */
 	if (lsnat != NULL) {
-		struct cfg_spool *spool;
+		struct nat44_cfg_spool *spool;
 
 		sep = strtok(lsnat, ",");
 		while (sep != NULL) {
-			spool = (struct cfg_spool *)buf;
-			space += sizeof(struct cfg_spool);
+			spool = (struct nat44_cfg_spool *)buf;
+			space += sizeof(struct nat44_cfg_spool);
 			/*
 			 * The sctp nat does not allow the port numbers to
 			 * be mapped to new port numbers. Therefore, no ports
@@ -549,8 +556,8 @@ setup_redir_port(char *buf, int *ac, cha
 				spool->port = GETLOPORT(portRange);
 			}
 			r->spool_cnt++;
-			/* Point to the next possible cfg_spool. */
-			buf = &buf[sizeof(struct cfg_spool)];
+			/* Point to the next possible nat44_cfg_spool. */
+			buf = &buf[sizeof(struct nat44_cfg_spool)];
 			sep = strtok(NULL, ",");
 		}
 	}
@@ -561,15 +568,15 @@ setup_redir_port(char *buf, int *ac, cha
 static int
 setup_redir_proto(char *buf, int *ac, char ***av)
 {
-	struct cfg_redir *r;
+	struct nat44_cfg_redir *r;
 	struct protoent *protoent;
 	size_t space;
 
-	r = (struct cfg_redir *)buf;
+	r = (struct nat44_cfg_redir *)buf;
 	r->mode = REDIR_PROTO;
-	/* Skip cfg_redir at beginning of buf. */
-	buf = &buf[sizeof(struct cfg_redir)];
-	space = sizeof(struct cfg_redir);
+	/* Skip nat44_cfg_redir at beginning of buf. */
+	buf = &buf[sizeof(struct nat44_cfg_redir)];
+	space = sizeof(struct nat44_cfg_redir);
 
 	/*
 	 * Extract protocol.
@@ -616,18 +623,28 @@ setup_redir_proto(char *buf, int *ac, ch
 }
 
 static void
-print_nat_config(unsigned char *buf)
+nat_show_log(struct nat44_cfg_nat *n, void *arg)
+{
+	char *buf;
+
+	buf = (char *)(n + 1);
+	if (buf[0] != '\0')
+		printf("nat %s: %s\n", n->name, buf);
+}
+
+static void
+nat_show_cfg(struct nat44_cfg_nat *n, void *arg)
 {
-	struct cfg_nat *n;
 	int i, cnt, flag, off;
-	struct cfg_redir *t;
-	struct cfg_spool *s;
+	struct nat44_cfg_redir *t;
+	struct nat44_cfg_spool *s;
+	caddr_t buf;
 	struct protoent *p;
 
-	n = (struct cfg_nat *)buf;
+	buf = (caddr_t)n;
 	flag = 1;
-	off  = sizeof(*n);
-	printf("ipfw nat %u config", n->id);
+	off = sizeof(*n);
+	printf("ipfw nat %s config", n->name);
 	if (strlen(n->if_name) != 0)
 		printf(" if %s", n->if_name);
 	else if (n->ip.s_addr != 0)
@@ -661,8 +678,8 @@ print_nat_config(unsigned char *buf)
 	}
 	/* Print all the redirect's data configuration. */
 	for (cnt = 0; cnt < n->redir_cnt; cnt++) {
-		t = (struct cfg_redir *)&buf[off];
-		off += SOF_REDIR;
+		t = (struct nat44_cfg_redir *)&buf[off];
+		off += sizeof(struct nat44_cfg_redir);
 		switch (t->mode) {
 		case REDIR_ADDR:
 			printf(" redirect_addr");
@@ -670,13 +687,13 @@ print_nat_config(unsigned char *buf)
 				printf(" %s", inet_ntoa(t->laddr));
 			else
 				for (i = 0; i < t->spool_cnt; i++) {
-					s = (struct cfg_spool *)&buf[off];
+					s = (struct nat44_cfg_spool *)&buf[off];
 					if (i)
 						printf(",");
 					else
 						printf(" ");
 					printf("%s", inet_ntoa(s->addr));
-					off += SOF_SPOOL;
+					off += sizeof(struct nat44_cfg_spool);
 				}
 			printf(" %s", inet_ntoa(t->paddr));
 			break;
@@ -690,12 +707,12 @@ print_nat_config(unsigned char *buf)
 					    t->pport_cnt - 1);
 			} else
 				for (i=0; i < t->spool_cnt; i++) {
-					s = (struct cfg_spool *)&buf[off];
+					s = (struct nat44_cfg_spool *)&buf[off];
 					if (i)
 						printf(",");
 					printf("%s:%u", inet_ntoa(s->addr),
 					    s->port);
-					off += SOF_SPOOL;
+					off += sizeof(struct nat44_cfg_spool);
 				}
 
 			printf(" ");
@@ -736,7 +753,8 @@ print_nat_config(unsigned char *buf)
 void
 ipfw_config_nat(int ac, char **av)
 {
-	struct cfg_nat *n;		/* Nat instance configuration. */
+	ipfw_obj_header *oh;
+	struct nat44_cfg_nat *n;		/* Nat instance configuration. */
 	int i, off, tok, ac1;
 	char *id, *buf, **av1, *end;
 	size_t len;
@@ -755,7 +773,7 @@ ipfw_config_nat(int ac, char **av)
 	if (ac == 0)
 		errx(EX_DATAERR, "missing option");
 
-	len = sizeof(struct cfg_nat);
+	len = sizeof(*oh) + sizeof(*n);
 	ac1 = ac;
 	av1 = av;
 	while (ac1 > 0) {
@@ -804,7 +822,7 @@ ipfw_config_nat(int ac, char **av)
 			if (ac1 < 2)
 				errx(EX_DATAERR, "redirect_proto: "
 				    "not enough arguments");
-			len += sizeof(struct cfg_redir);
+			len += sizeof(struct nat44_cfg_redir);
 			av1 += 2;
 			ac1 -= 2;
 			/* Skip optional remoteIP/port */
@@ -825,11 +843,14 @@ ipfw_config_nat(int ac, char **av)
 	if ((buf = malloc(len)) == NULL)
 		errx(EX_OSERR, "malloc failed");
 
-	/* Offset in buf: save space for n at the beginning. */
-	off = sizeof(*n);
+	/* Offset in buf: save space for header at the beginning. */
+	off = sizeof(*oh) + sizeof(*n);
 	memset(buf, 0, len);
-	n = (struct cfg_nat *)buf;
-	n->id = i;
+	oh = (ipfw_obj_header *)buf;
+	n = (struct nat44_cfg_nat *)(oh + 1);
+	oh->ntlv.head.length = sizeof(oh->ntlv);
+	snprintf(oh->ntlv.name, sizeof(oh->ntlv.name), "%d", i);
+	snprintf(n->name, sizeof(n->name), "%d", i);
 
 	while (ac > 0) {
 		tok = match_token(nat_params, *av);
@@ -900,9 +921,9 @@ ipfw_config_nat(int ac, char **av)
 		}
 	}
 
-	i = do_cmd(IP_FW_NAT_CFG, buf, off);
-	if (i)
-		err(1, "setsockopt(%s)", "IP_FW_NAT_CFG");
+	i = do_set3(IP_FW_NAT44_XCONFIG, &oh->opheader, len);
+	if (i != 0)
+		err(1, "setsockopt(%s)", "IP_FW_NAT44_XCONFIG");
 
 	if (!co.do_quiet) {
 		/* After every modification, we show the resultant rule. */
@@ -912,23 +933,147 @@ ipfw_config_nat(int ac, char **av)
 	}
 }
 
+struct nat_list_arg {
+	uint16_t	cmd;
+	int		is_all;
+};
+
+static int
+nat_show_data(struct nat44_cfg_nat *cfg, void *arg)
+{
+	struct nat_list_arg *nla;
+	ipfw_obj_header *oh;
+
+	nla = (struct nat_list_arg *)arg;
+
+	switch (nla->cmd) {
+	case IP_FW_NAT44_XGETCONFIG:
+		if (nat_get_cmd(cfg->name, nla->cmd, &oh) != 0) {
+			warnx("Error getting nat instance %s info", cfg->name);
+			break;
+		}
+		nat_show_cfg((struct nat44_cfg_nat *)(oh + 1), NULL);
+		free(oh);
+		break;
+	case IP_FW_NAT44_XGETLOG:
+		if (nat_get_cmd(cfg->name, nla->cmd, &oh) == 0) {
+			nat_show_log((struct nat44_cfg_nat *)(oh + 1), NULL);
+			free(oh);
+			break;
+		}
+		/* Handle error */
+		if (nla->is_all != 0 && errno == ENOENT)
+			break;
+		warn("Error getting nat instance %s info", cfg->name);
+		break;
+	}
+
+	return (0);
+}
+
+/*
+ * Compare nat names.
+ * Honor number comparison.
+ */
+static int
+natname_cmp(const void *a, const void *b)
+{
+	struct nat44_cfg_nat *ia, *ib;
+
+	ia = (struct nat44_cfg_nat *)a;
+	ib = (struct nat44_cfg_nat *)b;
+
+	return (stringnum_cmp(ia->name, ib->name));
+}
+
+/*
+ * Retrieves nat list from kernel,
+ * optionally sorts it and calls requested function for each table.
+ * Returns 0 on success.
+ */
+static int
+nat_foreach(nat_cb_t *f, void *arg, int sort)
+{
+	ipfw_obj_lheader *olh;
+	struct nat44_cfg_nat *cfg;
+	size_t sz;
+	int i, error;
+
+	/* Start with reasonable default */
+	sz = sizeof(*olh) + 16 * sizeof(struct nat44_cfg_nat);
+
+	for (;;) {
+		if ((olh = calloc(1, sz)) == NULL)
+			return (ENOMEM);
+
+		olh->size = sz;
+		if (do_get3(IP_FW_NAT44_LIST_NAT, &olh->opheader, &sz) != 0) {
+			free(olh);
+			if (errno == ENOMEM) {
+				sz = olh->size;
+				continue;
+			}
+			return (errno);
+		}
+
+		if (sort != 0)
+			qsort(olh + 1, olh->count, olh->objsize, natname_cmp);
+
+		cfg = (struct nat44_cfg_nat*)(olh + 1);
+		for (i = 0; i < olh->count; i++) {
+			error = f(cfg, arg); /* Ignore errors for now */
+			cfg = (struct nat44_cfg_nat *)((caddr_t)cfg +
+			    olh->objsize);
+		}
+
+		free(olh);
+		break;
+	}
+
+	return (0);
+}
+
+static int
+nat_get_cmd(char *name, uint16_t cmd, ipfw_obj_header **ooh)
+{
+	ipfw_obj_header *oh;
+	struct nat44_cfg_nat *cfg;
+	size_t sz;
+
+	/* Start with reasonable default */
+	sz = sizeof(*oh) + sizeof(*cfg) + 128;
+
+	for (;;) {
+		if ((oh = calloc(1, sz)) == NULL)
+			return (ENOMEM);
+		cfg = (struct nat44_cfg_nat *)(oh + 1);
+		oh->ntlv.head.length = sizeof(oh->ntlv);
+		strlcpy(oh->ntlv.name, name, sizeof(oh->ntlv.name));
+		strlcpy(cfg->name, name, sizeof(cfg->name));
+
+		if (do_get3(cmd, &oh->opheader, &sz) != 0) {
+			sz = cfg->size;
+			free(oh);
+			if (errno == ENOMEM)
+				continue;
+			return (errno);
+		}
+
+		*ooh = oh;
+		break;
+	}
+
+	return (0);
+}
 
 void
 ipfw_show_nat(int ac, char **av)
 {
-	struct cfg_nat *n;
-	struct cfg_redir *e;
-	int cmd, i, nbytes, do_cfg, do_rule, frule, lrule, nalloc, size;
-	int nat_cnt, redir_cnt, r;
-	uint8_t *data, *p;
-	char *endptr;
-
-	do_rule = 0;
-	nalloc = 1024;
-	size = 0;
-	data = NULL;
-	frule = 0;
-	lrule = IPFW_DEFAULT_RULE; /* max ipfw rule number */
+	ipfw_obj_header *oh;
+	char *name;
+	int cmd;
+	struct nat_list_arg nla;
+
 	ac--;
 	av++;
 
@@ -936,55 +1081,35 @@ ipfw_show_nat(int ac, char **av)
 		return;
 
 	/* Parse parameters. */
-	for (cmd = IP_FW_NAT_GET_LOG, do_cfg = 0; ac != 0; ac--, av++) {
+	cmd = 0; /* XXX: Change to IP_FW_NAT44_XGETLOG @ MFC */
+	name = NULL;
+	for ( ; ac != 0; ac--, av++) {
 		if (!strncmp(av[0], "config", strlen(av[0]))) {
-			cmd = IP_FW_NAT_GET_CONFIG, do_cfg = 1;
+			cmd = IP_FW_NAT44_XGETCONFIG;
 			continue;
 		}
-		/* Convert command line rule #. */
-		frule = lrule = strtoul(av[0], &endptr, 10);
-		if (*endptr == '-')
-			lrule = strtoul(endptr+1, &endptr, 10);
-		if (lrule == 0)
-			err(EX_USAGE, "invalid rule number: %s", av[0]);
-		do_rule = 1;
-	}
-
-	nbytes = nalloc;
-	while (nbytes >= nalloc) {
-		nalloc = nalloc * 2;
-		nbytes = nalloc;
-		data = safe_realloc(data, nbytes);
-		if (do_cmd(cmd, data, (uintptr_t)&nbytes) < 0)
-			err(EX_OSERR, "getsockopt(IP_FW_GET_%s)",
-			    (cmd == IP_FW_NAT_GET_LOG) ? "LOG" : "CONFIG");
-	}
-	if (nbytes == 0)
-		exit(0);
-	if (do_cfg) {
-		nat_cnt = *((int *)data);
-		for (i = sizeof(nat_cnt); nat_cnt; nat_cnt--) {
-			n = (struct cfg_nat *)&data[i];
-			if (frule <= n->id && lrule >= n->id)
-				print_nat_config(&data[i]);
-			i += sizeof(struct cfg_nat);
-			for (redir_cnt = 0; redir_cnt < n->redir_cnt; redir_cnt++) {
-				e = (struct cfg_redir *)&data[i];
-				i += sizeof(struct cfg_redir) + e->spool_cnt *
-				    sizeof(struct cfg_spool);
-			}
+		if (strcmp(av[0], "log") == 0) {
+			cmd = IP_FW_NAT44_XGETLOG;
+			continue;
 		}
+		if (name != NULL)
+			err(EX_USAGE,"only one instance name may be specified");
+		name = av[0];
+	}
+
+	if (cmd == 0)
+		errx(EX_USAGE, "Please specify action. Available: config,log");
+
+	if (name == NULL) {
+		memset(&nla, 0, sizeof(nla));
+		nla.cmd = cmd;
+		nla.is_all = 1;
+		nat_foreach(nat_show_data, &nla, 1);
 	} else {
-		for (i = 0; 1; i += LIBALIAS_BUF_SIZE + sizeof(int)) {
-			p = &data[i];
-			if (p == data + nbytes)
-				break;
-			bcopy(p, &r, sizeof(int));
-			if (do_rule) {
-				if (!(frule <= r && lrule >= r))
-					continue;
-			}
-			printf("nat %u: %s\n", r, p+sizeof(int));
-		}
+		if (nat_get_cmd(name, cmd, &oh) != 0)
+			err(EX_OSERR, "Error getting nat %s instance info", name);
+		nat_show_cfg((struct nat44_cfg_nat *)(oh + 1), NULL);
+		free(oh);
 	}
 }
+

Modified: projects/ipfw/sys/netinet/ip_fw.h
==============================================================================
--- projects/ipfw/sys/netinet/ip_fw.h	Sun Sep  7 18:05:37 2014	(r271230)
+++ projects/ipfw/sys/netinet/ip_fw.h	Sun Sep  7 18:30:29 2014	(r271231)
@@ -98,6 +98,12 @@ typedef struct _ip_fw3_opheader {
 #define	IP_FW_TABLE_XSWAP	109	/* swap two tables */
 #define	IP_FW_TABLE_VLIST	110	/* dump table value hash */
 
+#define	IP_FW_NAT44_XCONFIG	111	/* Create/modify NAT44 instance */
+#define	IP_FW_NAT44_DESTROY	112	/* Destroys NAT44 instance */
+#define	IP_FW_NAT44_XGETCONFIG	113	/* Get NAT44 instance config */
+#define	IP_FW_NAT44_LIST_NAT	114	/* List all NAT44 instances */
+#define	IP_FW_NAT44_XGETLOG	115	/* Get log from NAT44 instance */
+
 /*
  * The kernel representation of ipfw rules is made of a list of
  * 'instructions' (for all practical purposes equivalent to BPF
@@ -402,6 +408,8 @@ typedef struct  _ipfw_insn_log {
 	u_int32_t log_left;	/* how many left to log 	*/
 } ipfw_insn_log;
 
+/* Legacy NAT structures, compat only */
+#ifndef	_KERNEL
 /*
  * Data structures required by both ipfw(8) and ipfw(4) but not part of the
  * management API are protected by IPFW_INTERNAL.
@@ -463,6 +471,44 @@ struct cfg_nat {
 #define SOF_REDIR       sizeof(struct cfg_redir)
 #define SOF_SPOOL       sizeof(struct cfg_spool)
 
+#endif	/* ifndef _KERNEL */
+
+
+struct nat44_cfg_spool {
+	struct in_addr	addr;
+	uint16_t	port;
+	uint16_t	spare;
+};
+#define NAT44_REDIR_ADDR	0x01
+#define NAT44_REDIR_PORT	0x02
+#define NAT44_REDIR_PROTO	0x04
+
+/* Nat redirect configuration. */
+struct nat44_cfg_redir {
+	struct in_addr	laddr;		/* local ip address */
+	struct in_addr	paddr;		/* public ip address */
+	struct in_addr	raddr;		/* remote ip address */
+	uint16_t	lport;		/* local port */
+	uint16_t	pport;		/* public port */
+	uint16_t	rport;		/* remote port  */
+	uint16_t	pport_cnt;	/* number of public ports */
+	uint16_t	rport_cnt;	/* number of remote ports */
+	uint16_t	mode;		/* type of redirect mode */
+	uint16_t	spool_cnt;	/* num of entry in spool chain */ 
+	uint16_t	spare;
+	uint32_t	proto;		/* protocol: tcp/udp */
+};
+
+/* Nat configuration data struct. */
+struct nat44_cfg_nat {
+	char		name[64];	/* nat name */
+	char		if_name[64];	/* interface name */
+	uint32_t	size;		/* structure size incl. redirs */
+	struct in_addr	ip;		/* nat IPv4 address */
+	uint32_t	mode;		/* aliasing mode */
+	uint32_t	redir_cnt;	/* number of entry in spool chain */
+};
+
 /* Nat command. */
 typedef struct	_ipfw_insn_nat {
  	ipfw_insn	o;

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_nat.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_nat.c	Sun Sep  7 18:05:37 2014	(r271230)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_nat.c	Sun Sep  7 18:30:29 2014	(r271231)
@@ -37,8 +37,6 @@ __FBSDID("$FreeBSD$");
 #include <sys/module.h>
 #include <sys/rwlock.h>
 
-#define        IPFW_INTERNAL   /* Access to protected data structures in ip_fw.h. */
-
 #include <netinet/libalias/alias.h>
 #include <netinet/libalias/alias_local.h>
 
@@ -55,6 +53,45 @@ __FBSDID("$FreeBSD$");
 
 #include <machine/in_cksum.h>	/* XXX for in_cksum */
 
+struct cfg_spool {
+	LIST_ENTRY(cfg_spool)   _next;          /* chain of spool instances */
+	struct in_addr          addr;
+	uint16_t		port;
+};
+
+/* Nat redirect configuration. */
+struct cfg_redir {
+	LIST_ENTRY(cfg_redir)	_next;	/* chain of redir instances */
+	uint16_t		mode;	/* type of redirect mode */
+	uint16_t		proto;	/* protocol: tcp/udp */
+	struct in_addr		laddr;	/* local ip address */
+	struct in_addr		paddr;	/* public ip address */
+	struct in_addr		raddr;	/* remote ip address */
+	uint16_t		lport;	/* local port */
+	uint16_t		pport;	/* public port */
+	uint16_t		rport;	/* remote port	*/
+	uint16_t		pport_cnt;	/* number of public ports */
+	uint16_t		rport_cnt;	/* number of remote ports */
+	struct alias_link	**alink;	
+	u_int16_t		spool_cnt; /* num of entry in spool chain */
+	/* chain of spool instances */
+	LIST_HEAD(spool_chain, cfg_spool) spool_chain;
+};
+
+/* Nat configuration data struct. */
+struct cfg_nat {
+	/* chain of nat instances */
+	LIST_ENTRY(cfg_nat)	_next;
+	int			id;		/* nat id  */
+	struct in_addr		ip;		/* nat ip address */
+	struct libalias		*lib;		/* libalias instance */
+	int			mode;		/* aliasing mode */
+	int			redir_cnt; /* number of entry in spool chain */
+	/* chain of redir instances */
+	LIST_HEAD(redir_chain, cfg_redir) redir_chain;  
+	char			if_name[IF_NAMESIZE];	/* interface name */
+};
+
 static eventhandler_tag ifaddr_event_tag;
 
 static void
@@ -117,11 +154,11 @@ del_redir_spool_cfg(struct cfg_nat *n, s
 	LIST_FOREACH_SAFE(r, head, _next, tmp_r) {
 		num = 1; /* Number of alias_link to delete. */
 		switch (r->mode) {
-		case REDIR_PORT:
+		case NAT44_REDIR_PORT:
 			num = r->pport_cnt;
 			/* FALLTHROUGH */
-		case REDIR_ADDR:
-		case REDIR_PROTO:
+		case NAT44_REDIR_ADDR:
+		case NAT44_REDIR_PROTO:
 			/* Delete all libalias redirect entry. */
 			for (i = 0; i < num; i++)
 				LibAliasRedirectDelete(n->lib, r->alink[i]);
@@ -142,27 +179,41 @@ del_redir_spool_cfg(struct cfg_nat *n, s
 	}
 }
 
-static void
+static int
 add_redir_spool_cfg(char *buf, struct cfg_nat *ptr)
 {
-	struct cfg_redir *r, *ser_r;
-	struct cfg_spool *s, *ser_s;
+	struct cfg_redir *r;
+	struct cfg_spool *s;
+	struct nat44_cfg_redir *ser_r;
+	struct nat44_cfg_spool *ser_s;
+
 	int cnt, off, i;
 
 	for (cnt = 0, off = 0; cnt < ptr->redir_cnt; cnt++) {
-		ser_r = (struct cfg_redir *)&buf[off];
-		r = malloc(SOF_REDIR, M_IPFW, M_WAITOK | M_ZERO);
-		memcpy(r, ser_r, SOF_REDIR);
+		ser_r = (struct nat44_cfg_redir *)&buf[off];
+		r = malloc(sizeof(*r), M_IPFW, M_WAITOK | M_ZERO);
+		r->mode = ser_r->mode;
+		r->laddr = ser_r->laddr;
+		r->paddr = ser_r->paddr;
+		r->raddr = ser_r->raddr;
+		r->lport = ser_r->lport;
+		r->pport = ser_r->pport;
+		r->rport = ser_r->rport;
+		r->pport_cnt = ser_r->pport_cnt;
+		r->rport_cnt = ser_r->rport_cnt;
+		r->proto = ser_r->proto;
+		r->spool_cnt = ser_r->spool_cnt;
+		//memcpy(r, ser_r, SOF_REDIR);
 		LIST_INIT(&r->spool_chain);
-		off += SOF_REDIR;
+		off += sizeof(struct nat44_cfg_redir);
 		r->alink = malloc(sizeof(struct alias_link *) * r->pport_cnt,
 		    M_IPFW, M_WAITOK | M_ZERO);
 		switch (r->mode) {
-		case REDIR_ADDR:
+		case NAT44_REDIR_ADDR:
 			r->alink[0] = LibAliasRedirectAddr(ptr->lib, r->laddr,
 			    r->paddr);
 			break;
-		case REDIR_PORT:
+		case NAT44_REDIR_PORT:
 			for (i = 0 ; i < r->pport_cnt; i++) {
 				/* If remotePort is all ports, set it to 0. */
 				u_short remotePortCopy = r->rport + i;
@@ -178,7 +229,7 @@ add_redir_spool_cfg(char *buf, struct cf
 				}
 			}
 			break;
-		case REDIR_PROTO:
+		case NAT44_REDIR_PROTO:
 			r->alink[0] = LibAliasRedirectProto(ptr->lib ,r->laddr,
 			    r->raddr, r->paddr, r->proto);
 			break;
@@ -186,23 +237,27 @@ add_redir_spool_cfg(char *buf, struct cf
 			printf("unknown redirect mode: %u\n", r->mode);
 			break;
 		}
-		/* XXX perhaps return an error instead of panic ? */
-		if (r->alink[0] == NULL)
-			panic("LibAliasRedirect* returned NULL");
+		if (r->alink[0] == NULL) {
+			printf("LibAliasRedirect* returned NULL\n");
+			return (EINVAL);
+		}
 		/* LSNAT handling. */
 		for (i = 0; i < r->spool_cnt; i++) {
-			ser_s = (struct cfg_spool *)&buf[off];
-			s = malloc(SOF_REDIR, M_IPFW, M_WAITOK | M_ZERO);
-			memcpy(s, ser_s, SOF_SPOOL);
+			ser_s = (struct nat44_cfg_spool *)&buf[off];
+			s = malloc(sizeof(*s), M_IPFW, M_WAITOK | M_ZERO);
+			s->addr = ser_s->addr;
+			s->port = ser_s->port;
 			LibAliasAddServer(ptr->lib, r->alink[0],
 			    s->addr, htons(s->port));
-			off += SOF_SPOOL;
+			off += sizeof(struct nat44_cfg_spool);
 			/* Hook spool entry. */
 			LIST_INSERT_HEAD(&r->spool_chain, s, _next);
 		}
 		/* And finally hook this redir entry. */
 		LIST_INSERT_HEAD(&ptr->redir_chain, r, _next);
 	}
+
+	return (0);
 }
 
 /*
@@ -392,60 +447,68 @@ lookup_nat(struct nat_list *l, int nat_i
 	return res;
 }
 
-static int
-ipfw_nat_cfg(struct sockopt *sopt)
+static struct cfg_nat *
+lookup_nat_name(struct nat_list *l, char *name)
 {
-	struct cfg_nat *cfg, *ptr;
-	char *buf;
-	struct ip_fw_chain *chain = &V_layer3_chain;
-	size_t len;
-	int gencnt, error = 0;
+	struct cfg_nat *res;
+	int id;
+	char *errptr;
 
-	len = sopt->sopt_valsize;
-	buf = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
-	if ((error = sooptcopyin(sopt, buf, len, sizeof(struct cfg_nat))) != 0)
-		goto out;
+	id = strtol(name, &errptr, 10);
+	if (id == 0 || *errptr != '\0')
+		return (NULL);
 
-	cfg = (struct cfg_nat *)buf;
-	if (cfg->id < 0) {
-		error = EINVAL;
-		goto out;
+	LIST_FOREACH(res, l, _next) {
+		if (res->id == id)
+			break;
 	}
+	return (res);
+}
+
+/* IP_FW3 configuration routines */
+
+static void
+nat44_config(struct ip_fw_chain *chain, struct nat44_cfg_nat *ucfg)
+{
+	struct cfg_nat *ptr, *tcfg;
+	int gencnt;
 
 	/*
 	 * Find/create nat rule.
 	 */
-	IPFW_WLOCK(chain);
+	IPFW_UH_WLOCK(chain);
 	gencnt = chain->gencnt;
-	ptr = lookup_nat(&chain->nat, cfg->id);
+	ptr = lookup_nat_name(&chain->nat, ucfg->name);
 	if (ptr == NULL) {
-		IPFW_WUNLOCK(chain);
+		IPFW_UH_WUNLOCK(chain);
 		/* New rule: allocate and init new instance. */
 		ptr = malloc(sizeof(struct cfg_nat), M_IPFW, M_WAITOK | M_ZERO);
 		ptr->lib = LibAliasInit(NULL);
 		LIST_INIT(&ptr->redir_chain);
 	} else {
 		/* Entry already present: temporarily unhook it. */
+		IPFW_WLOCK(chain);
 		LIST_REMOVE(ptr, _next);
-		flush_nat_ptrs(chain, cfg->id);
+		flush_nat_ptrs(chain, ptr->id);
 		IPFW_WUNLOCK(chain);
+		IPFW_UH_WUNLOCK(chain);
 	}
 
 	/*
-	 * Basic nat configuration.
+	 * Basic nat (re)configuration.
 	 */
-	ptr->id = cfg->id;
+	ptr->id = strtol(ucfg->name, NULL, 10);
 	/*
 	 * XXX - what if this rule doesn't nat any ip and just
 	 * redirect?
 	 * do we set aliasaddress to 0.0.0.0?
 	 */
-	ptr->ip = cfg->ip;
-	ptr->redir_cnt = cfg->redir_cnt;
-	ptr->mode = cfg->mode;
-	LibAliasSetMode(ptr->lib, cfg->mode, ~0);
+	ptr->ip = ucfg->ip;
+	ptr->redir_cnt = ucfg->redir_cnt;
+	ptr->mode = ucfg->mode;
+	strlcpy(ptr->if_name, ucfg->if_name, sizeof(ptr->if_name));
+	LibAliasSetMode(ptr->lib, ptr->mode, ~0);
 	LibAliasSetAddress(ptr->lib, ptr->ip);
-	memcpy(ptr->if_name, cfg->if_name, IF_NAMESIZE);
 
 	/*
 	 * Redir and LSNAT configuration.
@@ -453,16 +516,455 @@ ipfw_nat_cfg(struct sockopt *sopt)
 	/* Delete old cfgs. */
 	del_redir_spool_cfg(ptr, &ptr->redir_chain);
 	/* Add new entries. */
-	add_redir_spool_cfg(&buf[(sizeof(struct cfg_nat))], ptr);
+	add_redir_spool_cfg((char *)(ucfg + 1), ptr);
+	IPFW_UH_WLOCK(chain);
 
-	IPFW_WLOCK(chain);
 	/* Extra check to avoid race with another ipfw_nat_cfg() */
-	if (gencnt != chain->gencnt &&
-	    ((cfg = lookup_nat(&chain->nat, ptr->id)) != NULL))
-		LIST_REMOVE(cfg, _next);
+	tcfg = NULL;
+	if (gencnt != chain->gencnt)
+	    tcfg = lookup_nat_name(&chain->nat, ucfg->name);
+	IPFW_WLOCK(chain);
+	if (tcfg != NULL)
+		LIST_REMOVE(tcfg, _next);
 	LIST_INSERT_HEAD(&chain->nat, ptr, _next);
+	IPFW_WUNLOCK(chain);
 	chain->gencnt++;
+
+	IPFW_UH_WUNLOCK(chain);
+
+	if (tcfg != NULL)
+		free(tcfg, M_IPFW);
+}
+
+/*
+ * Creates/configure nat44 instance
+ * Data layout (v0)(current):
+ * Request: [ ipfw_obj_header nat44_cfg_nat .. ]
+ *
+ * Returns 0 on success
+ */
+static int
+nat44_cfg(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
+    struct sockopt_data *sd)
+{
+	ipfw_obj_header *oh;
+	struct nat44_cfg_nat *ucfg;
+	int id;
+	size_t read;
+	char *errptr;
+
+	/* Check minimum header size */
+	if (sd->valsize < (sizeof(*oh) + sizeof(*ucfg)))
+		return (EINVAL);
+
+	oh = (ipfw_obj_header *)sd->kbuf;
+
+	/* Basic length checks for TLVs */
+	if (oh->ntlv.head.length != sizeof(oh->ntlv))
+		return (EINVAL);
+
+	ucfg = (struct nat44_cfg_nat *)(oh + 1);
+
+	/* Check if name is properly terminated and looks like number */
+	if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
+		return (EINVAL);
+	id = strtol(ucfg->name, &errptr, 10);
+	if (id == 0 || *errptr != '\0')
+		return (EINVAL);
+
+	read = sizeof(*oh) + sizeof(*ucfg);
+	/* Check number of redirs */
+	if (sd->valsize < read + ucfg->redir_cnt*sizeof(struct nat44_cfg_redir))
+		return (EINVAL);
+
+	nat44_config(chain, ucfg);
+	return (0);
+}
+
+/*
+ * Destroys given nat instances.

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



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