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
This commit is contained in:
Andrey V. Elsukov 2011-06-14 13:35:24 +00:00
parent 980ccceb94
commit 1875bbfe54
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=223080
7 changed files with 99 additions and 15 deletions

View File

@ -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 engine on address change.
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

View File

@ -1121,8 +1121,11 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
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;

View File

@ -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,

View File

@ -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;

View File

@ -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) ?

View File

@ -207,7 +207,8 @@ ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m)
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 cfg_nat *t, struct mbuf *m)
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 cfg_nat *t, struct mbuf *m)
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;

View File

@ -220,6 +220,12 @@ struct mbuf *m_megapullup(struct mbuf *, int);
#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