kern/157867: [patch][ipfw] natd globalport support for ipfw nat
Alexander V. Chernikov
melifaro at ipfw.ru
Tue Jun 14 06:00:21 UTC 2011
>Number: 157867
>Category: kern
>Synopsis: [patch][ipfw] natd globalport support for ipfw nat
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: change-request
>Submitter-Id: current-users
>Arrival-Date: Tue Jun 14 06:00:19 UTC 2011
>Closed-Date:
>Last-Modified:
>Originator: Alexander V. Chernikov
>Release: 9.0-CURRENT
>Organization:
JSC Meganet
>Environment:
FreeBSD zfscurr0.home.ipfw.ru 9.0-CURRENT FreeBSD 9.0-CURRENT #7 r222980M: Sat Jun 11 20:25:05 MSD 2011 root at zfscurr0.home.ipfw.ru:/var/xtmp/usj/obj/usr/src/sys/DEVEL amd64
>Description:
Permit ipfw nat to find translation state in multiple nat instances via new 'global' option. This functionality is very close to natd -globalport (please see MULTIPLE ISTANCES in natd(8) for more detailed explanation)
>How-To-Repeat:
>Fix:
Patch attached with submission follows:
Index: sbin/ipfw/nat.c
===================================================================
--- sbin/ipfw/nat.c (revision 221263)
+++ sbin/ipfw/nat.c (working copy)
@@ -53,6 +53,7 @@
{ "deny_in", TOK_DENY_INC },
{ "same_ports", TOK_SAME_PORTS },
{ "unreg_only", TOK_UNREG_ONLY },
+ { "skip_global", TOK_SKIP_GLOBAL },
{ "reset", TOK_RESET_ADDR },
{ "reverse", TOK_ALIAS_REV },
{ "proxy_only", TOK_PROXY_ONLY },
@@ -675,6 +676,9 @@
} else if (n->mode & PKT_ALIAS_UNREGISTERED_ONLY) {
printf(" unreg_only");
n->mode &= ~PKT_ALIAS_UNREGISTERED_ONLY;
+ } else if (n->mode & PKT_ALIAS_SKIP_GLOBAL) {
+ printf(" skip_global");
+ n->mode &= ~PKT_ALIAS_SKIP_GLOBAL;
} else if (n->mode & PKT_ALIAS_RESET_ON_ADDR_CHANGE) {
printf(" reset");
n->mode &= ~PKT_ALIAS_RESET_ON_ADDR_CHANGE;
@@ -815,6 +819,9 @@
case TOK_UNREG_ONLY:
n->mode |= PKT_ALIAS_UNREGISTERED_ONLY;
break;
+ case TOK_SKIP_GLOBAL:
+ n->mode |= PKT_ALIAS_SKIP_GLOBAL;
+ break;
case TOK_RESET_ADDR:
n->mode |= PKT_ALIAS_RESET_ON_ADDR_CHANGE;
break;
Index: sbin/ipfw/ipfw2.c
===================================================================
--- sbin/ipfw/ipfw2.c (revision 221263)
+++ sbin/ipfw/ipfw2.c (working copy)
@@ -1112,7 +1112,10 @@
break;
case O_NAT:
- PRINT_UINT_ARG("nat ", cmd->arg1);
+ if (cmd->arg1 != 0)
+ PRINT_UINT_ARG("nat ", cmd->arg1);
+ else
+ printf("nat global");
break;
case O_SETFIB:
@@ -2731,7 +2734,12 @@
case TOK_NAT:
action->opcode = O_NAT;
action->len = F_INSN_SIZE(ipfw_insn_nat);
- goto chkarg;
+ if (_substrcmp(*av, "global") == 0) {
+ action->arg1 = 0;
+ av++;
+ break;
+ } else
+ goto chkarg;
case TOK_QUEUE:
action->opcode = O_QUEUE;
Index: sbin/ipfw/ipfw.8
===================================================================
--- sbin/ipfw/ipfw.8 (revision 221263)
+++ sbin/ipfw/ipfw.8 (working copy)
@@ -2419,8 +2419,28 @@
Reverse the way libalias handles aliasing.
.It Cm proxy_only
Obey transparent proxy rules only, packet aliasing is not performed.
+.It Cm skip_global
+Skip instance in case of global state lookup (see below).
.El
.Pp
+Some specials value can be supplied instead of
+.Va nat_number:
+.Bl -tag -width indent
+.It Cm global
+Looks up translation state in all configured nat instances. If an entry
+is found, packet is aliased according to that entry. If no entry
+was found in any of the instances, packet is passed unchanged, and
+no new entry will be created. See section
+.Sx MULTIPLE INSTANCES
+in
+.Xr natd 8
+for more information.
+.It Cm tablearg
+Uses argument supplied in lookup table. See
+.Sx LOOKUP TABLES
+section below for more information on lookup tables.
+.El
+.Pp
To let the packet continue after being (de)aliased, set the sysctl variable
.Va net.inet.ip.fw.one_pass
to 0.
Index: sbin/ipfw/ipfw2.h
===================================================================
--- sbin/ipfw/ipfw2.h (revision 221263)
+++ sbin/ipfw/ipfw2.h (working copy)
@@ -178,6 +178,7 @@
TOK_DENY_INC,
TOK_SAME_PORTS,
TOK_UNREG_ONLY,
+ TOK_SKIP_GLOBAL,
TOK_RESET_ADDR,
TOK_ALIAS_REV,
TOK_PROXY_ONLY,
Index: sys/netinet/libalias/alias.h
===================================================================
--- sys/netinet/libalias/alias.h (revision 221263)
+++ sys/netinet/libalias/alias.h (working copy)
@@ -220,6 +220,12 @@
*/
#define PKT_ALIAS_REVERSE 0x80
+/*
+ * If PKT_ALIAS_SKIP_GLOBAL is set, nat instance is not checked for matching states
+ * in 'nat global' rule.
+ */
+#define PKT_ALIAS_SKIP_GLOBAL 0x100
+
/* Function return codes. */
#define PKT_ALIAS_ERROR -1
#define PKT_ALIAS_OK 1
Index: sys/netinet/ipfw/ip_fw_nat.c
===================================================================
--- sys/netinet/ipfw/ip_fw_nat.c (revision 221263)
+++ sys/netinet/ipfw/ip_fw_nat.c (working copy)
@@ -208,11 +208,13 @@
struct mbuf *mcl;
struct ip *ip;
/* XXX - libalias duct tape */
- int ldt, retval;
+ int ldt, retval, found;
char *c;
+ struct ip_fw_chain *chain;
ldt = 0;
retval = 0;
+ found = 0;
mcl = m_megapullup(m, m->m_pkthdr.len);
if (mcl == NULL) {
args->m = NULL;
@@ -257,12 +259,44 @@
ldt = 1;
c = mtod(mcl, char *);
- if (args->oif == NULL)
- retval = LibAliasIn(t->lib, c,
- mcl->m_len + M_TRAILINGSPACE(mcl));
- else
- retval = LibAliasOut(t->lib, c,
- mcl->m_len + M_TRAILINGSPACE(mcl));
+
+ /* Check if this is 'global' instance */
+ if (t == NULL) {
+ if (args->oif == NULL) {
+ /* Wrong direction, skip processing */
+ args->m = mcl;
+ return (IP_FW_NAT);
+ }
+
+ chain = &V_layer3_chain;
+ IPFW_RLOCK(chain);
+ /* Check every nat entry... */
+ LIST_FOREACH(t, &chain->nat, _next) {
+ if ((t->lib->packetAliasMode & PKT_ALIAS_SKIP_GLOBAL) != 0)
+ continue;
+
+ if ((retval = LibAliasOutTry(t->lib, c, mcl->m_len + M_TRAILINGSPACE(mcl), 0)) == PKT_ALIAS_OK) {
+ /* Nat instance recognises state */
+ found = 1;
+ break;
+ }
+
+ }
+ IPFW_RUNLOCK(chain);
+
+ if (found != 1) {
+ /* No instance found, return ignore */
+ args->m = mcl;
+ return (IP_FW_NAT);
+ }
+ } else {
+ if (args->oif == NULL)
+ retval = LibAliasIn(t->lib, c,
+ mcl->m_len + M_TRAILINGSPACE(mcl));
+ else
+ retval = LibAliasOut(t->lib, c,
+ mcl->m_len + M_TRAILINGSPACE(mcl));
+ }
if (retval == PKT_ALIAS_RESPOND) {
m->m_flags |= M_SKIP_FIREWALL;
retval = PKT_ALIAS_OK;
Index: sys/netinet/ipfw/ip_fw2.c
===================================================================
--- sys/netinet/ipfw/ip_fw2.c (revision 221263)
+++ sys/netinet/ipfw/ip_fw2.c (working copy)
@@ -2118,6 +2118,13 @@
int nat_id;
set_match(args, f_pos, chain);
+ /* Check if this is 'global' nat rule */
+ if (cmd->arg1 == 0) {
+ retval = ipfw_nat_ptr(args, NULL, m);
+ l = 0;
+ done = 1;
+ break;
+ }
t = ((ipfw_insn_nat *)cmd)->nat;
if (t == NULL) {
nat_id = (cmd->arg1 == IP_FW_TABLEARG) ?
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list