Author: ae
Date: Tue Jun 14 13:35:24 2011
New Revision: 223080
URL: http://svn.freebsd.org/changeset/base/223080

Log:
  Implement "global" mode for ipfw nat. It is similar to natd(8)
  "globalport" option for multiple NAT instances.
  
  If ipfw rule contains "global" keyword instead of nat_number, then
  for each outgoing packet ipfw_nat looks up translation state in all
  configured nat instances. If an entry is found, packet aliased
  according to that entry, otherwise packet is passed unchanged.
  
  User can specify "skip_global" option in NAT configuration to exclude
  an instance from the lookup in global mode.
  
  PR:           kern/157867
  Submitted by: Alexander V. Chernikov (previous version)
  Tested by:    Eugene Grosbein

Modified:
  head/sbin/ipfw/ipfw.8
  head/sbin/ipfw/ipfw2.c
  head/sbin/ipfw/ipfw2.h
  head/sbin/ipfw/nat.c
  head/sys/netinet/ipfw/ip_fw2.c
  head/sys/netinet/ipfw/ip_fw_nat.c
  head/sys/netinet/libalias/alias.h

Modified: head/sbin/ipfw/ipfw.8
==============================================================================
--- head/sbin/ipfw/ipfw.8       Tue Jun 14 13:02:26 2011        (r223079)
+++ head/sbin/ipfw/ipfw.8       Tue Jun 14 13:35:24 2011        (r223080)
@@ -1,7 +1,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd May 30, 2011
+.Dd June 14, 2011
 .Dt IPFW 8
 .Os
 .Sh NAME
@@ -2435,6 +2435,27 @@ Reset table of the packet aliasing engin
 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

Modified: head/sbin/ipfw/ipfw2.c
==============================================================================
--- head/sbin/ipfw/ipfw2.c      Tue Jun 14 13:02:26 2011        (r223079)
+++ head/sbin/ipfw/ipfw2.c      Tue Jun 14 13:35:24 2011        (r223080)
@@ -1121,8 +1121,11 @@ show_ipfw(struct ip_fw *rule, int pcwidt
                        break;
 
                case O_NAT:
-                       PRINT_UINT_ARG("nat ", cmd->arg1);
-                       break;
+                       if (cmd->arg1 != 0)
+                               PRINT_UINT_ARG("nat ", cmd->arg1);
+                       else
+                               printf("nat global");
+                       break;
 
                case O_SETFIB:
                        PRINT_UINT_ARG("setfib ", cmd->arg1);
@@ -2738,9 +2741,14 @@ ipfw_add(char *av[])
                break;
 
        case TOK_NAT:
-               action->opcode = O_NAT;
-               action->len = F_INSN_SIZE(ipfw_insn_nat);
-               goto chkarg;
+               action->opcode = O_NAT;
+               action->len = F_INSN_SIZE(ipfw_insn_nat);
+               if (_substrcmp(*av, "global") == 0) {
+                       action->arg1 = 0;
+                       av++;
+                       break;
+               } else
+                       goto chkarg;
 
        case TOK_QUEUE:
                action->opcode = O_QUEUE;

Modified: head/sbin/ipfw/ipfw2.h
==============================================================================
--- head/sbin/ipfw/ipfw2.h      Tue Jun 14 13:02:26 2011        (r223079)
+++ head/sbin/ipfw/ipfw2.h      Tue Jun 14 13:35:24 2011        (r223080)
@@ -178,6 +178,7 @@ enum tokens {
        TOK_DENY_INC,
        TOK_SAME_PORTS,
        TOK_UNREG_ONLY,
+       TOK_SKIP_GLOBAL,
        TOK_RESET_ADDR,
        TOK_ALIAS_REV,
        TOK_PROXY_ONLY,

Modified: head/sbin/ipfw/nat.c
==============================================================================
--- head/sbin/ipfw/nat.c        Tue Jun 14 13:02:26 2011        (r223079)
+++ head/sbin/ipfw/nat.c        Tue Jun 14 13:35:24 2011        (r223080)
@@ -53,6 +53,7 @@ static struct _s_x nat_params[] = {
        { "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 },
@@ -628,6 +629,9 @@ print_nat_config(unsigned char *buf)
                } else if (n->mode & PKT_ALIAS_SAME_PORTS) {
                        printf(" same_ports");
                        n->mode &= ~PKT_ALIAS_SAME_PORTS;
+               } else if (n->mode & PKT_ALIAS_SKIP_GLOBAL) {
+                       printf(" skip_global");
+                       n->mode &= ~PKT_ALIAS_SKIP_GLOBAL;
                } else if (n->mode & PKT_ALIAS_UNREGISTERED_ONLY) {
                        printf(" unreg_only");
                        n->mode &= ~PKT_ALIAS_UNREGISTERED_ONLY;
@@ -746,10 +750,11 @@ ipfw_config_nat(int ac, char **av)
                case TOK_IP:
                case TOK_IF:
                        ac1--; av1++;
-                       break;      
+                       break;
                case TOK_ALOG:
                case TOK_DENY_INC:
                case TOK_SAME_PORTS:
+               case TOK_SKIP_GLOBAL:
                case TOK_UNREG_ONLY:
                case TOK_RESET_ADDR:
                case TOK_ALIAS_REV:
@@ -821,6 +826,9 @@ ipfw_config_nat(int ac, char **av)
                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;

Modified: head/sys/netinet/ipfw/ip_fw2.c
==============================================================================
--- head/sys/netinet/ipfw/ip_fw2.c      Tue Jun 14 13:02:26 2011        
(r223079)
+++ head/sys/netinet/ipfw/ip_fw2.c      Tue Jun 14 13:35:24 2011        
(r223080)
@@ -2194,6 +2194,13 @@ do {                                                     
        \
                                    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) ?

Modified: head/sys/netinet/ipfw/ip_fw_nat.c
==============================================================================
--- head/sys/netinet/ipfw/ip_fw_nat.c   Tue Jun 14 13:02:26 2011        
(r223079)
+++ head/sys/netinet/ipfw/ip_fw_nat.c   Tue Jun 14 13:35:24 2011        
(r223080)
@@ -207,7 +207,8 @@ ipfw_nat(struct ip_fw_args *args, struct
        struct mbuf *mcl;
        struct ip *ip;
        /* XXX - libalias duct tape */
-       int ldt, retval;
+       int ldt, retval, found;
+       struct ip_fw_chain *chain;
        char *c;
 
        ldt = 0;
@@ -256,12 +257,44 @@ ipfw_nat(struct ip_fw_args *args, struct
                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);
+               }
+
+               found = 0;
+               chain = &V_layer3_chain;
+               IPFW_RLOCK(chain);
+               /* Check every nat entry... */
+               LIST_FOREACH(t, &chain->nat, _next) {
+                       if ((t->mode & PKT_ALIAS_SKIP_GLOBAL) != 0)
+                               continue;
+                       retval = LibAliasOutTry(t->lib, c,
+                           mcl->m_len + M_TRAILINGSPACE(mcl), 0);
+                       if (retval == 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));
+       }
 
        /*
         * We drop packet when:
@@ -274,7 +307,7 @@ ipfw_nat(struct ip_fw_args *args, struct
        if (retval == PKT_ALIAS_ERROR ||
            (args->oif == NULL && (retval == PKT_ALIAS_UNRESOLVED_FRAGMENT ||
            (retval == PKT_ALIAS_IGNORED &&
-           (t->lib->packetAliasMode & PKT_ALIAS_DENY_INCOMING) != 0)))) {
+           (t->mode & PKT_ALIAS_DENY_INCOMING) != 0)))) {
                /* XXX - should i add some logging? */
                m_free(mcl);
                args->m = NULL;

Modified: head/sys/netinet/libalias/alias.h
==============================================================================
--- head/sys/netinet/libalias/alias.h   Tue Jun 14 13:02:26 2011        
(r223079)
+++ head/sys/netinet/libalias/alias.h   Tue Jun 14 13:35:24 2011        
(r223080)
@@ -220,6 +220,12 @@ struct mbuf    *m_megapullup(struct mbuf
 #define        PKT_ALIAS_PUNCH_FW              0x100
 #endif
 
+/*
+ * If PKT_ALIAS_SKIP_GLOBAL is set, nat instance is not checked for matching
+ * states in 'ipfw nat global' rule.
+ */
+#define        PKT_ALIAS_SKIP_GLOBAL           0x200
+
 /* Function return codes. */
 #define        PKT_ALIAS_ERROR                 -1
 #define        PKT_ALIAS_OK                    1
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to