summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authoryx160601 <none@none>2008-07-23 19:59:47 -0700
committeryx160601 <none@none>2008-07-23 19:59:47 -0700
commitd6c23f6fbecbcca8ddd2b74c6e10f37095f9fd46 (patch)
treeac3db8f764d9c2c1acc09b935ff17183f6f42b79 /usr/src
parent34537ab1867f3ee4fb96c044d343e33685a463aa (diff)
downloadillumos-joyent-d6c23f6fbecbcca8ddd2b74c6e10f37095f9fd46.tar.gz
PSARC 2008/250 ipv6 NAT for IPFilter
6600474 RFE: Need ipv6 support on NAT
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/ipf/lib/Makefile.com6
-rw-r--r--usr/src/cmd/ipf/lib/common/printactiveaddr.c37
-rw-r--r--usr/src/cmd/ipf/lib/common/printactivenat.c19
-rw-r--r--usr/src/cmd/ipf/lib/common/printaddr.c63
-rw-r--r--usr/src/cmd/ipf/lib/common/printfr.c82
-rw-r--r--usr/src/cmd/ipf/lib/common/printhostmask.c17
-rw-r--r--usr/src/cmd/ipf/lib/common/printlookup.c34
-rw-r--r--usr/src/cmd/ipf/lib/common/printnat.c87
-rw-r--r--usr/src/cmd/ipf/tools/Makefile.tools6
-rw-r--r--usr/src/cmd/ipf/tools/ip_fil.c5
-rw-r--r--usr/src/cmd/ipf/tools/ipmon.c53
-rw-r--r--usr/src/cmd/ipf/tools/ipnat_y.y382
-rw-r--r--usr/src/cmd/ipf/tools/lexer.c6
-rw-r--r--usr/src/uts/common/Makefile.files2
-rw-r--r--usr/src/uts/common/inet/ipf/fil.c92
-rw-r--r--usr/src/uts/common/inet/ipf/ip_compat.c310
-rw-r--r--usr/src/uts/common/inet/ipf/ip_fil_solaris.c34
-rw-r--r--usr/src/uts/common/inet/ipf/ip_nat.c447
-rw-r--r--usr/src/uts/common/inet/ipf/ip_nat6.c2648
-rw-r--r--usr/src/uts/common/inet/ipf/ipf.h4
-rw-r--r--usr/src/uts/common/inet/ipf/netinet/ip_fil.h118
-rw-r--r--usr/src/uts/common/inet/ipf/netinet/ip_nat.h113
-rw-r--r--usr/src/uts/common/inet/ipf/netinet/ipf_stack.h4
-rw-r--r--usr/src/uts/common/inet/ipf/netinet/ipl.h4
24 files changed, 4065 insertions, 508 deletions
diff --git a/usr/src/cmd/ipf/lib/Makefile.com b/usr/src/cmd/ipf/lib/Makefile.com
index 8019bb8e9c..2d582dc3b4 100644
--- a/usr/src/cmd/ipf/lib/Makefile.com
+++ b/usr/src/cmd/ipf/lib/Makefile.com
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -49,7 +49,7 @@ OBJECTS= addicmp.o addipopt.o bcopywrap.o \
printhashnode.o printip.o printpool.o \
printpoolnode.o printfr.o printfraginfo.o \
printhostmap.o printifname.o printhostmask.o \
- printlog.o printmask.o printnat.o printpacket.o \
+ printlog.o printlookup.o printmask.o printnat.o printpacket.o \
printpacket6.o printportcmp.o printproto.o \
printsbuf.o printstate.o printtunable.o ratoi.o \
remove_pool.o remove_poolnode.o remove_hash.o \
@@ -57,7 +57,7 @@ OBJECTS= addicmp.o addipopt.o bcopywrap.o \
tcpflags.o var.o verbose.o \
v6ionames.o v6optvalue.o printpool_live.o \
printpooldata.o printhash_live.o printhashdata.o \
- printactivenat.o
+ printactiveaddr.o printactivenat.o printaddr.o
include $(SRC)/lib/Makefile.lib
include ../../Makefile.ipf
diff --git a/usr/src/cmd/ipf/lib/common/printactiveaddr.c b/usr/src/cmd/ipf/lib/common/printactiveaddr.c
new file mode 100644
index 0000000000..f3ec165d7f
--- /dev/null
+++ b/usr/src/cmd/ipf/lib/common/printactiveaddr.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2002-2004 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com)
+ */
+
+#include "ipf.h"
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#if !defined(lint)
+static const char rcsid[] = "@(#)$Id: printactiveaddr.c,v 1.1 2008/02/12 16:11:49 darren_r Exp $";
+#endif
+
+void
+printactiveaddress(v, fmt, addr, ifname)
+ int v;
+ char *fmt;
+ i6addr_t *addr;
+ char *ifname;
+{
+ switch (v)
+ {
+ case 4 :
+ printf(fmt, inet_ntoa(addr->in4));
+ break;
+#ifdef USE_INET6
+ case 6 :
+ printaddr(v, FRI_NORMAL, ifname, (u_32_t *)&addr->in6, NULL);
+ break;
+#endif
+ default :
+ break;
+ }
+}
diff --git a/usr/src/cmd/ipf/lib/common/printactivenat.c b/usr/src/cmd/ipf/lib/common/printactivenat.c
index ace6b6cfe3..54d86f96f4 100644
--- a/usr/src/cmd/ipf/lib/common/printactivenat.c
+++ b/usr/src/cmd/ipf/lib/common/printactivenat.c
@@ -1,12 +1,7 @@
/*
- * Copyright (C) 1993-2001 by Darren Reed.
+ * Copyright (C) 2002-2004 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
- *
- * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com)
- *
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -29,17 +24,23 @@ int opts, alive;
if (nat->nat_flags & SI_CLONE)
printf(" CLONE");
- printf(" %-15s", inet_ntoa(nat->nat_inip));
+ printactiveaddress(nat->nat_v, " %-15s", &nat->nat_inip6,
+ nat->nat_ifnames[0]);
if ((nat->nat_flags & IPN_TCPUDP) != 0)
printf(" %-5hu", ntohs(nat->nat_inport));
- printf(" <- -> %-15s",inet_ntoa(nat->nat_outip));
+ printf(" <- -> ");
+ printactiveaddress(nat->nat_v, "%-15s", &nat->nat_outip6,
+ nat->nat_ifnames[0]);
if ((nat->nat_flags & IPN_TCPUDP) != 0)
printf(" %-5hu", ntohs(nat->nat_outport));
- printf(" [%s", inet_ntoa(nat->nat_oip));
+ printf(" [");
+ printactiveaddress(nat->nat_v, "%s", &nat->nat_oip6,
+ nat->nat_ifnames[0]);
+
if ((nat->nat_flags & IPN_TCPUDP) != 0)
printf(" %hu", ntohs(nat->nat_oport));
printf("]");
diff --git a/usr/src/cmd/ipf/lib/common/printaddr.c b/usr/src/cmd/ipf/lib/common/printaddr.c
new file mode 100644
index 0000000000..914ec3c663
--- /dev/null
+++ b/usr/src/cmd/ipf/lib/common/printaddr.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2005 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "ipf.h"
+
+
+void printaddr(v, type, ifname, addr, mask)
+int v, type;
+char *ifname;
+u_32_t *addr, *mask;
+{
+ char *suffix;
+
+ switch (type)
+ {
+ case FRI_BROADCAST :
+ suffix = "/bcast";
+ break;
+
+ case FRI_DYNAMIC :
+ printf("%s", ifname);
+ printmask(v, mask);
+ suffix = NULL;
+ break;
+
+ case FRI_NETWORK :
+ suffix = "/net";
+ break;
+
+ case FRI_NETMASKED :
+ suffix = "/netmasked";
+ break;
+
+ case FRI_PEERADDR :
+ suffix = "/peer";
+ break;
+
+ case FRI_LOOKUP :
+ suffix = NULL;
+ printlookup((i6addr_t *)addr, (i6addr_t *)mask);
+ break;
+
+ case FRI_NORMAL :
+ printhostmask(v, addr, mask);
+ suffix = NULL;
+ break;
+ default :
+ printf("<%d>", type);
+ printmask(v, mask);
+ suffix = NULL;
+ break;
+ }
+
+ if (suffix != NULL) {
+ printf("%s/%s", ifname, suffix);
+ }
+}
diff --git a/usr/src/cmd/ipf/lib/common/printfr.c b/usr/src/cmd/ipf/lib/common/printfr.c
index 5a77998948..063eb87c07 100644
--- a/usr/src/cmd/ipf/lib/common/printfr.c
+++ b/usr/src/cmd/ipf/lib/common/printfr.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1993-2001 by Darren Reed.
+ * Copyright (C) 2000-2005 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
@@ -13,86 +13,6 @@
#include "ipf.h"
-static void printaddr(int, int, char *, u_32_t *, u_32_t *);
-
-static void printaddr(v, type, ifname, addr, mask)
-int v, type;
-char *ifname;
-u_32_t *addr, *mask;
-{
- char *suffix;
-
- switch (type)
- {
- case FRI_BROADCAST :
- suffix = "/bcast";
- break;
-
- case FRI_DYNAMIC :
- printf("%s", ifname);
- printmask(v, mask);
- suffix = NULL;
- break;
-
- case FRI_NETWORK :
- suffix = "/net";
- break;
-
- case FRI_NETMASKED :
- suffix = "/netmasked";
- break;
-
- case FRI_PEERADDR :
- suffix = "/peer";
- break;
-
- case FRI_LOOKUP :
- suffix = NULL;
- printlookup((i6addr_t *)addr, (i6addr_t *)mask);
- break;
-
- case FRI_NORMAL :
- printhostmask(v, addr, mask);
- suffix = NULL;
- break;
- default :
- printf("<%d>", type);
- printmask(v, mask);
- suffix = NULL;
- break;
- }
-
- if (suffix != NULL) {
- printf("%s/%s", ifname, suffix);
- }
-}
-
-
-void printlookup(addr, mask)
-i6addr_t *addr, *mask;
-{
- switch (addr->iplookuptype)
- {
- case IPLT_POOL :
- printf("pool/");
- break;
- case IPLT_HASH :
- printf("hash/");
- break;
- default :
- printf("lookup(%x)=", addr->iplookuptype);
- break;
- }
-
- printf("%u", addr->iplookupnum);
- if (opts & OPT_UNDEF) {
- if (mask->iplookupptr == NULL) {
- printf("(!)");
- }
- }
-}
-
-
/*
* print the filter structure in a useful way
*/
diff --git a/usr/src/cmd/ipf/lib/common/printhostmask.c b/usr/src/cmd/ipf/lib/common/printhostmask.c
index 2afe5c0400..bd8a798b9f 100644
--- a/usr/src/cmd/ipf/lib/common/printhostmask.c
+++ b/usr/src/cmd/ipf/lib/common/printhostmask.c
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 1993-2001 by Darren Reed.
+ * Copyright (C) 2000-2005 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
* $Id: printhostmask.c,v 1.8 2002/04/11 15:01:19 darrenr Exp $
*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -24,26 +24,25 @@ u_32_t *addr, *mask;
struct in_addr ipa;
#endif
- if (!*addr && !*mask)
+ if ((v == 4) && (!*addr) && (!*mask))
printf("any");
else {
#ifdef USE_INET6
void *ptr = addr;
int af;
- if (v == 4) {
- ptr = addr;
+ if (v == 4)
af = AF_INET;
- } else if (v == 6) {
- ptr = addr;
+ else if (v == 6)
af = AF_INET6;
- } else
+ else
af = 0;
printf("%s", inet_ntop(af, ptr, ipbuf, sizeof(ipbuf)));
#else
ipa.s_addr = *addr;
printf("%s", inet_ntoa(ipa));
#endif
- printmask(v, mask);
+ if (mask != NULL)
+ printmask(v, mask);
}
}
diff --git a/usr/src/cmd/ipf/lib/common/printlookup.c b/usr/src/cmd/ipf/lib/common/printlookup.c
new file mode 100644
index 0000000000..ffc822e595
--- /dev/null
+++ b/usr/src/cmd/ipf/lib/common/printlookup.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2005 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "ipf.h"
+
+
+void printlookup(addr, mask)
+ i6addr_t *addr, *mask;
+{
+ switch (addr->iplookuptype)
+ {
+ case IPLT_POOL :
+ printf("pool/");
+ break;
+ case IPLT_HASH :
+ printf("hash/");
+ break;
+ default :
+ printf("lookup(%x)=", addr->iplookuptype);
+ break;
+ }
+
+ printf("%u", addr->iplookupnum);
+ if (opts & OPT_UNDEF) {
+ if (mask->iplookupptr == NULL)
+ printf("(!)");
+ }
+}
diff --git a/usr/src/cmd/ipf/lib/common/printnat.c b/usr/src/cmd/ipf/lib/common/printnat.c
index 521d057f1e..ea8bd72fb0 100644
--- a/usr/src/cmd/ipf/lib/common/printnat.c
+++ b/usr/src/cmd/ipf/lib/common/printnat.c
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 1993-2001 by Darren Reed.
+ * Copyright (C) 2002-2005 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
* Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com)
*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -27,7 +27,9 @@ ipnat_t *np;
int opts;
{
struct protoent *pr;
- int bits;
+ int bits, af;
+ char ipbuf[INET6_ADDRSTRLEN];
+ void *ptr;
pr = getprotobynumber(np->in_p);
@@ -63,11 +65,11 @@ int opts;
printf("! ");
printf("from ");
if (np->in_redir == NAT_REDIRECT) {
- printhostmask(4, (u_32_t *)&np->in_srcip,
- (u_32_t *)&np->in_srcmsk);
+ printhostmask(np->in_v, (u_32_t *)&np->in_src[0],
+ (u_32_t *)&np->in_src[1]);
} else {
- printhostmask(4, (u_32_t *)&np->in_inip,
- (u_32_t *)&np->in_inmsk);
+ printhostmask(np->in_v, (u_32_t *)&np->in_in[0],
+ (u_32_t *)&np->in_in[1]);
}
if (np->in_scmp)
printportcmp(np->in_p, &np->in_tuc.ftu_src);
@@ -76,37 +78,46 @@ int opts;
printf(" !");
printf(" to ");
if (np->in_redir == NAT_REDIRECT) {
- printhostmask(4, (u_32_t *)&np->in_outip,
- (u_32_t *)&np->in_outmsk);
+ printhostmask(np->in_v, (u_32_t *)&np->in_out[0],
+ (u_32_t *)&np->in_out[1]);
} else {
- printhostmask(4, (u_32_t *)&np->in_srcip,
- (u_32_t *)&np->in_srcmsk);
+ printhostmask(np->in_v, (u_32_t *)&np->in_src[0],
+ (u_32_t *)&np->in_src[1]);
}
if (np->in_dcmp)
printportcmp(np->in_p, &np->in_tuc.ftu_dst);
}
+ if (np->in_v == 4)
+ af = AF_INET;
+ else if (np->in_v == 6)
+ af = AF_INET6;
+ else
+ af = 0;
+
if (np->in_redir == NAT_REDIRECT) {
if (!(np->in_flags & IPN_FILTER)) {
- printf("%s", inet_ntoa(np->in_out[0].in4));
- bits = count4bits(np->in_outmsk);
- if (bits != -1)
- printf("/%d", bits);
- else
- printf("/%s", inet_ntoa(np->in_out[1].in4));
+ ptr = (void *)(u_32_t *)&np->in_out[0];
+ printf("%s", inet_ntop(af, ptr, ipbuf, sizeof (ipbuf)));
+ printmask(np->in_v, (u_32_t *)&np->in_out[1]);
if (np->in_flags & IPN_TCPUDP) {
printf(" port %d", ntohs(np->in_pmin));
if (np->in_pmax != np->in_pmin)
printf("-%d", ntohs(np->in_pmax));
}
}
- printf(" -> %s", inet_ntoa(np->in_in[0].in4));
- if (np->in_flags & IPN_SPLIT)
- printf(",%s", inet_ntoa(np->in_in[1].in4));
- if (np->in_inip == 0) {
- bits = count4bits(np->in_inmsk);
- printf("/%d", bits);
+ printf(" -> ");
+ ptr = (void *)(u_32_t *)&np->in_in[0];
+ printf("%s", inet_ntop(af, ptr, ipbuf, sizeof (ipbuf)));
+ if (np->in_flags & IPN_SPLIT) {
+ printf(",");
+ ptr = (void *)(u_32_t *)&np->in_in[1];
+ printf("%s", inet_ntop(af, ptr, ipbuf, sizeof (ipbuf)));
}
+ if (((np->in_v == 4) && (np->in_inip == 0)) ||
+ ((np->in_v == 6) && IP6_ISZERO(&np->in_in[0])))
+ printmask(np->in_v, (u_32_t *)&np->in_in[1]);
+
if (np->in_flags & IPN_TCPUDP) {
if ((np->in_flags & IPN_FIXEDDPORT) != 0)
printf(" port = %d", ntohs(np->in_pnext));
@@ -127,7 +138,7 @@ int opts;
if (np->in_mssclamp != 0)
printf(" mssclamp %d", np->in_mssclamp);
if (*np->in_plabel != '\0')
- printf(" proxy %.*s", (int)sizeof(np->in_plabel),
+ printf(" proxy %.*s", (int)sizeof (np->in_plabel),
np->in_plabel);
if (np->in_tag.ipt_tag[0] != '\0')
printf(" tag %-.*s", IPFTAG_LEN, np->in_tag.ipt_tag);
@@ -136,24 +147,22 @@ int opts;
printf("\tpmax %u\n", np->in_pmax);
} else {
if (!(np->in_flags & IPN_FILTER)) {
- printf("%s/", inet_ntoa(np->in_in[0].in4));
- bits = count4bits(np->in_inmsk);
- if (bits != -1)
- printf("%d", bits);
- else
- printf("%s", inet_ntoa(np->in_in[1].in4));
+ ptr = (void *)(u_32_t *)&np->in_in[0];
+ printf("%s", inet_ntop(af, ptr, ipbuf, sizeof (ipbuf)));
+ printmask(np->in_v, (u_32_t *)&np->in_in[1]);
}
printf(" -> ");
if (np->in_flags & IPN_IPRANGE) {
- printf("range %s-", inet_ntoa(np->in_out[0].in4));
- printf("%s", inet_ntoa(np->in_out[1].in4));
+ printf("range ");
+ ptr = (void *)(u_32_t *)&np->in_out[0];
+ printf("%s", inet_ntop(af, ptr, ipbuf, sizeof (ipbuf)));
+ printf("-");
+ ptr = (void *)(u_32_t *)&np->in_out[1];
+ printf("%s", inet_ntop(af, ptr, ipbuf, sizeof (ipbuf)));
} else {
- printf("%s/", inet_ntoa(np->in_out[0].in4));
- bits = count4bits(np->in_outmsk);
- if (bits != -1)
- printf("%d", bits);
- else
- printf("%s", inet_ntoa(np->in_out[1].in4));
+ ptr = (void *)(u_32_t *)&np->in_out[0];
+ printf("%s", inet_ntop(af, ptr, ipbuf, sizeof (ipbuf)));
+ printmask(np->in_v, (u_32_t *)&np->in_out[1]);
}
if (*np->in_plabel != '\0') {
printf(" proxy port ");
@@ -168,7 +177,7 @@ int opts;
else
fputs("???", stdout);
}
- printf(" %.*s/", (int)sizeof(np->in_plabel),
+ printf(" %.*s/", (int)sizeof (np->in_plabel),
np->in_plabel);
printproto(pr, np->in_p, NULL);
} else if (np->in_redir == NAT_MAPBLK) {
diff --git a/usr/src/cmd/ipf/tools/Makefile.tools b/usr/src/cmd/ipf/tools/Makefile.tools
index 65d3eb211b..4b171b1b6a 100644
--- a/usr/src/cmd/ipf/tools/Makefile.tools
+++ b/usr/src/cmd/ipf/tools/Makefile.tools
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#
@@ -36,8 +36,8 @@ IPMON_OBJS= ipmon.o ipmon_y.o ipmon_l.o
IPNAT_OBJS= ipnat.o ipnat_y.o ipnat_l.o
IPPOOL_OBJS= ippool.o ippool_y.o ippool_l.o
IPFTEST_OBJS= ipftest.o \
- ip_fil.o ip_state.o \
- ip_frag.o ip_nat.o fil.o \
+ ip_fil.o ip_state.o ip_compat.o \
+ ip_frag.o ip_nat.o ip_nat6.o fil.o \
ip_htable.o ip_lookup.o \
ip_proxy.o ip_auth.o ip_log.o \
ipf_y.o ipf_l.o \
diff --git a/usr/src/cmd/ipf/tools/ip_fil.c b/usr/src/cmd/ipf/tools/ip_fil.c
index 52fa867504..bbdb57802a 100644
--- a/usr/src/cmd/ipf/tools/ip_fil.c
+++ b/usr/src/cmd/ipf/tools/ip_fil.c
@@ -3,7 +3,7 @@
*
* See the IPFILTER.LICENCE file for details on licencing.
*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -479,7 +479,8 @@ ipf_stack_t *ifs;
f->fr_ifa = (void *)-1;
#endif
RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
- fr_natifpsync(IPFSYNC_OLDIFP, ifp, NULL, ifs);
+ fr_natifpsync(IPFSYNC_OLDIFP, 4, ifp, NULL, ifs);
+ fr_natifpsync(IPFSYNC_OLDIFP, 6, ifp, NULL, ifs);
}
diff --git a/usr/src/cmd/ipf/tools/ipmon.c b/usr/src/cmd/ipf/tools/ipmon.c
index 0cacc6ce54..e9d37720ef 100644
--- a/usr/src/cmd/ipf/tools/ipmon.c
+++ b/usr/src/cmd/ipf/tools/ipmon.c
@@ -1,9 +1,9 @@
/*
- * Copyright (C) 1993-2001, 2003 by Darren Reed.
+ * Copyright (C) 2001-2008 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -737,49 +737,52 @@ int blen;
}
(void) strftime(t, len, "%T", tm);
t += strlen(t);
- (void) sprintf(t, ".%-.6ld @%hd ", ipl->ipl_usec, nl->nl_rule + 1);
+ (void) sprintf(t, ".%-.6ld @%hd ", ipl->ipl_usec, nl->nlg_rule + 1);
t += strlen(t);
- if (nl->nl_type == NL_NEWMAP)
+ if (nl->nlg_type == NL_NEWMAP)
strcpy(t, "NAT:MAP ");
- else if (nl->nl_type == NL_NEWRDR)
+ else if (nl->nlg_type == NL_NEWRDR)
strcpy(t, "NAT:RDR ");
- else if (nl->nl_type == NL_FLUSH)
+ else if (nl->nlg_type == NL_FLUSH)
strcpy(t, "NAT:FLUSH ");
- else if (nl->nl_type == NL_EXPIRE)
+ else if (nl->nlg_type == NL_EXPIRE)
strcpy(t, "NAT:EXPIRE ");
- else if (nl->nl_type == NL_NEWBIMAP)
+ else if (nl->nlg_type == NL_NEWBIMAP)
strcpy(t, "NAT:BIMAP ");
- else if (nl->nl_type == NL_NEWBLOCK)
+ else if (nl->nlg_type == NL_NEWBLOCK)
strcpy(t, "NAT:MAPBLOCK ");
- else if (nl->nl_type == NL_CLONE)
+ else if (nl->nlg_type == NL_CLONE)
strcpy(t, "NAT:CLONE ");
else
- sprintf(t, "Type: %d ", nl->nl_type);
+ sprintf(t, "Type: %d ", nl->nlg_type);
t += strlen(t);
- proto = getproto(nl->nl_p);
+ proto = getproto(nl->nlg_p);
- (void) sprintf(t, "%s,%s <- -> ", HOSTNAME_V4(res, nl->nl_inip),
- portname(res, proto, (u_int)nl->nl_inport));
+ (void) sprintf(t, "%s,%s <- -> ", hostname(res, nl->nlg_v,
+ (u_32_t *)&nl->nlg_inip),
+ portname(res, proto, (u_int)nl->nlg_inport));
t += strlen(t);
- (void) sprintf(t, "%s,%s ", HOSTNAME_V4(res, nl->nl_outip),
- portname(res, proto, (u_int)nl->nl_outport));
+ (void) sprintf(t, "%s,%s ", hostname(res, nl->nlg_v,
+ (u_32_t *)&nl->nlg_outip),
+ portname(res, proto, (u_int)nl->nlg_outport));
t += strlen(t);
- (void) sprintf(t, "[%s,%s]", HOSTNAME_V4(res, nl->nl_origip),
- portname(res, proto, (u_int)nl->nl_origport));
+ (void) sprintf(t, "[%s,%s]", hostname(res, nl->nlg_v,
+ (u_32_t *)&nl->nlg_origip),
+ portname(res, proto, (u_int)nl->nlg_origport));
t += strlen(t);
- if (nl->nl_type == NL_EXPIRE) {
+ if (nl->nlg_type == NL_EXPIRE) {
#ifdef USE_QUAD_T
(void) sprintf(t, " Pkts %qd/%qd Bytes %qd/%qd",
- (long long)nl->nl_pkts[0],
- (long long)nl->nl_pkts[1],
- (long long)nl->nl_bytes[0],
- (long long)nl->nl_bytes[1]);
+ (long long)nl->nlg_pkts[0],
+ (long long)nl->nlg_pkts[1],
+ (long long)nl->nlg_bytes[0],
+ (long long)nl->nlg_bytes[1]);
#else
(void) sprintf(t, " Pkts %ld/%ld Bytes %ld/%ld",
- nl->nl_pkts[0], nl->nl_pkts[1],
- nl->nl_bytes[0], nl->nl_bytes[1]);
+ nl->nlg_pkts[0], nl->nlg_pkts[1],
+ nl->nlg_bytes[0], nl->nlg_bytes[1]);
#endif
t += strlen(t);
}
diff --git a/usr/src/cmd/ipf/tools/ipnat_y.y b/usr/src/cmd/ipf/tools/ipnat_y.y
index 48ca425c4f..cab9d6d3c5 100644
--- a/usr/src/cmd/ipf/tools/ipnat_y.y
+++ b/usr/src/cmd/ipf/tools/ipnat_y.y
@@ -1,10 +1,10 @@
%{
/*
- * Copyright (C) 2003 by Darren Reed.
+ * Copyright (C) 2001-2008 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -66,13 +66,15 @@ static addfunc_t nataddfunc = NULL;
static void newnatrule __P((void));
static void setnatproto __P((int));
-static u_32_t lookuphost __P((char *));
%}
%union {
char *str;
u_32_t num;
- struct in_addr ipa;
+ struct {
+ i6addr_t a;
+ int v;
+ } ipa;
frentry_t fr;
frtuc_t *frt;
u_short port;
@@ -82,8 +84,9 @@ static u_32_t lookuphost __P((char *));
int pc;
} pc;
struct {
- struct in_addr a;
- struct in_addr m;
+ i6addr_t a;
+ i6addr_t m;
+ int v;
} ipp;
union i6addr ip6;
};
@@ -102,8 +105,9 @@ static u_32_t lookuphost __P((char *));
%token IPNY_TLATE
%type <port> portspec
%type <num> hexnumber compare range proto
-%type <ipa> hostname ipv4
-%type <ipp> addr nummask rhaddr
+%type <num> saddr daddr sobject dobject mapfrom rdrfrom dip
+%type <ipa> hostname ipv4 ipaddr
+%type <ipp> addr rhaddr
%type <pc> portstuff
%%
file: line
@@ -113,6 +117,8 @@ file: line
;
line: xx rule { while ((nat = nattop) != NULL) {
+ if (nat->in_v == 0)
+ nat->in_v = 4;
nattop = nat->in_next;
(*nataddfunc)(natfd, natioctlfunc, nat);
free(nat);
@@ -145,11 +151,12 @@ eol: | ';'
;
map: mapit ifnames addr IPNY_TLATE rhaddr proxy mapoptions
- { nat->in_v = 4;
- nat->in_inip = $3.a.s_addr;
- nat->in_inmsk = $3.m.s_addr;
- nat->in_outip = $5.a.s_addr;
- nat->in_outmsk = $5.m.s_addr;
+ { if ($3.v != 0 && $3.v != $5.v && $5.v != 0)
+ yyerror("1.address family mismatch");
+ bcopy(&$3.a, &nat->in_in[0], sizeof($3.a));
+ bcopy(&$3.m, &nat->in_in[1], sizeof($3.a));
+ bcopy(&$5.a, &nat->in_out[0], sizeof($5.a));
+ bcopy(&$5.m, &nat->in_out[1], sizeof($5.a));
if (nat->in_ifnames[1][0] == '\0')
strncpy(nat->in_ifnames[1],
nat->in_ifnames[0],
@@ -161,11 +168,12 @@ map: mapit ifnames addr IPNY_TLATE rhaddr proxy mapoptions
nat_setgroupmap(nat);
}
| mapit ifnames addr IPNY_TLATE rhaddr mapport mapoptions
- { nat->in_v = 4;
- nat->in_inip = $3.a.s_addr;
- nat->in_inmsk = $3.m.s_addr;
- nat->in_outip = $5.a.s_addr;
- nat->in_outmsk = $5.m.s_addr;
+ { if ($3.v != 0 && $3.v != $5.v && $5.v != 0)
+ yyerror("2.address family mismatch");
+ bcopy(&$3.a, &nat->in_in[0], sizeof($3.a));
+ bcopy(&$3.m, &nat->in_in[1], sizeof($3.a));
+ bcopy(&$5.a, &nat->in_out[0], sizeof($5.a));
+ bcopy(&$5.m, &nat->in_out[1], sizeof($5.a));
if (nat->in_ifnames[1][0] == '\0')
strncpy(nat->in_ifnames[1],
nat->in_ifnames[0],
@@ -177,9 +185,10 @@ map: mapit ifnames addr IPNY_TLATE rhaddr proxy mapoptions
nat_setgroupmap(nat);
}
| mapit ifnames mapfrom IPNY_TLATE rhaddr proxy mapoptions
- { nat->in_v = 4;
- nat->in_outip = $5.a.s_addr;
- nat->in_outmsk = $5.m.s_addr;
+ { if ($3 != 0 && $3 != $5.v && $5.v != 0)
+ yyerror("3.address family mismatch");
+ bcopy(&$5.a, &nat->in_out[0], sizeof($5.a));
+ bcopy(&$5.m, &nat->in_out[1], sizeof($5.a));
if (nat->in_ifnames[1][0] == '\0')
strncpy(nat->in_ifnames[1],
nat->in_ifnames[0],
@@ -191,9 +200,10 @@ map: mapit ifnames addr IPNY_TLATE rhaddr proxy mapoptions
nat_setgroupmap(nat);
}
| mapit ifnames mapfrom IPNY_TLATE rhaddr mapport mapoptions
- { nat->in_v = 4;
- nat->in_outip = $5.a.s_addr;
- nat->in_outmsk = $5.m.s_addr;
+ { if ($3 != 0 && $3 != $5.v && $5.v != 0)
+ yyerror("4.address family mismatch");
+ bcopy(&$5.a, &nat->in_out[0], sizeof($5.a));
+ bcopy(&$5.m, &nat->in_out[1], sizeof($5.a));
if (nat->in_ifnames[1][0] == '\0')
strncpy(nat->in_ifnames[1],
nat->in_ifnames[0],
@@ -208,11 +218,12 @@ map: mapit ifnames addr IPNY_TLATE rhaddr proxy mapoptions
mapblock:
mapblockit ifnames addr IPNY_TLATE addr ports mapoptions
- { nat->in_v = 4;
- nat->in_inip = $3.a.s_addr;
- nat->in_inmsk = $3.m.s_addr;
- nat->in_outip = $5.a.s_addr;
- nat->in_outmsk = $5.m.s_addr;
+ { if ($3.v != 0 && $3.v != $5.v && $5.v != 0)
+ yyerror("5.address family mismatch");
+ bcopy(&$3.a, &nat->in_in[0], sizeof($3.a));
+ bcopy(&$3.m, &nat->in_in[1], sizeof($3.a));
+ bcopy(&$5.a, &nat->in_out[0], sizeof($5.a));
+ bcopy(&$5.m, &nat->in_out[1], sizeof($5.a));
if (nat->in_ifnames[1][0] == '\0')
strncpy(nat->in_ifnames[1],
nat->in_ifnames[0],
@@ -226,9 +237,10 @@ mapblock:
;
redir: rdrit ifnames addr dport IPNY_TLATE dip nport setproto rdroptions
- { nat->in_v = 4;
- nat->in_outip = $3.a.s_addr;
- nat->in_outmsk = $3.m.s_addr;
+ { if ($6 != 0 && $3.v != 0 && $6 != $3.v)
+ yyerror("6.address family mismatch");
+ bcopy(&$3.a, &nat->in_out[0], sizeof($3.a));
+ bcopy(&$3.m, &nat->in_out[1], sizeof($3.a));
if (nat->in_ifnames[1][0] == '\0')
strncpy(nat->in_ifnames[1],
nat->in_ifnames[0],
@@ -241,7 +253,8 @@ redir: rdrit ifnames addr dport IPNY_TLATE dip nport setproto rdroptions
setnatproto(IPPROTO_TCP);
}
| rdrit ifnames rdrfrom IPNY_TLATE dip nport setproto rdroptions
- { nat->in_v = 4;
+ { if ($5 != 0 && $3 != 0 && $5 != $3)
+ yyerror("7.address family mismatch");
if ((nat->in_p == 0) &&
((nat->in_flags & IPN_TCPUDP) == 0) &&
(nat->in_pmin != 0 ||
@@ -254,9 +267,10 @@ redir: rdrit ifnames addr dport IPNY_TLATE dip nport setproto rdroptions
sizeof(nat->in_ifnames[0]));
}
| rdrit ifnames addr IPNY_TLATE dip setproto rdroptions
- { nat->in_v = 4;
- nat->in_outip = $3.a.s_addr;
- nat->in_outmsk = $3.m.s_addr;
+ { if ($5 != 0 && $3.v != 0 && $5 != $3.v)
+ yyerror("8.address family mismatch");
+ bcopy(&$3.a, &nat->in_out[0], sizeof($3.a));
+ bcopy(&$3.m, &nat->in_out[1], sizeof($3.a));
if (nat->in_ifnames[1][0] == '\0')
strncpy(nat->in_ifnames[1],
nat->in_ifnames[0],
@@ -307,23 +321,77 @@ setproto:
}
;
-rhaddr: addr { $$.a = $1.a; $$.m = $1.m; }
- | IPNY_RANGE ipv4 '-' ipv4
- { $$.a = $2; $$.m = $4;
- nat->in_flags |= IPN_IPRANGE; }
+rhaddr: addr { $$.a = $1.a;
+ $$.m = $1.m;
+ $$.v = $1.v;
+ if ($$.v == 0)
+ $$.v = nat->in_v;
+ yyexpectaddr = 0; }
+ | IPNY_RANGE hostname '-' hostname
+ { if ($2.v != 0 && $4.v != 0 && $4.v != $2.v)
+ yyerror("9.address family "
+ "mismatch");
+ $$.v = $2.v;
+ $$.a = $2.a;
+ $$.m = $4.a;
+ nat->in_flags |= IPN_IPRANGE;
+ yyexpectaddr = 0; }
;
dip:
- hostname { nat->in_inip = $1.s_addr;
- nat->in_inmsk = 0xffffffff; }
- | hostname '/' YY_NUMBER { nat->in_inip = $1.s_addr;
- if (nat->in_inip != 0 ||
- ($3 != 0 && $3 != 32))
+ hostname { bcopy(&$1.a, &nat->in_in[0],
+ sizeof($1.a));
+ if ($1.v == 0)
+ $1.v = nat->in_v;
+ if ($1.v == 4) {
+ nat->in_inmsk = 0xffffffff;
+ } else {
+ nat->in_in[1].i6[0] = 0xffffffff;
+ nat->in_in[1].i6[1] = 0xffffffff;
+ nat->in_in[1].i6[2] = 0xffffffff;
+ nat->in_in[1].i6[3] = 0xffffffff;
+ }
+ $$ = $1.v;
+ }
+ | hostname '/' YY_NUMBER { if ($1.v == 0)
+ $1.v = nat->in_v;
+ if ($1.v == 4 &&
+ ($1.a.in4.s_addr != 0 ||
+ ($3 != 0 && $3 != 32)))
+ yyerror("Invalid mask for dip");
+ else if ($1.v == 6 &&
+ ($1.a.in4.s_addr != 0 ||
+ ($3 != 0 && $3 != 128)))
yyerror("Invalid mask for dip");
- ntomask(4, $3, &nat->in_inmsk); }
- | hostname ',' hostname { nat->in_flags |= IPN_SPLIT;
- nat->in_inip = $1.s_addr;
- nat->in_inmsk = $3.s_addr; }
+ else if ($1.v == 0 ) {
+ if ($1.a.in4.s_addr == 0 &&
+ ($3 == 32 || $3 == 0))
+ $1.v = 4;
+ else if ($3 == 128)
+ $1.v = 6;
+ }
+ bcopy(&$1.a, &nat->in_in[0],
+ sizeof($1.a));
+ ntomask($1.v, $3,
+ (u_32_t *)&nat->in_in[1]);
+ nat->in_in[0].i6[0] &= nat->in_in[1].i6[0];
+ nat->in_in[0].i6[0] &= nat->in_in[1].i6[1];
+ nat->in_in[0].i6[0] &= nat->in_in[1].i6[2];
+ nat->in_in[0].i6[0] &= nat->in_in[1].i6[3];
+ nat->in_v = $1.v;
+ $$ = $1.v;
+ }
+ | hostname ',' { yyexpectaddr = 1; } hostname
+ { if ($1.v != $4.v)
+ yyerror("10.address family "
+ "mismatch");
+ $$ = $1.v;
+ nat->in_flags |= IPN_SPLIT;
+ bcopy(&$1.a, &nat->in_in[0],
+ sizeof($1.a));
+ bcopy(&$4.a, &nat->in_in[1],
+ sizeof($4.a));
+ yyexpectaddr = 0; }
;
portspec:
@@ -368,23 +436,42 @@ mapblockit:
;
mapfrom:
- from sobject IPNY_TO dobject
+ from sobject IPNY_TO dobject { if ($2 != 0 && $4 != 0 && $2 != $4)
+ yyerror("11.address family "
+ "mismatch");
+ $$ = $2;
+ }
| from sobject '!' IPNY_TO dobject
- { nat->in_flags |= IPN_NOTDST; }
+ { if ($2 != 0 && $5 != 0 && $2 != $5)
+ yyerror("12.address family "
+ "mismatch");
+ nat->in_flags |= IPN_NOTDST;
+ $$ = $2;
+ }
;
rdrfrom:
- from sobject IPNY_TO dobject
+ from sobject IPNY_TO dobject { if ($2 != 0 && $4 != 0 && $2 != $4)
+ yyerror("13.address family "
+ "mismatch");
+ $$ = $2;
+ }
| '!' from sobject IPNY_TO dobject
- { nat->in_flags |= IPN_NOTSRC; }
+ { if ($3 != 0 && $5 != 0 && $3 != $5)
+ yyerror("14.address family "
+ "mismatch");
+ nat->in_flags |= IPN_NOTSRC;
+ $$ = $3;
+ }
;
-from: IPNY_FROM { nat->in_flags |= IPN_FILTER; }
+from: IPNY_FROM { nat->in_flags |= IPN_FILTER;
+ yyexpectaddr = 1; }
;
ifnames:
- ifname
- | ifname ',' otherifname
+ ifname { yyexpectaddr = 1; }
+ | ifname ',' otherifname { yyexpectaddr = 1; }
;
ifname: YY_STR { strncpy(nat->in_ifnames[0], $1,
@@ -428,24 +515,31 @@ mapport:
;
sobject:
- saddr
+ saddr { $$ = $1; }
| saddr IPNY_PORT portstuff { nat->in_sport = $3.p1;
nat->in_stop = $3.p2;
- nat->in_scmp = $3.pc; }
+ nat->in_scmp = $3.pc;
+ $$ = $1;
+ }
;
saddr: addr { if (nat->in_redir == NAT_REDIRECT) {
- nat->in_srcip = $1.a.s_addr;
- nat->in_srcmsk = $1.m.s_addr;
+ bcopy(&$1.a, &nat->in_src[0],
+ sizeof($1.a));
+ bcopy(&$1.m, &nat->in_src[1],
+ sizeof($1.a));
} else {
- nat->in_inip = $1.a.s_addr;
- nat->in_inmsk = $1.m.s_addr;
+ bcopy(&$1.a, &nat->in_in[0],
+ sizeof($1.a));
+ bcopy(&$1.m, &nat->in_in[1],
+ sizeof($1.a));
}
+ $$ = $1.v;
}
;
dobject:
- daddr
+ daddr { $$ = $1; }
| daddr IPNY_PORT portstuff { nat->in_dport = $3.p1;
nat->in_dtop = $3.p2;
nat->in_dcmp = $3.pc;
@@ -455,33 +549,93 @@ dobject:
;
daddr: addr { if (nat->in_redir == NAT_REDIRECT) {
- nat->in_outip = $1.a.s_addr;
- nat->in_outmsk = $1.m.s_addr;
+ bcopy(&$1.a, &nat->in_out[0],
+ sizeof($1.a));
+ bcopy(&$1.m, &nat->in_out[1],
+ sizeof($1.a));
} else {
- nat->in_srcip = $1.a.s_addr;
- nat->in_srcmsk = $1.m.s_addr;
+ bcopy(&$1.a, &nat->in_src[0],
+ sizeof($1.a));
+ bcopy(&$1.m, &nat->in_src[1],
+ sizeof($1.a));
}
+ $$ = $1.v;
}
;
-addr: IPNY_ANY { $$.a.s_addr = 0; $$.m.s_addr = 0; }
- | nummask { $$.a = $1.a; $$.m = $1.m;
- $$.a.s_addr &= $$.m.s_addr; }
- | hostname '/' ipv4 { $$.a = $1; $$.m = $3;
- $$.a.s_addr &= $$.m.s_addr; }
- | hostname '/' hexnumber { $$.a = $1; $$.m.s_addr = $3;
- $$.a.s_addr &= $$.m.s_addr; }
- | hostname IPNY_MASK ipv4 { $$.a = $1; $$.m = $3;
- $$.a.s_addr &= $$.m.s_addr; }
- | hostname IPNY_MASK hexnumber { $$.a = $1; $$.m.s_addr = $3;
- $$.a.s_addr &= $$.m.s_addr; }
- ;
-
-nummask:
- hostname { $$.a = $1;
- $$.m.s_addr = 0xffffffff; }
- | hostname '/' YY_NUMBER { $$.a = $1;
- ntomask(4, $3, &$$.m.s_addr); }
+addr: IPNY_ANY { yyexpectaddr = 0;
+ bzero(&$$.a, sizeof($$.a));
+ bzero(&$$.m, sizeof($$.a));
+ $$.v = nat->in_v;
+ }
+ | hostname { $$.a = $1.a;
+ $$.v = $1.v;
+ if ($$.v == 4) {
+ $$.m.in4.s_addr = 0xffffffff;
+ } else {
+ $$.m.i6[0] = 0xffffffff;
+ $$.m.i6[1] = 0xffffffff;
+ $$.m.i6[2] = 0xffffffff;
+ $$.m.i6[3] = 0xffffffff;
+ }
+ yyexpectaddr = 0;
+ }
+ | hostname '/' YY_NUMBER { $$.a = $1.a;
+ if ($1.v == 0) {
+ if ($1.a.in4.s_addr != 0)
+ yyerror("invalid addr");
+ if ($3 == 0 || $3 == 32)
+ $1.v = 4;
+ else if ($3 == 128)
+ $1.v = 6;
+ else
+ yyerror("invalid mask");
+ nat->in_v = $1.v;
+ }
+ ntomask($1.v, $3, (u_32_t *)&$$.m);
+ $$.a.i6[0] &= $$.m.i6[0];
+ $$.a.i6[1] &= $$.m.i6[1];
+ $$.a.i6[2] &= $$.m.i6[2];
+ $$.a.i6[3] &= $$.m.i6[3];
+ $$.v = $1.v;
+ yyexpectaddr = 0;
+ }
+ | hostname '/' ipaddr { if ($1.v != $3.v) {
+ yyerror("1.address family "
+ "mismatch");
+ }
+ $$.a = $1.a;
+ $$.m = $3.a;
+ $$.a.i6[0] &= $$.m.i6[0];
+ $$.a.i6[1] &= $$.m.i6[1];
+ $$.a.i6[2] &= $$.m.i6[2];
+ $$.a.i6[3] &= $$.m.i6[3];
+ $$.v = $1.v;
+ yyexpectaddr = 0;
+ }
+ | hostname '/' hexnumber { $$.a = $1.a;
+ $$.m.in4.s_addr = htonl($3);
+ $$.a.in4.s_addr &= $$.m.in4.s_addr;
+ $$.v = 4;
+ }
+ | hostname IPNY_MASK ipaddr { if ($1.v != $3.v) {
+ yyerror("2.address family "
+ "mismatch");
+ }
+ $$.a = $1.a;
+ $$.m = $3.a;
+ $$.a.i6[0] &= $$.m.i6[0];
+ $$.a.i6[1] &= $$.m.i6[1];
+ $$.a.i6[2] &= $$.m.i6[2];
+ $$.a.i6[3] &= $$.m.i6[3];
+ $$.v = $1.v;
+ yyexpectaddr = 0;
+ }
+ | hostname IPNY_MASK hexnumber { $$.a = $1.a;
+ $$.m.in4.s_addr = htonl($3);
+ $$.a.in4.s_addr &= $$.m.in4.s_addr;
+ $$.v = 4;
+ }
;
portstuff:
@@ -562,13 +716,40 @@ hexnumber:
;
hostname:
- YY_STR { $$.s_addr = lookuphost($1);
- free($1);
- if ($$.s_addr == 0)
+ YY_STR { i6addr_t addr;
+ if (gethost($1, &addr, 0) == 0) {
+ $$.a = addr;
+ $$.v = 4;
+ } else
+ if (gethost($1, &addr, 1) == 0) {
+ $$.a = addr;
+ $$.v = 6;
+ } else {
yyerror("Unknown hostname");
+ }
+ if ($$.v != 0)
+ nat->in_v = $$.v;
+ free($1);
+ }
+ | YY_NUMBER { bzero(&$$.a, sizeof($$.a));
+ $$.a.in4.s_addr = htonl($1);
+ if ($$.a.in4.s_addr != 0)
+ $$.v = 4;
+ else
+ $$.v = nat->in_v;
+ if ($$.v != 0)
+ nat->in_v = $$.v;
+ }
+ | ipv4 { $$ = $1;
+ nat->in_v = 4;
+ }
+ | YY_IPV6 { $$.a = $1;
+ $$.v = 6;
+ nat->in_v = 6;
+ }
+ | YY_NUMBER YY_IPV6 { $$.a = $2;
+ $$.v = 6;
}
- | YY_NUMBER { $$.s_addr = htonl($1); }
- | ipv4 { $$.s_addr = $1.s_addr; }
;
compare:
@@ -585,13 +766,20 @@ range:
| YY_RANGE_IN { $$ = FR_INRANGE; }
;
+ipaddr: ipv4 { $$ = $1; }
+ | YY_IPV6 { $$.a = $1;
+ $$.v = 6;
+ }
+ ;
+
ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
{ if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
yyerror("Invalid octet string for IP address");
return 0;
}
- $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
- $$.s_addr = htonl($$.s_addr);
+ $$.a.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
+ $$.a.in4.s_addr = htonl($$.a.in4.s_addr);
+ $$.v = 4;
}
;
@@ -844,13 +1032,3 @@ void *ptr;
}
}
-static u_32_t lookuphost(name)
-char *name;
-{
- i6addr_t addr;
-
- if (gethost(name, &addr, 0) == -1) {
- return 0;
- }
- return addr.in4_addr;
-}
diff --git a/usr/src/cmd/ipf/tools/lexer.c b/usr/src/cmd/ipf/tools/lexer.c
index 39975a55ce..3b74edee90 100644
--- a/usr/src/cmd/ipf/tools/lexer.c
+++ b/usr/src/cmd/ipf/tools/lexer.c
@@ -1,9 +1,9 @@
/*
- * Copyright (C) 2004 by Darren Reed.
+ * Copyright (C) 2002-2008 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -398,7 +398,7 @@ nextchar:
* 0000:0000:0000:0000:0000:0000:0000:0000
*/
#ifdef USE_INET6
- if (yyexpectaddr == 1 && isbuilding == 0 && (ishex(c) || c == ':')) {
+ if (isbuilding == 0 && (ishex(c) || c == ':')) {
char ipv6buf[45 + 1], *s, oc;
int start;
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index dabf3c5035..c91ad888ce 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -1469,7 +1469,7 @@ PHX_OBJS += phx.o
IPF_OBJS += ip_fil_solaris.o fil.o solaris.o ip_state.o ip_frag.o ip_nat.o \
ip_proxy.o ip_auth.o ip_pool.o ip_htable.o ip_lookup.o \
- ip_log.o misc.o
+ ip_log.o misc.o ip_compat.o ip_nat6.o
IBD_OBJS += ibd.o
diff --git a/usr/src/uts/common/inet/ipf/fil.c b/usr/src/uts/common/inet/ipf/fil.c
index f38a3a23a2..7cdedaaa4b 100644
--- a/usr/src/uts/common/inet/ipf/fil.c
+++ b/usr/src/uts/common/inet/ipf/fil.c
@@ -222,7 +222,6 @@ static void *fr_ifsync __P((int, int, char *, char *,
void *, void *, ipf_stack_t *));
static ipftuneable_t *fr_findtunebyname __P((const char *, ipf_stack_t *));
static ipftuneable_t *fr_findtunebycookie __P((void *, void **, ipf_stack_t *));
-static void ipf_unlinktoken __P((ipftoken_t *, ipf_stack_t *));
/*
@@ -696,10 +695,15 @@ fr_info_t *fin;
fin->fin_data[0] = *(u_short *)icmp6;
+ if ((icmp6->icmp6_type & ICMP6_INFOMSG_MASK) != 0)
+ fin->fin_flx |= FI_ICMPQUERY;
+
switch (icmp6->icmp6_type)
{
case ICMP6_ECHO_REPLY :
case ICMP6_ECHO_REQUEST :
+ if (fin->fin_dlen >= 6)
+ fin->fin_data[1] = icmp6->icmp6_id;
minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t);
break;
case ICMP6_DST_UNREACH :
@@ -2465,9 +2469,24 @@ ipf_stack_t *ifs;
*/
fr = fr_checkauth(fin, &pass);
if (!out) {
- if (fr_checknatin(fin, &pass) == -1) {
- RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
- goto finished;
+ switch (fin->fin_v)
+ {
+ case 4 :
+ if (fr_checknatin(fin, &pass) == -1) {
+ RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
+ goto finished;
+ }
+ break;
+#ifdef USE_INET6
+ case 6 :
+ if (fr_checknat6in(fin, &pass) == -1) {
+ RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
+ goto finished;
+ }
+ break;
+#endif
+ default :
+ break;
}
}
if (!out)
@@ -2491,10 +2510,27 @@ ipf_stack_t *ifs;
if (out && FR_ISPASS(pass)) {
(void) fr_acctpkt(fin, NULL);
- if (fr_checknatout(fin, &pass) == -1) {
- RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
- goto finished;
- } else if ((ifs->ifs_fr_update_ipid != 0) && (v == 4)) {
+ switch (fin->fin_v)
+ {
+ case 4 :
+ if (fr_checknatout(fin, &pass) == -1) {
+ RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
+ goto finished;
+ }
+ break;
+#ifdef USE_INET6
+ case 6 :
+ if (fr_checknat6out(fin, &pass) == -1) {
+ RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
+ goto finished;
+ }
+ break;
+#endif
+ default :
+ break;
+ }
+
+ if ((ifs->ifs_fr_update_ipid != 0) && (v == 4)) {
if (fr_updateipid(fin) == -1) {
IPF_BUMP(ifs->ifs_frstats[1].fr_ipud);
pass &= ~FR_CMDMASK;
@@ -5405,15 +5441,14 @@ int type;
} else if (obj.ipfo_size != fr_objbytes[type][1])
return EINVAL;
#else
- if (obj.ipfo_rev != IPFILTER_VERSION)
- /* XXX compatibility hook here */
- ;
- if ((fr_objbytes[type][0] & 1) != 0) {
- if (obj.ipfo_size < fr_objbytes[type][1])
- /* XXX compatibility hook here */
- return EINVAL;
- } else if (obj.ipfo_size != fr_objbytes[type][1])
- /* XXX compatibility hook here */
+ if (obj.ipfo_rev != IPFILTER_VERSION) {
+ error = fr_incomptrans(&obj, ptr);
+ return error;
+ }
+
+ if ((fr_objbytes[type][0] & 1) != 0 &&
+ obj.ipfo_size < fr_objbytes[type][1] ||
+ obj.ipfo_size != fr_objbytes[type][1])
return EINVAL;
#endif
@@ -5465,8 +5500,8 @@ int type, sz;
return EINVAL;
#else
if (obj.ipfo_rev != IPFILTER_VERSION)
- /* XXX compatibility hook here */
- ;
+ /*XXX compatibility hook here */
+ /*EMPTY*/;
if (obj.ipfo_size != sz)
/* XXX compatibility hook here */
return EINVAL;
@@ -5515,7 +5550,7 @@ int type, sz;
#else
if (obj.ipfo_rev != IPFILTER_VERSION)
/* XXX compatibility hook here */
- ;
+ /*EMPTY*/;
if (obj.ipfo_size != sz)
/* XXX compatibility hook here */
return EINVAL;
@@ -5560,15 +5595,14 @@ int type;
} else if (obj.ipfo_size != fr_objbytes[type][1])
return EINVAL;
#else
- if (obj.ipfo_rev != IPFILTER_VERSION)
- /* XXX compatibility hook here */
- ;
- if ((fr_objbytes[type][0] & 1) != 0) {
- if (obj.ipfo_size < fr_objbytes[type][1])
- /* XXX compatibility hook here */
- return EINVAL;
- } else if (obj.ipfo_size != fr_objbytes[type][1])
- /* XXX compatibility hook here */
+ if (obj.ipfo_rev != IPFILTER_VERSION) {
+ error = fr_outcomptrans(&obj, ptr);
+ return error;
+ }
+
+ if ((fr_objbytes[type][0] & 1) != 0 &&
+ obj.ipfo_size < fr_objbytes[type][1] ||
+ obj.ipfo_size != fr_objbytes[type][1])
return EINVAL;
#endif
diff --git a/usr/src/uts/common/inet/ipf/ip_compat.c b/usr/src/uts/common/inet/ipf/ip_compat.c
new file mode 100644
index 0000000000..8d75fadda0
--- /dev/null
+++ b/usr/src/uts/common/inet/ipf/ip_compat.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#if defined(KERNEL) || defined(_KERNEL)
+# undef KERNEL
+# undef _KERNEL
+# define KERNEL 1
+# define _KERNEL 1
+#endif
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#if defined(__NetBSD__)
+# if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL)
+# include "opt_ipfilter_log.h"
+# endif
+#endif
+#if defined(_KERNEL) && defined(__FreeBSD_version) && \
+ (__FreeBSD_version >= 220000)
+# if (__FreeBSD_version >= 400000)
+# if !defined(IPFILTER_LKM)
+# include "opt_inet6.h"
+# endif
+# if (__FreeBSD_version == 400019)
+# define CSUM_DELAY_DATA
+# endif
+# endif
+# include <sys/filio.h>
+#else
+# include <sys/ioctl.h>
+#endif
+#if !defined(_AIX51)
+# include <sys/fcntl.h>
+#endif
+#if defined(_KERNEL)
+# include <sys/systm.h>
+# include <sys/file.h>
+#else
+# include <stdio.h>
+# include <string.h>
+# include <stdlib.h>
+# include <stddef.h>
+# include <sys/file.h>
+# define _KERNEL
+# ifdef __OpenBSD__
+struct file;
+# endif
+# include <sys/uio.h>
+# undef _KERNEL
+#endif
+#if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux) && \
+ !defined(linux)
+# include <sys/mbuf.h>
+#else
+# if !defined(linux)
+# include <sys/byteorder.h>
+# endif
+# if (SOLARIS2 < 5) && defined(sun)
+# include <sys/dditypes.h>
+# endif
+#endif
+#ifdef __hpux
+# define _NET_ROUTE_INCLUDED
+#endif
+#if !defined(linux)
+# include <sys/protosw.h>
+#endif
+#include <sys/socket.h>
+#include <net/if.h>
+#ifdef sun
+# include <net/af.h>
+#endif
+#if !defined(_KERNEL) && defined(__FreeBSD__)
+# include "radix_ipf.h"
+#endif
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#if !defined(linux)
+# include <netinet/ip_var.h>
+#endif
+#if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */
+# include <sys/hashing.h>
+# include <netinet/in_var.h>
+#endif
+#include <netinet/tcp.h>
+#if (!defined(__sgi) && !defined(AIX)) || defined(_KERNEL)
+# include <netinet/udp.h>
+# include <netinet/ip_icmp.h>
+#endif
+#ifdef __hpux
+# undef _NET_ROUTE_INCLUDED
+#endif
+#include "netinet/ip_compat.h"
+#ifdef USE_INET6
+# include <netinet/icmp6.h>
+# if !SOLARIS && defined(_KERNEL) && !defined(__osf__) && !defined(__hpux)
+# include <netinet6/in6_var.h>
+# endif
+#endif
+#include <netinet/tcpip.h>
+#include "netinet/ip_fil.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_frag.h"
+#include "netinet/ip_state.h"
+#include "netinet/ip_proxy.h"
+#include "netinet/ip_auth.h"
+#include "netinet/ipf_stack.h"
+#ifdef IPFILTER_SCAN
+# include "netinet/ip_scan.h"
+#endif
+#ifdef IPFILTER_SYNC
+# include "netinet/ip_sync.h"
+#endif
+#include "netinet/ip_pool.h"
+#include "netinet/ip_htable.h"
+#ifdef IPFILTER_COMPILED
+# include "netinet/ip_rules.h"
+#endif
+#if defined(IPFILTER_BPF) && defined(_KERNEL)
+# include <net/bpf.h>
+#endif
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
+# include <sys/malloc.h>
+# if defined(_KERNEL) && !defined(IPFILTER_LKM)
+# include "opt_ipfilter.h"
+# endif
+#endif
+#include "netinet/ipl.h"
+/* END OF INCLUDES */
+
+#ifdef IPFILTER_COMPAT
+
+# define IPFILTER_VERSION_4010900 4010900
+
+struct nat_4010900 {
+ ipfmutex_t nat_lock;
+ struct nat *nat_next;
+ struct nat **nat_pnext;
+ struct nat *nat_hnext[2];
+ struct nat **nat_phnext[2];
+ struct hostmap *nat_hm;
+ void *nat_data;
+ struct nat **nat_me;
+ struct ipstate *nat_state;
+ struct ap_session *nat_aps; /* proxy session */
+ frentry_t *nat_fr; /* filter rule ptr if appropriate */
+ struct ipnat *nat_ptr; /* pointer back to the rule */
+ void *nat_ifps[2];
+ void *nat_sync;
+ ipftqent_t nat_tqe;
+ u_32_t nat_flags;
+ u_32_t nat_sumd[2]; /* ip checksum delta for data segment */
+ u_32_t nat_ipsumd; /* ip checksum delta for ip header */
+ u_32_t nat_mssclamp; /* if != zero clamp MSS to this */
+ i6addr_t nat_inip6;
+ i6addr_t nat_outip6;
+ i6addr_t nat_oip6; /* other ip */
+ U_QUAD_T nat_pkts[2];
+ U_QUAD_T nat_bytes[2];
+ union {
+ udpinfo_t nat_unu;
+ tcpinfo_t nat_unt;
+ icmpinfo_t nat_uni;
+ greinfo_t nat_ugre;
+ } nat_un;
+ u_short nat_oport; /* other port */
+ u_short nat_use;
+ u_char nat_p; /* protocol for NAT */
+ int nat_dir;
+ int nat_ref; /* reference count */
+ int nat_hv[2];
+ char nat_ifnames[2][LIFNAMSIZ];
+ int nat_rev; /* 0 = forward, 1 = reverse */
+ int nat_redir;
+};
+
+struct nat_save_4010900 {
+ void *ipn_next;
+ struct nat_4010900 ipn_nat;
+ struct ipnat ipn_ipnat;
+ struct frentry ipn_fr;
+ int ipn_dsize;
+ char ipn_data[4];
+};
+
+struct natlookup_4010900 {
+ struct in_addr nlc_inip;
+ struct in_addr nlc_outip;
+ struct in_addr nlc_realip;
+ int nlc_flags;
+ u_short nlc_inport;
+ u_short nlc_outport;
+ u_short nlc_realport;
+};
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: fr_incomptrans */
+/* Returns: int - 0 = success, else failure */
+/* Parameters: obj(I) - pointer to ioctl data */
+/* ptr(I) - pointer to store real data in */
+/* */
+/* Translate the copied in ipfobj_t to new for backward compatibility at */
+/* the ABI for user land. */
+/* ------------------------------------------------------------------------ */
+int fr_incomptrans(obj, ptr)
+ipfobj_t *obj;
+void *ptr;
+{
+ int error;
+ natlookup_t *nlp;
+ nat_save_t *nsp;
+ struct nat_save_4010900 nsc;
+ struct natlookup_4010900 nlc;
+
+ switch (obj->ipfo_type)
+ {
+ case IPFOBJ_NATLOOKUP :
+ if ((obj->ipfo_rev != IPFILTER_VERSION_4010900) ||
+ (obj->ipfo_size != sizeof (nlc)))
+ return EINVAL;
+ error = COPYIN((caddr_t)obj->ipfo_ptr, (caddr_t)&nlc,
+ obj->ipfo_size);
+ if (!error) {
+ nlp = (natlookup_t *)ptr;
+ bzero((char *)nlp, sizeof (*nlp));
+ nlp->nl_inip = nlc.nlc_inip;
+ nlp->nl_outip = nlc.nlc_outip;
+ nlp->nl_inport = nlc.nlc_inport;
+ nlp->nl_outport = nlc.nlc_outport;
+ nlp->nl_flags = nlc.nlc_flags;
+ nlp->nl_v = 4;
+ }
+ break;
+ case IPFOBJ_NATSAVE :
+ if ((obj->ipfo_rev != IPFILTER_VERSION_4010900) ||
+ (obj->ipfo_size != sizeof (nsc)))
+ return EINVAL;
+ error = COPYIN((caddr_t)obj->ipfo_ptr, (caddr_t)&nsc,
+ obj->ipfo_size);
+ if (!error) {
+ nsp = (nat_save_t *)ptr;
+ bzero((char *)nsp, sizeof (*nsp));
+ nsp->ipn_next = nsc.ipn_next;
+ nsp->ipn_dsize = nsc.ipn_dsize;
+ nsp->ipn_nat.nat_inip = nsc.ipn_nat.nat_inip;
+ nsp->ipn_nat.nat_outip = nsc.ipn_nat.nat_outip;
+ nsp->ipn_nat.nat_oip = nsc.ipn_nat.nat_oip;
+ nsp->ipn_nat.nat_inport = nsc.ipn_nat.nat_inport;
+ nsp->ipn_nat.nat_outport = nsc.ipn_nat.nat_outport;
+ nsp->ipn_nat.nat_oport = nsc.ipn_nat.nat_oport;
+ nsp->ipn_nat.nat_flags = nsc.ipn_nat.nat_flags;
+ nsp->ipn_nat.nat_v = 4;
+ }
+ break;
+ default :
+ return EINVAL;
+ }
+ return error;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function: fr_outcomptrans */
+/* Returns: int - 0 = success, else failure */
+/* Parameters: obj(I) - pointer to ioctl data */
+/* ptr(I) - pointer to store real data in */
+/* */
+/* Translate the copied out ipfobj_t to new definition for backward */
+/* compatibility at the ABI for user land. */
+/* ------------------------------------------------------------------------ */
+int fr_outcomptrans(obj, ptr)
+ipfobj_t *obj;
+void *ptr;
+{
+ int error;
+ natlookup_t *nlp;
+ struct natlookup_4010900 nlc;
+
+ switch (obj->ipfo_type)
+ {
+ case IPFOBJ_NATLOOKUP :
+ if ((obj->ipfo_rev != IPFILTER_VERSION_4010900) ||
+ (obj->ipfo_size != sizeof (nlc)))
+ return EINVAL;
+ bzero((char *)&nlc, sizeof (nlc));
+ nlp = (natlookup_t *)ptr;
+ nlc.nlc_inip = nlp->nl_inip;
+ nlc.nlc_outip = nlp->nl_outip;
+ nlc.nlc_realip = nlp->nl_realip;
+ nlc.nlc_inport = nlp->nl_inport;
+ nlc.nlc_outport = nlp->nl_outport;
+ nlc.nlc_realport = nlp->nl_realport;
+ nlc.nlc_flags = nlp->nl_flags;
+ error = COPYOUT((caddr_t)&nlc, (caddr_t)obj->ipfo_ptr,
+ obj->ipfo_size);
+ break;
+ default :
+ return EINVAL;
+ }
+ return error;
+}
+
+#endif /* IPFILTER_COMPAT */
diff --git a/usr/src/uts/common/inet/ipf/ip_fil_solaris.c b/usr/src/uts/common/inet/ipf/ip_fil_solaris.c
index 36f374d586..ede4e0d639 100644
--- a/usr/src/uts/common/inet/ipf/ip_fil_solaris.c
+++ b/usr/src/uts/common/inet/ipf/ip_fil_solaris.c
@@ -733,8 +733,8 @@ int *rp;
WRITE_ENTER(&ifs->ifs_ipf_global);
frsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs);
- fr_natifpsync(IPFSYNC_RESYNC, NULL, NULL, ifs);
- fr_nataddrsync(NULL, NULL, ifs);
+ fr_natifpsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs);
+ fr_nataddrsync(0, NULL, NULL, ifs);
fr_statesync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs);
error = 0;
}
@@ -1010,8 +1010,8 @@ fr_info_t *fin;
if (fin->fin_v == 6) {
ip6 = (ip6_t *)m->b_rptr;
ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
- ip6->ip6_src = fin->fin_dst6;
- ip6->ip6_dst = fin->fin_src6;
+ ip6->ip6_src = fin->fin_dst6.in6;
+ ip6->ip6_dst = fin->fin_src6.in6;
ip6->ip6_plen = htons(sizeof(*tcp));
ip6->ip6_nxt = IPPROTO_TCP;
tcp2->th_sum = fr_cksum(m, (ip_t *)ip6, IPPROTO_TCP, tcp2);
@@ -1224,7 +1224,7 @@ int dst;
return -1;
}
} else
- dst6 = fin->fin_dst6;
+ dst6 = fin->fin_dst6.in6;
csz = sz;
sz -= sizeof(ip6_t);
@@ -1233,7 +1233,7 @@ int dst;
ip6->ip6_plen = htons((u_short)sz);
ip6->ip6_nxt = IPPROTO_ICMPV6;
ip6->ip6_src = dst6;
- ip6->ip6_dst = fin->fin_src6;
+ ip6->ip6_dst = fin->fin_src6.in6;
sz -= offsetof(struct icmp, icmp_ip);
bcopy((char *)mb->b_rptr, (char *)&icmp->icmp_ip, sz);
icmp->icmp_cksum = csz - sizeof(ip6_t);
@@ -2034,8 +2034,8 @@ int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info,
{
case NE_PLUMB :
frsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, hn->hne_data,
- ifs);
- fr_natifpsync(IPFSYNC_NEWIFP, (void *)hn->hne_nic,
+ ifs);
+ fr_natifpsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic,
hn->hne_data, ifs);
fr_statesync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic,
hn->hne_data, ifs);
@@ -2043,7 +2043,8 @@ int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info,
case NE_UNPLUMB :
frsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs);
- fr_natifpsync(IPFSYNC_OLDIFP, (void *)hn->hne_nic, NULL, ifs);
+ fr_natifpsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL,
+ ifs);
fr_statesync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs);
break;
@@ -2059,7 +2060,7 @@ int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info,
frsync(IPFSYNC_RESYNC, 4, (void *)hn->hne_nic, NULL,
ifs);
sin = hn->hne_data;
- fr_nataddrsync((void *)hn->hne_nic, &sin->sin_addr,
+ fr_nataddrsync(4, (void *)hn->hne_nic, &sin->sin_addr,
ifs);
}
break;
@@ -2084,6 +2085,7 @@ int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info,
int ipf_nic_event_v6(hook_event_token_t event, hook_data_t info,
netstack_t *ns)
{
+ struct sockaddr_in6 *sin6;
hook_nic_event_t *hn;
ipf_stack_t *ifs = ns->netstack_ipf;
@@ -2092,17 +2094,27 @@ int ipf_nic_event_v6(hook_event_token_t event, hook_data_t info,
switch (hn->hne_event)
{
case NE_PLUMB :
- frsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, hn->hne_data, ifs);
+ frsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic,
+ hn->hne_data, ifs);
+ fr_natifpsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic,
+ hn->hne_data, ifs);
fr_statesync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic,
hn->hne_data, ifs);
break;
case NE_UNPLUMB :
frsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs);
+ fr_natifpsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL,
+ ifs);
fr_statesync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs);
break;
case NE_ADDRESS_CHANGE :
+ if (hn->hne_lif == 1) {
+ sin6 = hn->hne_data;
+ fr_nataddrsync(6, (void *)hn->hne_nic, &sin6->sin6_addr,
+ ifs);
+ }
break;
default :
break;
diff --git a/usr/src/uts/common/inet/ipf/ip_nat.c b/usr/src/uts/common/inet/ipf/ip_nat.c
index 994a9eb034..2327c01d8c 100644
--- a/usr/src/uts/common/inet/ipf/ip_nat.c
+++ b/usr/src/uts/common/inet/ipf/ip_nat.c
@@ -145,8 +145,6 @@ static int nat_clearlist __P((ipf_stack_t *));
static void nat_addnat __P((struct ipnat *, ipf_stack_t *));
static void nat_addrdr __P((struct ipnat *, ipf_stack_t *));
static void nat_delete __P((struct nat *, int, ipf_stack_t *));
-static void nat_delrdr __P((struct ipnat *));
-static void nat_delnat __P((struct ipnat *));
static int fr_natgetent __P((caddr_t, ipf_stack_t *));
static int fr_natgetsz __P((caddr_t, ipf_stack_t *));
static int fr_natputent __P((caddr_t, int, ipf_stack_t *));
@@ -158,17 +156,14 @@ static hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr,
struct in_addr, struct in_addr, u_32_t,
ipf_stack_t *));
static INLINE int nat_icmpquerytype4 __P((int));
-static int nat_siocaddnat __P((ipnat_t *, ipnat_t **, int,
- ipf_stack_t *));
-static void nat_siocdelnat __P((ipnat_t *, ipnat_t **, int,
- ipf_stack_t *));
+static int nat_ruleaddrinit __P((ipnat_t *));
+static int nat_siocaddnat __P((ipnat_t *, ipnat_t **, int, ipf_stack_t *));
+static void nat_siocdelnat __P((ipnat_t *, ipnat_t **, int, ipf_stack_t *));
static INLINE int nat_icmperrortype4 __P((int));
static INLINE int nat_finalise __P((fr_info_t *, nat_t *, natinfo_t *,
tcphdr_t *, nat_t **, int));
static INLINE int nat_resolverule __P((ipnat_t *, ipf_stack_t *));
-static nat_t *fr_natclone __P((fr_info_t *, nat_t *));
static void nat_mssclamp __P((tcphdr_t *, u_32_t, u_short *));
-static INLINE int nat_wildok __P((nat_t *, int, int, int, int));
static int nat_getnext __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *));
static int nat_iterator __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *));
static int nat_extraflush __P((int, ipf_stack_t *));
@@ -394,7 +389,7 @@ ipf_stack_t *ifs;
/* */
/* Removes a redirect rule from the hash table of redirect rules. */
/* ------------------------------------------------------------------------ */
-static void nat_delrdr(n)
+void nat_delrdr(n)
ipnat_t *n;
{
if (n->in_rnext)
@@ -410,7 +405,7 @@ ipnat_t *n;
/* */
/* Removes a NAT map rule from the hash table of NAT map rules. */
/* ------------------------------------------------------------------------ */
-static void nat_delnat(n)
+void nat_delnat(n)
ipnat_t *n;
{
if (n->in_mnext != NULL)
@@ -479,6 +474,7 @@ ipf_stack_t *ifs;
hm->hm_mapip = map;
hm->hm_ref = 1;
hm->hm_port = port;
+ hm->hm_v = 4;
}
return hm;
}
@@ -795,8 +791,27 @@ ipf_stack_t *ifs;
READ_ENTER(&ifs->ifs_ipf_nat);
}
error = fr_inobj(data, &nl, IPFOBJ_NATLOOKUP);
+ if (nl.nl_v != 6)
+ nl.nl_v = 4;
if (error == 0) {
- if (nat_lookupredir(&nl, ifs) != NULL) {
+ void *ptr;
+
+ switch (nl.nl_v)
+ {
+ case 4:
+ ptr = nat_lookupredir(&nl, ifs);
+ break;
+#ifdef USE_INET6
+ case 6:
+ ptr = nat6_lookupredir(&nl, ifs);
+ break;
+#endif
+ default:
+ ptr = NULL;
+ break;
+ }
+
+ if (ptr != NULL) {
error = fr_outobj(data, &nl, IPFOBJ_NATLOOKUP);
} else {
error = ESRCH;
@@ -943,6 +958,17 @@ ipf_stack_t *ifs;
} else
n->in_space = 1;
+#ifdef USE_INET6
+ if (n->in_v == 6 && (n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0 &&
+ !IP6_ISONES(&n->in_out[1]) && !IP6_ISZERO(&n->in_out[1]))
+ IP6_ADD(&n->in_out[0], 1, &n->in_next6)
+ else if (n->in_v == 6 &&
+ (n->in_flags & IPN_SPLIT) && (n->in_redir & NAT_REDIRECT))
+ n->in_next6 = n->in_in[0];
+ else if (n->in_v == 6)
+ n->in_next6 = n->in_out[0];
+ else
+#endif
if ((n->in_outmsk != 0xffffffff) && (n->in_outmsk != 0) &&
((n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0))
n->in_nip = ntohl(n->in_outip) + 1;
@@ -951,6 +977,7 @@ ipf_stack_t *ifs;
n->in_nip = ntohl(n->in_inip);
else
n->in_nip = ntohl(n->in_outip);
+
if (n->in_redir & NAT_MAP) {
n->in_pnext = ntohs(n->in_pmin);
/*
@@ -1006,11 +1033,35 @@ ipf_stack_t *ifs;
if (n->in_redir & NAT_REDIRECT) {
n->in_flags &= ~IPN_NOTDST;
- nat_addrdr(n, ifs);
+ switch (n->in_v)
+ {
+ case 4 :
+ nat_addrdr(n, ifs);
+ break;
+#ifdef USE_INET6
+ case 6 :
+ nat6_addrdr(n, ifs);
+ break;
+#endif
+ default :
+ break;
+ }
}
if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) {
n->in_flags &= ~IPN_NOTSRC;
- nat_addnat(n, ifs);
+ switch (n->in_v)
+ {
+ case 4 :
+ nat_addnat(n, ifs);
+ break;
+#ifdef USE_INET6
+ case 6 :
+ nat6_addnat(n, ifs);
+ break;
+#endif
+ default :
+ break;
+ }
}
n = NULL;
ifs->ifs_nat_stats.ns_rules++;
@@ -1038,14 +1089,14 @@ ipnat_t *n;
ipf_stack_t *ifs;
{
n->in_ifnames[0][LIFNAMSIZ - 1] = '\0';
- n->in_ifps[0] = fr_resolvenic(n->in_ifnames[0], 4, ifs);
+ n->in_ifps[0] = fr_resolvenic(n->in_ifnames[0], n->in_v, ifs);
n->in_ifnames[1][LIFNAMSIZ - 1] = '\0';
if (n->in_ifnames[1][0] == '\0') {
(void) strncpy(n->in_ifnames[1], n->in_ifnames[0], LIFNAMSIZ);
n->in_ifps[1] = n->in_ifps[0];
} else {
- n->in_ifps[1] = fr_resolvenic(n->in_ifnames[1], 4, ifs);
+ n->in_ifps[1] = fr_resolvenic(n->in_ifnames[1], n->in_v, ifs);
}
if (n->in_plabel[0] != '\0') {
@@ -1074,6 +1125,8 @@ ipnat_t *n, **np;
int getlock;
ipf_stack_t *ifs;
{
+ int i;
+
if (getlock) {
WRITE_ENTER(&ifs->ifs_ipf_nat);
}
@@ -1084,6 +1137,10 @@ ipf_stack_t *ifs;
if (ifs->ifs_nat_list == NULL) {
ifs->ifs_nat_masks = 0;
ifs->ifs_rdr_masks = 0;
+ for (i = 0; i < 4; i++) {
+ ifs->ifs_nat6_masks[i] = 0;
+ ifs->ifs_rdr6_masks[i] = 0;
+ }
}
if (n->in_tqehead[0] != NULL) {
@@ -1329,7 +1386,7 @@ finished:
/* header adjustment. It is by design see (IP_CKSUM_RECV() macro in ip.c). */
/* */
/* ------------------------------------------------------------------------ */
-static void nat_calc_chksum_diffs(nat)
+void nat_calc_chksum_diffs(nat)
nat_t *nat;
{
u_32_t sum_orig = 0;
@@ -1338,6 +1395,9 @@ nat_t *nat;
u_32_t ipsum_orig = 0;
u_32_t ipsum_changed = 0;
+ if (nat->nat_v != 4 && nat->nat_v != 6)
+ return;
+
/*
* the switch calculates operands for CALC_SUMD(),
* which will compute the partial chksum delta.
@@ -1349,16 +1409,26 @@ nat_t *nat;
* we are dealing with RDR rule (DST address gets
* modified on packet from client)
*/
- sum_changed = LONG_SUM(ntohl(nat->nat_inip.s_addr));
- sum_orig = LONG_SUM(ntohl(nat->nat_outip.s_addr));
+ if (nat->nat_v == 4) {
+ sum_changed = LONG_SUM(ntohl(nat->nat_inip.s_addr));
+ sum_orig = LONG_SUM(ntohl(nat->nat_outip.s_addr));
+ } else {
+ sum_changed = LONG_SUM6(&nat->nat_inip6);
+ sum_orig = LONG_SUM6(&nat->nat_outip6);
+ }
break;
case NAT_OUTBOUND:
/*
* we are dealing with MAP rule (SRC address gets
* modified on packet from client)
*/
- sum_changed = LONG_SUM(ntohl(nat->nat_outip.s_addr));
- sum_orig = LONG_SUM(ntohl(nat->nat_inip.s_addr));
+ if (nat->nat_v == 4) {
+ sum_changed = LONG_SUM(ntohl(nat->nat_outip.s_addr));
+ sum_orig = LONG_SUM(ntohl(nat->nat_inip.s_addr));
+ } else {
+ sum_changed = LONG_SUM6(&nat->nat_outip6);
+ sum_orig = LONG_SUM6(&nat->nat_inip6);
+ }
break;
default: ;
break;
@@ -1386,24 +1456,34 @@ nat_t *nat;
switch (nat->nat_dir)
{
case NAT_INBOUND:
- sum_changed = LONG_SUM(
- ntohl(nat->nat_inip.s_addr) +
- ntohs(nat->nat_inport)
- );
- sum_orig = LONG_SUM(
- ntohl(nat->nat_outip.s_addr) +
- ntohs(nat->nat_outport)
- );
+ if (nat->nat_v == 4) {
+ sum_changed = LONG_SUM(
+ ntohl(nat->nat_inip.s_addr) +
+ ntohs(nat->nat_inport));
+ sum_orig = LONG_SUM(
+ ntohl(nat->nat_outip.s_addr) +
+ ntohs(nat->nat_outport));
+ } else {
+ sum_changed = LONG_SUM6(&nat->nat_inip6) +
+ ntohs(nat->nat_inport);
+ sum_orig = LONG_SUM6(&nat->nat_outip6) +
+ ntohs(nat->nat_outport);
+ }
break;
case NAT_OUTBOUND:
- sum_changed = LONG_SUM(
- ntohl(nat->nat_outip.s_addr) +
- ntohs(nat->nat_outport)
- );
- sum_orig = LONG_SUM(
- ntohl(nat->nat_inip.s_addr) +
- ntohs(nat->nat_inport)
- );
+ if (nat->nat_v == 4) {
+ sum_changed = LONG_SUM(
+ ntohl(nat->nat_outip.s_addr) +
+ ntohs(nat->nat_outport));
+ sum_orig = LONG_SUM(
+ ntohl(nat->nat_inip.s_addr) +
+ ntohs(nat->nat_inport));
+ } else {
+ sum_changed = LONG_SUM6(&nat->nat_outip6) +
+ ntohs(nat->nat_outport);
+ sum_orig = LONG_SUM6(&nat->nat_inip6) +
+ ntohs(nat->nat_inport);
+ }
break;
default: ;
break;
@@ -1427,27 +1507,28 @@ nat_t *nat;
* we may reuse the already computed nat_sumd[0] for IP header chksum
* adjustment in case the L4 (TCP/UDP header) is not changed by NAT.
*/
- if (NAT_HAS_L4_CHANGED(nat)) {
- /*
- * bad luck, NAT changes also the L4 header, use IP addresses
- * to compute chksum adjustment for IP header.
- */
- CALC_SUMD(ipsum_orig, ipsum_changed, sumd);
- nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
- }
- else {
- /*
- * the NAT does not change L4 hdr -> reuse chksum adjustment
- * for IP hdr.
- */
- nat->nat_ipsumd = nat->nat_sumd[0];
+ if (nat->nat_v == 4) {
+ if (NAT_HAS_L4_CHANGED(nat)) {
+ /*
+ * bad luck, NAT changes also the L4 header, use IP
+ * addresses to compute chksum adjustment for IP header.
+ */
+ CALC_SUMD(ipsum_orig, ipsum_changed, sumd);
+ nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
+ } else {
+ /*
+ * the NAT does not change L4 hdr -> reuse chksum
+ * adjustment for IP hdr.
+ */
+ nat->nat_ipsumd = nat->nat_sumd[0];
- /*
- * if L4 header does not use chkusm - zero out deltas
- */
- if (!(nat->nat_flags & IPN_TCPUDPICMP)) {
- nat->nat_sumd[0] = 0;
- nat->nat_sumd[1] = 0;
+ /*
+ * if L4 header does not use chksum - zero out deltas
+ */
+ if (!(nat->nat_flags & IPN_TCPUDP)) {
+ nat->nat_sumd[0] = 0;
+ nat->nat_sumd[1] = 0;
+ }
}
}
@@ -1564,6 +1645,8 @@ ipf_stack_t *ifs;
/*
* Check that the NAT entry doesn't already exist in the kernel.
*/
+ if (nat->nat_v != 6)
+ nat->nat_v = 4;
bzero((char *)&fin, sizeof(fin));
fin.fin_p = nat->nat_p;
fin.fin_ifs = ifs;
@@ -1574,8 +1657,25 @@ ipf_stack_t *ifs;
if (getlock) {
READ_ENTER(&ifs->ifs_ipf_nat);
}
- n = nat_inlookup(&fin, nat->nat_flags, fin.fin_p,
- nat->nat_oip, nat->nat_outip);
+
+ switch (nat->nat_v)
+ {
+ case 4:
+ fin.fin_v = nat->nat_v;
+ n = nat_inlookup(&fin, nat->nat_flags, fin.fin_p,
+ nat->nat_oip, nat->nat_outip);
+ break;
+#ifdef USE_INET6
+ case 6:
+ n = nat6_inlookup(&fin, nat->nat_flags, fin.fin_p,
+ &nat->nat_oip6.in6, &nat->nat_outip6.in6);
+ break;
+#endif
+ default:
+ n = NULL;
+ break;
+ }
+
if (getlock) {
RWLOCK_EXIT(&ifs->ifs_ipf_nat);
}
@@ -1590,8 +1690,24 @@ ipf_stack_t *ifs;
if (getlock) {
READ_ENTER(&ifs->ifs_ipf_nat);
}
- n = nat_outlookup(&fin, nat->nat_flags, fin.fin_p,
- nat->nat_inip, nat->nat_oip);
+
+ switch (nat->nat_v)
+ {
+ case 4:
+ n = nat_outlookup(&fin, nat->nat_flags, fin.fin_p,
+ nat->nat_inip, nat->nat_oip);
+ break;
+#ifdef USE_INET6
+ case 6:
+ n = nat6_outlookup(&fin, nat->nat_flags, fin.fin_p,
+ &nat->nat_inip6.in6, &nat->nat_oip6.in6);
+ break;
+#endif
+ default:
+ n = NULL;
+ break;
+ }
+
if (getlock) {
RWLOCK_EXIT(&ifs->ifs_ipf_nat);
}
@@ -1696,7 +1812,23 @@ ipf_stack_t *ifs;
if (getlock) {
WRITE_ENTER(&ifs->ifs_ipf_nat);
}
- error = nat_insert(nat, nat->nat_rev, ifs);
+
+ nat_calc_chksum_diffs(nat);
+
+ switch (nat->nat_v)
+ {
+ case 4 :
+ error = nat_insert(nat, nat->nat_rev, ifs);
+ break;
+#ifdef USE_INET6
+ case 6 :
+ error = nat6_insert(nat, nat->nat_rev, ifs);
+ break;
+#endif
+ default :
+ break;
+ }
+
if ((error == 0) && (aps != NULL)) {
aps->aps_next = ifs->ifs_ap_sess_list;
ifs->ifs_ap_sess_list = aps;
@@ -1926,6 +2058,10 @@ ipf_stack_t *ifs;
}
ifs->ifs_nat_masks = 0;
ifs->ifs_rdr_masks = 0;
+ for (i = 0; i < 4; i++) {
+ ifs->ifs_nat6_masks[i] = 0;
+ ifs->ifs_rdr6_masks[i] = 0;
+ }
return i;
}
@@ -2561,6 +2697,7 @@ int direction;
nat->nat_ifps[1] = np->in_ifps[1];
nat->nat_ptr = np;
nat->nat_p = fin->fin_p;
+ nat->nat_v = fin->fin_v;
nat->nat_mssclamp = np->in_mssclamp;
fr = fin->fin_fr;
nat->nat_fr = fr;
@@ -3152,6 +3289,9 @@ struct in_addr src , mapdst;
hv = NAT_HASH_FN(src.s_addr, hv + sport, ifs->ifs_ipf_nattable_sz);
nat = ifs->ifs_nat_table[1][hv];
for (; nat; nat = nat->nat_hnext[1]) {
+ if (nat->nat_v != 4)
+ continue;
+
if (nat->nat_ifps[0] != NULL) {
if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
continue;
@@ -3223,6 +3363,9 @@ find_in_wild_ports:
nat = ifs->ifs_nat_table[1][hv];
for (; nat; nat = nat->nat_hnext[1]) {
+ if (nat->nat_v != 4)
+ continue;
+
if (nat->nat_ifps[0] != NULL) {
if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
continue;
@@ -3397,6 +3540,9 @@ struct in_addr src , dst;
hv = NAT_HASH_FN(dst.s_addr, hv + dport, ifs->ifs_ipf_nattable_sz);
nat = ifs->ifs_nat_table[0][hv];
for (; nat; nat = nat->nat_hnext[0]) {
+ if (nat->nat_v != 4)
+ continue;
+
if (nat->nat_ifps[1] != NULL) {
if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
continue;
@@ -3458,6 +3604,9 @@ find_out_wild_ports:
nat = ifs->ifs_nat_table[0][hv];
for (; nat; nat = nat->nat_hnext[0]) {
+ if (nat->nat_v != 4)
+ continue;
+
if (nat->nat_ifps[1] != NULL) {
if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
continue;
@@ -3878,12 +4027,16 @@ u_32_t nflags;
int i;
ipf_stack_t *ifs = fin->fin_ifs;
+ if (fin->fin_v == 6) {
+#ifdef USE_INET6
+ return fr_nat6out(fin, nat, natadd, nflags);
+#else
+ return NULL;
+#endif
+ }
+
#if SOLARIS && defined(_KERNEL)
- net_data_t net_data_p;
- if (fin->fin_v == 4)
- net_data_p = ifs->ifs_ipf_ipv4;
- else
- net_data_p = ifs->ifs_ipf_ipv6;
+ net_data_t net_data_p = ifs->ifs_ipf_ipv4;
#endif
tcp = NULL;
@@ -4198,12 +4351,16 @@ u_32_t nflags;
int i;
ipf_stack_t *ifs = fin->fin_ifs;
+ if (fin->fin_v == 6) {
+#ifdef USE_INET6
+ return fr_nat6in(fin, nat, natadd, nflags);
+#else
+ return NULL;
+#endif
+ }
+
#if SOLARIS && defined(_KERNEL)
- net_data_t net_data_p;
- if (fin->fin_v == 4)
- net_data_p = ifs->ifs_ipf_ipv4;
- else
- net_data_p = ifs->ifs_ipf_ipv6;
+ net_data_t net_data_p = ifs->ifs_ipf_ipv4;
#endif
tcp = NULL;
@@ -4342,6 +4499,7 @@ nat_t *nat;
u_int nflags;
{
icmphdr_t *icmp;
+ struct icmp6_hdr *icmp6;
u_short *csump;
tcphdr_t *tcp;
udphdr_t *udp;
@@ -4384,6 +4542,15 @@ u_int nflags;
csump = &icmp->icmp_cksum;
}
break;
+
+ case IPPROTO_ICMPV6 :
+ icmp6 = fin->fin_dp;
+
+ if ((nflags & IPN_ICMPQUERY) != 0) {
+ if (icmp6->icmp6_cksum != 0)
+ csump = &icmp6->icmp6_cksum;
+ }
+ break;
}
return csump;
}
@@ -4542,9 +4709,10 @@ ipf_stack_t *ifs;
/* matches the one passed in) and change it, recalculating the checksum sum */
/* difference too. */
/* ------------------------------------------------------------------------ */
-void fr_nataddrsync(ifp, addr, ifs)
+void fr_nataddrsync(v, ifp, addr, ifs)
+int v;
void *ifp;
-struct in_addr *addr;
+void *addr;
ipf_stack_t *ifs;
{
u_32_t sum1, sum2, sumd;
@@ -4574,32 +4742,59 @@ ipf_stack_t *ifs;
if (((ifp != NULL) && ifp != (nat->nat_ifps[0])) ||
((nat->nat_flags & IPN_TCP) != 0))
continue;
- if (((np = nat->nat_ptr) == NULL) ||
- (np->in_nip || (np->in_outmsk != 0xffffffff)))
+ if ((np = nat->nat_ptr) == NULL)
+ continue;
+ if (v == 4 && np->in_v == 4) {
+ if (np->in_nip || np->in_outmsk != 0xffffffff)
+ continue;
+ /*
+ * Change the map-to address to be the same as
+ * the new one.
+ */
+ sum1 = nat->nat_outip.s_addr;
+ nat->nat_outip = *(struct in_addr *)addr;
+ sum2 = nat->nat_outip.s_addr;
+ } else if (v == 6 && np->in_v == 6) {
+ if (!IP6_ISZERO(&np->in_next6.in6) ||
+ !IP6_ISONES(&np->in_out[1].in6))
+ continue;
+ /*
+ * Change the map-to address to be the same as
+ * the new one.
+ */
+ nat->nat_outip6.in6 = *(struct in6_addr *)addr;
+ } else
continue;
-
- /*
- * Change the map-to address to be the same as the
- * new one.
- */
- sum1 = nat->nat_outip.s_addr;
- nat->nat_outip = *addr;
- sum2 = nat->nat_outip.s_addr;
} else if (((ifp == NULL) || (ifp == nat->nat_ifps[0])) &&
- !(nat->nat_flags & IPN_TCP) && (np = nat->nat_ptr) &&
- (np->in_outmsk == 0xffffffff) && !np->in_nip) {
- struct in_addr in;
-
- /*
- * Change the map-to address to be the same as the
- * new one.
- */
- sum1 = nat->nat_outip.s_addr;
- if (fr_ifpaddr(4, FRI_NORMAL, nat->nat_ifps[0],
- &in, NULL, ifs) != -1)
- nat->nat_outip = in;
- sum2 = nat->nat_outip.s_addr;
+ !(nat->nat_flags & IPN_TCP) && (np = nat->nat_ptr)) {
+ if (np->in_v == 4 && (v == 4 || v == 0)) {
+ struct in_addr in;
+ if (np->in_outmsk != 0xffffffff || np->in_nip)
+ continue;
+ /*
+ * Change the map-to address to be the same as
+ * the new one.
+ */
+ sum1 = nat->nat_outip.s_addr;
+ if (fr_ifpaddr(4, FRI_NORMAL, nat->nat_ifps[0],
+ &in, NULL, ifs) != -1)
+ nat->nat_outip = in;
+ sum2 = nat->nat_outip.s_addr;
+ } else if (np->in_v == 6 && (v == 6 || v == 0)) {
+ struct in6_addr in6;
+ if (!IP6_ISZERO(&np->in_next6.in6) ||
+ !IP6_ISONES(&np->in_out[1].in6))
+ continue;
+ /*
+ * Change the map-to address to be the same as
+ * the new one.
+ */
+ if (fr_ifpaddr(6, FRI_NORMAL, nat->nat_ifps[0],
+ (void *)&in6, NULL, ifs) != -1)
+ nat->nat_outip6.in6 = in6;
+ } else
+ continue;
} else {
continue;
}
@@ -4638,8 +4833,8 @@ ipf_stack_t *ifs;
/* "name" and for "action == IPFSYNC_OLDIFP", ifp is a pointer for which */
/* there is no longer any interface associated with it. */
/* ------------------------------------------------------------------------ */
-void fr_natifpsync(action, ifp, name, ifs)
-int action;
+void fr_natifpsync(action, v, ifp, name, ifs)
+int action, v;
void *ifp;
char *name;
ipf_stack_t *ifs;
@@ -4649,6 +4844,7 @@ ipf_stack_t *ifs;
#endif
nat_t *nat;
ipnat_t *n;
+ int nv;
if (ifs->ifs_fr_running <= 0)
return;
@@ -4665,34 +4861,42 @@ ipf_stack_t *ifs;
{
case IPFSYNC_RESYNC :
for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) {
+ nv = (v == 0) ? nat->nat_v : v;
+ if (nat->nat_v != nv)
+ continue;
if ((ifp == nat->nat_ifps[0]) ||
(nat->nat_ifps[0] == (void *)-1)) {
nat->nat_ifps[0] =
- fr_resolvenic(nat->nat_ifnames[0], 4, ifs);
+ fr_resolvenic(nat->nat_ifnames[0], nv, ifs);
}
if ((ifp == nat->nat_ifps[1]) ||
(nat->nat_ifps[1] == (void *)-1)) {
nat->nat_ifps[1] =
- fr_resolvenic(nat->nat_ifnames[1], 4, ifs);
+ fr_resolvenic(nat->nat_ifnames[1], nv, ifs);
}
}
for (n = ifs->ifs_nat_list; (n != NULL); n = n->in_next) {
+ nv = (v == 0) ? (int)n->in_v : v;
+ if ((int)n->in_v != nv)
+ continue;
if (n->in_ifps[0] == ifp ||
n->in_ifps[0] == (void *)-1) {
n->in_ifps[0] =
- fr_resolvenic(n->in_ifnames[0], 4, ifs);
+ fr_resolvenic(n->in_ifnames[0], nv, ifs);
}
if (n->in_ifps[1] == ifp ||
n->in_ifps[1] == (void *)-1) {
n->in_ifps[1] =
- fr_resolvenic(n->in_ifnames[1], 4, ifs);
+ fr_resolvenic(n->in_ifnames[1], nv, ifs);
}
}
break;
case IPFSYNC_NEWIFP :
for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) {
+ if (nat->nat_v != v)
+ continue;
if (!strncmp(name, nat->nat_ifnames[0],
sizeof(nat->nat_ifnames[0])))
nat->nat_ifps[0] = ifp;
@@ -4701,6 +4905,8 @@ ipf_stack_t *ifs;
nat->nat_ifps[1] = ifp;
}
for (n = ifs->ifs_nat_list; (n != NULL); n = n->in_next) {
+ if ((int)n->in_v != v)
+ continue;
if (!strncmp(name, n->in_ifnames[0],
sizeof(n->in_ifnames[0])))
n->in_ifps[0] = ifp;
@@ -4711,12 +4917,16 @@ ipf_stack_t *ifs;
break;
case IPFSYNC_OLDIFP :
for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) {
+ if (nat->nat_v != v)
+ continue;
if (ifp == nat->nat_ifps[0])
nat->nat_ifps[0] = (void *)-1;
if (ifp == nat->nat_ifps[1])
nat->nat_ifps[1] = (void *)-1;
}
for (n = ifs->ifs_nat_list; (n != NULL); n = n->in_next) {
+ if ((int)n->in_v != v)
+ continue;
if (n->in_ifps[0] == ifp)
n->in_ifps[0] = (void *)-1;
if (n->in_ifps[1] == ifp)
@@ -4794,25 +5004,26 @@ ipf_stack_t *ifs;
size_t sizes[1];
int types[1];
- natl.nl_inip = nat->nat_inip;
- natl.nl_outip = nat->nat_outip;
- natl.nl_origip = nat->nat_oip;
- natl.nl_bytes[0] = nat->nat_bytes[0];
- natl.nl_bytes[1] = nat->nat_bytes[1];
- natl.nl_pkts[0] = nat->nat_pkts[0];
- natl.nl_pkts[1] = nat->nat_pkts[1];
- natl.nl_origport = nat->nat_oport;
- natl.nl_inport = nat->nat_inport;
- natl.nl_outport = nat->nat_outport;
- natl.nl_p = nat->nat_p;
- natl.nl_type = type;
- natl.nl_rule = -1;
+ natl.nlg_inip = nat->nat_inip6;
+ natl.nlg_outip = nat->nat_outip6;
+ natl.nlg_origip = nat->nat_oip6;
+ natl.nlg_bytes[0] = nat->nat_bytes[0];
+ natl.nlg_bytes[1] = nat->nat_bytes[1];
+ natl.nlg_pkts[0] = nat->nat_pkts[0];
+ natl.nlg_pkts[1] = nat->nat_pkts[1];
+ natl.nlg_origport = nat->nat_oport;
+ natl.nlg_inport = nat->nat_inport;
+ natl.nlg_outport = nat->nat_outport;
+ natl.nlg_p = nat->nat_p;
+ natl.nlg_type = type;
+ natl.nlg_rule = -1;
+ natl.nlg_v = nat->nat_v;
# ifndef LARGE_NAT
if (nat->nat_ptr != NULL) {
for (rulen = 0, np = ifs->ifs_nat_list; np;
np = np->in_next, rulen++)
if (np == nat->nat_ptr) {
- natl.nl_rule = rulen;
+ natl.nlg_rule = rulen;
break;
}
}
@@ -4925,7 +5136,7 @@ ipf_stack_t *ifs;
/* */
/* Create a "duplcate" state table entry from the master. */
/* ------------------------------------------------------------------------ */
-static nat_t *fr_natclone(fin, nat)
+nat_t *fr_natclone(fin, nat)
fr_info_t *fin;
nat_t *nat;
{
@@ -5004,7 +5215,7 @@ nat_t *nat;
/* Use NAT entry and packet direction to determine which combination of */
/* wildcard flags should be used. */
/* ------------------------------------------------------------------------ */
-static INLINE int nat_wildok(nat, sport, dport, flags, dir)
+int nat_wildok(nat, sport, dport, flags, dir)
nat_t *nat;
int sport;
int dport;
diff --git a/usr/src/uts/common/inet/ipf/ip_nat6.c b/usr/src/uts/common/inet/ipf/ip_nat6.c
new file mode 100644
index 0000000000..77fd2c139f
--- /dev/null
+++ b/usr/src/uts/common/inet/ipf/ip_nat6.c
@@ -0,0 +1,2648 @@
+/*
+ * Copyright (C) 1995-2003 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"$
+
+#if defined(KERNEL) || defined(_KERNEL)
+# undef KERNEL
+# undef _KERNEL
+# define KERNEL 1
+# define _KERNEL 1
+#endif
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
+ defined(_KERNEL)
+# include "opt_ipfilter_log.h"
+#endif
+#if !defined(_KERNEL)
+# include <stdio.h>
+# include <string.h>
+# include <stdlib.h>
+# define _KERNEL
+# ifdef __OpenBSD__
+struct file;
+# endif
+# include <sys/uio.h>
+# undef _KERNEL
+#endif
+#if defined(_KERNEL) && (__FreeBSD_version >= 220000)
+# include <sys/filio.h>
+# include <sys/fcntl.h>
+#else
+# include <sys/ioctl.h>
+#endif
+#if !defined(AIX)
+# include <sys/fcntl.h>
+#endif
+#if !defined(linux)
+# include <sys/protosw.h>
+#endif
+#include <sys/socket.h>
+#if defined(_KERNEL)
+# include <sys/systm.h>
+# if !defined(__SVR4) && !defined(__svr4__)
+# include <sys/mbuf.h>
+# endif
+#endif
+#if defined(__SVR4) || defined(__svr4__)
+# include <sys/filio.h>
+# include <sys/byteorder.h>
+# ifdef _KERNEL
+# include <sys/dditypes.h>
+# endif
+# include <sys/stream.h>
+# include <sys/kmem.h>
+#endif
+#if __FreeBSD_version >= 300000
+# include <sys/queue.h>
+#endif
+#include <net/if.h>
+#if __FreeBSD_version >= 300000
+# include <net/if_var.h>
+# if defined(_KERNEL) && !defined(IPFILTER_LKM)
+# include "opt_ipfilter.h"
+# endif
+#endif
+#ifdef sun
+# include <net/af.h>
+#endif
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#ifdef RFC1825
+# include <vpn/md5.h>
+# include <vpn/ipsec.h>
+extern struct ifnet vpnif;
+#endif
+
+#if !defined(linux)
+# include <netinet/ip_var.h>
+#endif
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/ip_icmp.h>
+#include "netinet/ip_compat.h"
+#include <netinet/tcpip.h>
+#include "netinet/ip_fil.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_frag.h"
+#include "netinet/ip_state.h"
+#include "netinet/ip_proxy.h"
+#include "netinet/ipf_stack.h"
+#ifdef IPFILTER_SYNC
+#include "netinet/ip_sync.h"
+#endif
+#if (__FreeBSD_version >= 300000)
+# include <sys/malloc.h>
+#endif
+/* END OF INCLUDES */
+
+#undef SOCKADDR_IN
+#define SOCKADDR_IN struct sockaddr_in
+
+#if !defined(lint)
+static const char rcsid[] = "@(#)$Id: ip_nat6.c,v 1.2 2008/02/14 21:05:50 darrenr Exp $";
+#endif
+
+static hostmap_t *nat6_hostmap __P((ipnat_t *, i6addr_t *, i6addr_t *,
+ i6addr_t *, u_32_t, ipf_stack_t *));
+static INLINE int nat6_newmap __P((fr_info_t *, nat_t *, natinfo_t *));
+static INLINE int nat6_newrdr __P((fr_info_t *, nat_t *, natinfo_t *));
+static INLINE int nat6_finalise __P((fr_info_t *, nat_t *, natinfo_t *,
+ tcphdr_t *, nat_t **, int));
+static void nat6_tabmove __P((nat_t *, ipf_stack_t *));
+static int nat6_match __P((fr_info_t *, ipnat_t *));
+static INLINE int nat_icmpquerytype6 __P((int));
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat6_addrdr */
+/* Returns: Nil */
+/* Parameters: n(I) - pointer to NAT rule to add */
+/* */
+/* Adds a redirect rule to the hash table of redirect rules and the list of */
+/* loaded NAT rules. Updates the bitmask indicating which netmasks are in */
+/* use by redirect rules. */
+/* ------------------------------------------------------------------------ */
+void nat6_addrdr(n, ifs)
+ipnat_t *n;
+ipf_stack_t *ifs;
+{
+ ipnat_t **np;
+ i6addr_t j;
+ u_int hv;
+ int k;
+
+ k = count6bits(n->in_out[1].i6);
+ if ((k >= 0) && (k != 128))
+ ifs->ifs_rdr6_masks[k >> 5] |= 1 << (k & 31);
+ IP6_AND(&n->in_out[0], &n->in_out[1], &j);
+ hv = NAT_HASH_FN6(&j, 0, ifs->ifs_ipf_rdrrules_sz);
+ np = ifs->ifs_rdr_rules + hv;
+ while (*np != NULL)
+ np = &(*np)->in_rnext;
+ n->in_rnext = NULL;
+ n->in_prnext = np;
+ n->in_hv = hv;
+ *np = n;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat6_addnat */
+/* Returns: Nil */
+/* Parameters: n(I) - pointer to NAT rule to add */
+/* */
+/* Adds a NAT map rule to the hash table of rules and the list of loaded */
+/* NAT rules. Updates the bitmask indicating which netmasks are in use by */
+/* redirect rules. */
+/* ------------------------------------------------------------------------ */
+void nat6_addnat(n, ifs)
+ipnat_t *n;
+ipf_stack_t *ifs;
+{
+ ipnat_t **np;
+ i6addr_t j;
+ u_int hv;
+ int k;
+
+ k = count6bits(n->in_in[1].i6);
+ if ((k >= 0) && (k != 128))
+ ifs->ifs_nat6_masks[k >> 5] |= 1 << (k & 31);
+ IP6_AND(&n->in_in[0], &n->in_in[1], &j);
+ hv = NAT_HASH_FN6(&j, 0, ifs->ifs_ipf_natrules_sz);
+ np = ifs->ifs_nat_rules + hv;
+ while (*np != NULL)
+ np = &(*np)->in_mnext;
+ n->in_mnext = NULL;
+ n->in_pmnext = np;
+ n->in_hv = hv;
+ *np = n;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat6_hostmap */
+/* Returns: struct hostmap* - NULL if no hostmap could be created, */
+/* else a pointer to the hostmapping to use */
+/* Parameters: np(I) - pointer to NAT rule */
+/* real(I) - real IP address */
+/* map(I) - mapped IP address */
+/* port(I) - destination port number */
+/* Write Locks: ipf_nat */
+/* */
+/* Check if an ip address has already been allocated for a given mapping */
+/* that is not doing port based translation. If is not yet allocated, then */
+/* create a new entry if a non-NULL NAT rule pointer has been supplied. */
+/* ------------------------------------------------------------------------ */
+static struct hostmap *nat6_hostmap(np, src, dst, map, port, ifs)
+ipnat_t *np;
+i6addr_t *src, *dst, *map;
+u_32_t port;
+ipf_stack_t *ifs;
+{
+ hostmap_t *hm;
+ u_int hv;
+
+ hv = (src->i6[3] ^ dst->i6[3]);
+ hv += (src->i6[2] ^ dst->i6[2]);
+ hv += (src->i6[1] ^ dst->i6[1]);
+ hv += (src->i6[0] ^ dst->i6[0]);
+ hv += src->i6[3];
+ hv += src->i6[2];
+ hv += src->i6[1];
+ hv += src->i6[0];
+ hv += dst->i6[3];
+ hv += dst->i6[2];
+ hv += dst->i6[1];
+ hv += dst->i6[0];
+ hv %= HOSTMAP_SIZE;
+ for (hm = ifs->ifs_maptable[hv]; hm; hm = hm->hm_next)
+ if (IP6_EQ(&hm->hm_srcip6, src) &&
+ IP6_EQ(&hm->hm_dstip6, dst) &&
+ ((np == NULL) || (np == hm->hm_ipnat)) &&
+ ((port == 0) || (port == hm->hm_port))) {
+ hm->hm_ref++;
+ return hm;
+ }
+
+ if (np == NULL)
+ return NULL;
+
+ KMALLOC(hm, hostmap_t *);
+ if (hm) {
+ hm->hm_hnext = ifs->ifs_ipf_hm_maplist;
+ hm->hm_phnext = &ifs->ifs_ipf_hm_maplist;
+ if (ifs->ifs_ipf_hm_maplist != NULL)
+ ifs->ifs_ipf_hm_maplist->hm_phnext = &hm->hm_hnext;
+ ifs->ifs_ipf_hm_maplist = hm;
+
+ hm->hm_next = ifs->ifs_maptable[hv];
+ hm->hm_pnext = ifs->ifs_maptable + hv;
+ if (ifs->ifs_maptable[hv] != NULL)
+ ifs->ifs_maptable[hv]->hm_pnext = &hm->hm_next;
+ ifs->ifs_maptable[hv] = hm;
+ hm->hm_ipnat = np;
+ hm->hm_src = *src;
+ hm->hm_dst = *dst;
+ hm->hm_map = *map;
+ hm->hm_ref = 1;
+ hm->hm_port = port;
+ hm->hm_v = 6;
+ }
+ return hm;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat6_newmap */
+/* Returns: int - -1 == error, 0 == success */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to NAT entry */
+/* ni(I) - pointer to structure with misc. information needed */
+/* to create new NAT entry. */
+/* */
+/* Given an empty NAT structure, populate it with new information about a */
+/* new NAT session, as defined by the matching NAT rule. */
+/* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
+/* to the new IP address for the translation. */
+/* ------------------------------------------------------------------------ */
+static INLINE int nat6_newmap(fin, nat, ni)
+fr_info_t *fin;
+nat_t *nat;
+natinfo_t *ni;
+{
+ u_short st_port, dport, sport, port, sp, dp;
+ i6addr_t in, st_ip;
+ hostmap_t *hm;
+ u_32_t flags;
+ ipnat_t *np;
+ nat_t *natl;
+ int l;
+ ipf_stack_t *ifs = fin->fin_ifs;
+
+ /*
+ * If it's an outbound packet which doesn't match any existing
+ * record, then create a new port
+ */
+ l = 0;
+ hm = NULL;
+ np = ni->nai_np;
+ st_ip = np->in_next6;
+ st_port = np->in_pnext;
+ flags = ni->nai_flags;
+ sport = ni->nai_sport;
+ dport = ni->nai_dport;
+
+ /*
+ * Do a loop until we either run out of entries to try or we find
+ * a NAT mapping that isn't currently being used. This is done
+ * because the change to the source is not (usually) being fixed.
+ */
+ do {
+ port = 0;
+ in = np->in_next6;
+ if (l == 0) {
+ /*
+ * Check to see if there is an existing NAT
+ * setup for this IP address pair.
+ */
+ hm = nat6_hostmap(np, &fin->fin_src6, &fin->fin_dst6,
+ &in, 0, ifs);
+ if (hm != NULL)
+ in = hm->hm_map;
+ } else if ((l == 1) && (hm != NULL)) {
+ fr_hostmapdel(&hm);
+ }
+
+ nat->nat_hm = hm;
+
+ if (IP6_ISONES(&np->in_out[1]) && (np->in_pnext == 0)) {
+ if (l > 0)
+ return -1;
+ }
+
+ if (np->in_redir == NAT_BIMAP &&
+ IP6_EQ(&np->in_in[1], &np->in_out[1])) {
+ i6addr_t temp;
+ /*
+ * map the address block in a 1:1 fashion
+ */
+ temp.i6[0] = fin->fin_src6.i6[0] &
+ ~np->in_in[1].i6[0];
+ temp.i6[1] = fin->fin_src6.i6[1] &
+ ~np->in_in[1].i6[1];
+ temp.i6[2] = fin->fin_src6.i6[2] &
+ ~np->in_in[1].i6[2];
+ temp.i6[3] = fin->fin_src6.i6[3] &
+ ~np->in_in[1].i6[3];
+ in = np->in_out[0];
+ IP6_MERGE(&in, &temp, &np->in_in[0]);
+
+#ifdef NEED_128BIT_MATH
+ } else if (np->in_redir & NAT_MAPBLK) {
+ if ((l >= np->in_ppip) || ((l > 0) &&
+ !(flags & IPN_TCPUDP)))
+ return -1;
+ /*
+ * map-block - Calculate destination address.
+ */
+ IP6_MASK(&in, &fin->fin_src6, &np->in_in[1]);
+ in = ntol(in);
+ inb = in;
+ in /= np->in_ippip;
+ in &= ntohl(~np->in_out[1]);
+ in += ntohl(np->in_out[0]);
+ /*
+ * Calculate destination port.
+ */
+ if ((flags & IPN_TCPUDP) &&
+ (np->in_ppip != 0)) {
+ port = ntohs(sport) + l;
+ port %= np->in_ppip;
+ port += np->in_ppip *
+ (inb.s_addr % np->in_ippip);
+ port += MAPBLK_MINPORT;
+ port = htons(port);
+ }
+#endif
+
+ } else if (IP6_ISZERO(&np->in_out[0]) &&
+ IP6_ISONES(&np->in_out[1])) {
+ /*
+ * 0/128 - use the interface's IP address.
+ */
+ if ((l > 0) ||
+ fr_ifpaddr(6, FRI_NORMAL, fin->fin_ifp,
+ (void *)&in, NULL, fin->fin_ifs) == -1)
+ return -1;
+
+ } else if (IP6_ISZERO(&np->in_out[0]) &&
+ IP6_ISZERO(&np->in_out[1])) {
+ /*
+ * 0/0 - use the original source address/port.
+ */
+ if (l > 0)
+ return -1;
+ in = fin->fin_src6;
+
+ } else if (!IP6_ISONES(&np->in_out[1]) &&
+ (np->in_pnext == 0) && ((l > 0) || (hm == NULL))) {
+ IP6_INC(&np->in_next6);
+ }
+
+ natl = NULL;
+
+ if ((flags & IPN_TCPUDP) &&
+ ((np->in_redir & NAT_MAPBLK) == 0) &&
+ (np->in_flags & IPN_AUTOPORTMAP)) {
+ /*EMPTY*/;
+#ifdef NEED_128BIT_MATH
+ /*
+ * XXX "ports auto" (without map-block)
+ */
+ if ((l > 0) && (l % np->in_ppip == 0)) {
+ if (l > np->in_space) {
+ return -1;
+ } else if ((l > np->in_ppip) &&
+ !IP6_ISONES(&np->in_out[1])) {
+ IP6_INC(&np->in_next6);
+ }
+ }
+ if (np->in_ppip != 0) {
+ port = ntohs(sport);
+ port += (l % np->in_ppip);
+ port %= np->in_ppip;
+ port += np->in_ppip *
+ (ntohl(fin->fin_src6) %
+ np->in_ippip);
+ port += MAPBLK_MINPORT;
+ port = htons(port);
+ }
+#endif
+
+ } else if (((np->in_redir & NAT_MAPBLK) == 0) &&
+ (flags & IPN_TCPUDPICMP) && (np->in_pnext != 0)) {
+ /*
+ * Standard port translation. Select next port.
+ */
+ port = htons(np->in_pnext++);
+
+ if (np->in_pnext > ntohs(np->in_pmax)) {
+ np->in_pnext = ntohs(np->in_pmin);
+ if (!IP6_ISONES(&np->in_out[1])) {
+ IP6_INC(&np->in_next6);
+ }
+ }
+ }
+
+ if (np->in_flags & IPN_IPRANGE) {
+ if (IP6_GT(&np->in_next6, &np->in_out[1]))
+ np->in_next6 = np->in_out[0];
+ } else {
+ i6addr_t a1, a2;
+
+ a1 = np->in_next6;
+ IP6_INC(&a1);
+ IP6_AND(&a1, &np->in_out[1], &a2);
+ if (!IP6_ISONES(&np->in_out[1]) &&
+ IP6_GT(&a2, &np->in_out[0])) {
+ IP6_ADD(&np->in_out[0], 1, &np->in_next6);
+ }
+ }
+
+ if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY)))
+ port = sport;
+
+ /*
+ * Here we do a lookup of the connection as seen from
+ * the outside. If an IP# pair already exists, try
+ * again. So if you have A->B becomes C->B, you can
+ * also have D->E become C->E but not D->B causing
+ * another C->B. Also take protocol and ports into
+ * account when determining whether a pre-existing
+ * NAT setup will cause an external conflict where
+ * this is appropriate.
+ */
+ sp = fin->fin_data[0];
+ dp = fin->fin_data[1];
+ fin->fin_data[0] = fin->fin_data[1];
+ fin->fin_data[1] = htons(port);
+ natl = nat6_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
+ (u_int)fin->fin_p, &fin->fin_dst6.in6, &in.in6);
+ fin->fin_data[0] = sp;
+ fin->fin_data[1] = dp;
+
+ /*
+ * Has the search wrapped around and come back to the
+ * start ?
+ */
+ if ((natl != NULL) &&
+ (np->in_pnext != 0) && (st_port == np->in_pnext) &&
+ !IP6_ISZERO(&np->in_next6) &&
+ IP6_EQ(&st_ip, &np->in_next6))
+ return -1;
+ l++;
+ } while (natl != NULL);
+
+ if (np->in_space > 0)
+ np->in_space--;
+
+ /* Setup the NAT table */
+ nat->nat_inip6 = fin->fin_src6;
+ nat->nat_outip6 = in;
+ nat->nat_oip6 = fin->fin_dst6;
+ if (nat->nat_hm == NULL)
+ nat->nat_hm = nat6_hostmap(np, &fin->fin_src6, &fin->fin_dst6,
+ &nat->nat_outip6, 0, ifs);
+
+ if (flags & IPN_TCPUDP) {
+ nat->nat_inport = sport;
+ nat->nat_outport = port; /* sport */
+ nat->nat_oport = dport;
+ ((tcphdr_t *)fin->fin_dp)->th_sport = port;
+ } else if (flags & IPN_ICMPQUERY) {
+ ((struct icmp6_hdr *)fin->fin_dp)->icmp6_id = port;
+ nat->nat_inport = port;
+ nat->nat_outport = port;
+ }
+
+ ni->nai_port = port;
+ ni->nai_nport = dport;
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat6_newrdr */
+/* Returns: int - -1 == error, 0 == success (no move), 1 == success and */
+/* allow rule to be moved if IPN_ROUNDR is set. */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to NAT entry */
+/* ni(I) - pointer to structure with misc. information needed */
+/* to create new NAT entry. */
+/* */
+/* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
+/* to the new IP address for the translation. */
+/* ------------------------------------------------------------------------ */
+static INLINE int nat6_newrdr(fin, nat, ni)
+fr_info_t *fin;
+nat_t *nat;
+natinfo_t *ni;
+{
+ u_short nport, dport, sport;
+ i6addr_t in;
+ u_short sp, dp;
+ hostmap_t *hm;
+ u_32_t flags;
+ ipnat_t *np;
+ nat_t *natl;
+ int move;
+ ipf_stack_t *ifs = fin->fin_ifs;
+
+ move = 1;
+ hm = NULL;
+ in.i6[0] = 0;
+ in.i6[1] = 0;
+ in.i6[2] = 0;
+ in.i6[3] = 0;
+ np = ni->nai_np;
+ flags = ni->nai_flags;
+ sport = ni->nai_sport;
+ dport = ni->nai_dport;
+
+ /*
+ * If the matching rule has IPN_STICKY set, then we want to have the
+ * same rule kick in as before. Why would this happen? If you have
+ * a collection of rdr rules with "round-robin sticky", the current
+ * packet might match a different one to the previous connection but
+ * we want the same destination to be used.
+ */
+ if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) ==
+ (IPN_ROUNDR|IPN_STICKY)) {
+ hm = nat6_hostmap(NULL, &fin->fin_src6, &fin->fin_dst6, &in,
+ (u_32_t)dport, ifs);
+ if (hm != NULL) {
+ in = hm->hm_map;
+ np = hm->hm_ipnat;
+ ni->nai_np = np;
+ move = 0;
+ }
+ }
+
+ /*
+ * Otherwise, it's an inbound packet. Most likely, we don't
+ * want to rewrite source ports and source addresses. Instead,
+ * we want to rewrite to a fixed internal address and fixed
+ * internal port.
+ */
+ if (np->in_flags & IPN_SPLIT) {
+ in = np->in_next6;
+
+ if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) {
+ hm = nat6_hostmap(np, &fin->fin_src6, &fin->fin_dst6,
+ &in, (u_32_t)dport, ifs);
+ if (hm != NULL) {
+ in = hm->hm_map;
+ move = 0;
+ }
+ }
+
+ if (hm == NULL || hm->hm_ref == 1) {
+ if (IP6_EQ(&np->in_in[0], &in)) {
+ np->in_next6 = np->in_in[1];
+ move = 0;
+ } else {
+ np->in_next6 = np->in_in[0];
+ }
+ }
+
+ } else if (IP6_ISZERO(&np->in_in[0]) &&
+ IP6_ISONES(&np->in_in[1])) {
+ /*
+ * 0/128 - use the interface's IP address.
+ */
+ if (fr_ifpaddr(6, FRI_NORMAL, fin->fin_ifp, (void *)&in, NULL,
+ fin->fin_ifs) == -1)
+ return -1;
+
+ } else if (IP6_ISZERO(&np->in_in[0]) &&
+ IP6_ISZERO(&np->in_in[1])) {
+ /*
+ * 0/0 - use the original destination address/port.
+ */
+ in = fin->fin_dst6;
+
+ } else if (np->in_redir == NAT_BIMAP &&
+ IP6_EQ(&np->in_in[1], &np->in_out[1])) {
+ i6addr_t temp;
+ /*
+ * map the address block in a 1:1 fashion
+ */
+ temp.i6[0] = fin->fin_dst6.i6[0] & ~np->in_in[1].i6[0];
+ temp.i6[1] = fin->fin_dst6.i6[1] & ~np->in_in[1].i6[1];
+ temp.i6[2] = fin->fin_dst6.i6[2] & ~np->in_in[1].i6[2];
+ temp.i6[3] = fin->fin_dst6.i6[3] & ~np->in_in[1].i6[3];
+ in = np->in_in[0];
+ IP6_MERGE(&in, &temp, &np->in_in[1]);
+ } else {
+ in = np->in_in[0];
+ }
+
+ if ((np->in_pnext == 0) || ((flags & NAT_NOTRULEPORT) != 0))
+ nport = dport;
+ else {
+ /*
+ * Whilst not optimized for the case where
+ * pmin == pmax, the gain is not significant.
+ */
+ if (((np->in_flags & IPN_FIXEDDPORT) == 0) &&
+ (np->in_pmin != np->in_pmax)) {
+ nport = ntohs(dport) - ntohs(np->in_pmin) +
+ ntohs(np->in_pnext);
+ nport = htons(nport);
+ } else
+ nport = np->in_pnext;
+ }
+
+ /*
+ * When the redirect-to address is set to 0.0.0.0, just
+ * assume a blank `forwarding' of the packet. We don't
+ * setup any translation for this either.
+ */
+ if (IP6_ISZERO(&in)) {
+ if (nport == dport)
+ return -1;
+ in = fin->fin_dst6;
+ }
+
+ /*
+ * Check to see if this redirect mapping already exists and if
+ * it does, return "failure" (allowing it to be created will just
+ * cause one or both of these "connections" to stop working.)
+ */
+ sp = fin->fin_data[0];
+ dp = fin->fin_data[1];
+ fin->fin_data[1] = fin->fin_data[0];
+ fin->fin_data[0] = ntohs(nport);
+ natl = nat6_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
+ (u_int)fin->fin_p, &in.in6, &fin->fin_src6.in6);
+ fin->fin_data[0] = sp;
+ fin->fin_data[1] = dp;
+ if (natl != NULL)
+ return -1;
+
+ nat->nat_inip6 = in;
+ nat->nat_outip6 = fin->fin_dst6;
+ nat->nat_oip6 = fin->fin_src6;
+ if ((nat->nat_hm == NULL) && ((np->in_flags & IPN_STICKY) != 0))
+ nat->nat_hm = nat6_hostmap(np, &fin->fin_src6,
+ &fin->fin_dst6, &in, (u_32_t)dport, ifs);
+
+ ni->nai_nport = nport;
+ ni->nai_port = sport;
+
+ if (flags & IPN_TCPUDP) {
+ nat->nat_inport = nport;
+ nat->nat_outport = dport;
+ nat->nat_oport = sport;
+ ((tcphdr_t *)fin->fin_dp)->th_dport = nport;
+ } else if (flags & IPN_ICMPQUERY) {
+ ((struct icmp6_hdr *)fin->fin_dp)->icmp6_id = nport;
+ nat->nat_inport = nport;
+ nat->nat_outport = nport;
+ }
+
+ return move;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat6_new */
+/* Returns: nat_t* - NULL == failure to create new NAT structure, */
+/* else pointer to new NAT structure */
+/* Parameters: fin(I) - pointer to packet information */
+/* np(I) - pointer to NAT rule */
+/* natsave(I) - pointer to where to store NAT struct pointer */
+/* flags(I) - flags describing the current packet */
+/* direction(I) - direction of packet (in/out) */
+/* Write Lock: ipf_nat */
+/* */
+/* Attempts to create a new NAT entry. Does not actually change the packet */
+/* in any way. */
+/* */
+/* This fucntion is in three main parts: (1) deal with creating a new NAT */
+/* structure for a "MAP" rule (outgoing NAT translation); (2) deal with */
+/* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */
+/* and (3) building that structure and putting it into the NAT table(s). */
+/* ------------------------------------------------------------------------ */
+nat_t *nat6_new(fin, np, natsave, flags, direction)
+fr_info_t *fin;
+ipnat_t *np;
+nat_t **natsave;
+u_int flags;
+int direction;
+{
+ tcphdr_t *tcp = NULL;
+ hostmap_t *hm = NULL;
+ nat_t *nat, *natl;
+ u_int nflags;
+ natinfo_t ni;
+ int move;
+ ipf_stack_t *ifs = fin->fin_ifs;
+
+ /*
+ * Trigger automatic call to nat_extraflush() if the
+ * table has reached capcity specified by hi watermark.
+ */
+ if (NAT_TAB_WATER_LEVEL(ifs) > ifs->ifs_nat_flush_lvl_hi)
+ ifs->ifs_nat_doflush = 1;
+
+ if (ifs->ifs_nat_stats.ns_inuse >= ifs->ifs_ipf_nattable_max) {
+ ifs->ifs_nat_stats.ns_memfail++;
+ return NULL;
+ }
+
+ move = 1;
+ nflags = np->in_flags & flags;
+ nflags &= NAT_FROMRULE;
+
+ ni.nai_np = np;
+ ni.nai_nflags = nflags;
+ ni.nai_flags = flags;
+
+ /* Give me a new nat */
+ KMALLOC(nat, nat_t *);
+ if (nat == NULL) {
+ ifs->ifs_nat_stats.ns_memfail++;
+ /*
+ * Try to automatically tune the max # of entries in the
+ * table allowed to be less than what will cause kmem_alloc()
+ * to fail and try to eliminate panics due to out of memory
+ * conditions arising.
+ */
+ if (ifs->ifs_ipf_nattable_max > ifs->ifs_ipf_nattable_sz) {
+ ifs->ifs_ipf_nattable_max =
+ ifs->ifs_nat_stats.ns_inuse - 100;
+ printf("ipf_nattable_max reduced to %d\n",
+ ifs->ifs_ipf_nattable_max);
+ }
+ return NULL;
+ }
+
+ if (flags & IPN_TCPUDP) {
+ tcp = fin->fin_dp;
+ ni.nai_sport = htons(fin->fin_sport);
+ ni.nai_dport = htons(fin->fin_dport);
+ } else if (flags & IPN_ICMPQUERY) {
+ /*
+ * In the ICMP query NAT code, we translate the ICMP id fields
+ * to make them unique. This is indepedent of the ICMP type
+ * (e.g. in the unlikely event that a host sends an echo and
+ * an tstamp request with the same id, both packets will have
+ * their ip address/id field changed in the same way).
+ *
+ * The icmp_id field is used by the sender to identify the
+ * process making the icmp request. (the receiver justs
+ * copies it back in its response). So, it closely matches
+ * the concept of source port. We overlay sport, so we can
+ * maximally reuse the existing code.
+ */
+ ni.nai_sport = ((struct icmp6_hdr *)fin->fin_dp)->icmp6_id;
+ ni.nai_dport = ni.nai_sport;
+ }
+
+ bzero((char *)nat, sizeof (*nat));
+ nat->nat_flags = flags;
+ nat->nat_redir = np->in_redir;
+
+ if ((flags & NAT_SLAVE) == 0) {
+ MUTEX_ENTER(&ifs->ifs_ipf_nat_new);
+ }
+
+ /*
+ * Search the current table for a match.
+ */
+ if (direction == NAT_OUTBOUND) {
+ /*
+ * We can now arrange to call this for the same connection
+ * because ipf_nat_new doesn't protect the code path into
+ * this function.
+ */
+ natl = nat6_outlookup(fin, nflags, (u_int)fin->fin_p,
+ &fin->fin_src6.in6, &fin->fin_dst6.in6);
+ if (natl != NULL) {
+ KFREE(nat);
+ nat = natl;
+ goto done;
+ }
+
+ move = nat6_newmap(fin, nat, &ni);
+ if (move == -1)
+ goto badnat;
+
+ np = ni.nai_np;
+ } else {
+ /*
+ * NAT_INBOUND is used only for redirects rules
+ */
+ natl = nat6_inlookup(fin, nflags, (u_int)fin->fin_p,
+ &fin->fin_src6.in6, &fin->fin_dst6.in6);
+ if (natl != NULL) {
+ KFREE(nat);
+ nat = natl;
+ goto done;
+ }
+
+ move = nat6_newrdr(fin, nat, &ni);
+ if (move == -1)
+ goto badnat;
+
+ np = ni.nai_np;
+ }
+
+ if ((move == 1) && (np->in_flags & IPN_ROUNDR)) {
+ if (np->in_redir == NAT_REDIRECT) {
+ nat_delrdr(np);
+ nat6_addrdr(np, ifs);
+ } else if (np->in_redir == NAT_MAP) {
+ nat_delnat(np);
+ nat6_addnat(np, ifs);
+ }
+ }
+
+ if (nat6_finalise(fin, nat, &ni, tcp, natsave, direction) == -1) {
+ goto badnat;
+ }
+
+ nat_calc_chksum_diffs(nat);
+
+ if (flags & SI_WILDP)
+ ifs->ifs_nat_stats.ns_wilds++;
+ goto done;
+badnat:
+ ifs->ifs_nat_stats.ns_badnat++;
+ if ((hm = nat->nat_hm) != NULL)
+ fr_hostmapdel(&hm);
+ KFREE(nat);
+ nat = NULL;
+done:
+ if ((flags & NAT_SLAVE) == 0) {
+ MUTEX_EXIT(&ifs->ifs_ipf_nat_new);
+ }
+ return nat;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat6_finalise */
+/* Returns: int - 0 == sucess, -1 == failure */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to NAT entry */
+/* ni(I) - pointer to structure with misc. information needed */
+/* to create new NAT entry. */
+/* Write Lock: ipf_nat */
+/* */
+/* This is the tail end of constructing a new NAT entry and is the same */
+/* for both IPv4 and IPv6. */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+static INLINE int nat6_finalise(fin, nat, ni, tcp, natsave, direction)
+fr_info_t *fin;
+nat_t *nat;
+natinfo_t *ni;
+tcphdr_t *tcp;
+nat_t **natsave;
+int direction;
+{
+ frentry_t *fr;
+ ipnat_t *np;
+ ipf_stack_t *ifs = fin->fin_ifs;
+
+ np = ni->nai_np;
+
+ COPYIFNAME(fin->fin_ifp, nat->nat_ifnames[0], fin->fin_v);
+
+#ifdef IPFILTER_SYNC
+ if ((nat->nat_flags & SI_CLONE) == 0)
+ nat->nat_sync = ipfsync_new(SMC_NAT, fin, nat);
+#endif
+
+ nat->nat_me = natsave;
+ nat->nat_dir = direction;
+ nat->nat_ifps[0] = np->in_ifps[0];
+ nat->nat_ifps[1] = np->in_ifps[1];
+ nat->nat_ptr = np;
+ nat->nat_p = fin->fin_p;
+ nat->nat_v = fin->fin_v;
+ nat->nat_mssclamp = np->in_mssclamp;
+ fr = fin->fin_fr;
+ nat->nat_fr = fr;
+ nat->nat_v = 6;
+
+#ifdef IPF_V6_PROXIES
+ if ((np->in_apr != NULL) && ((ni->nai_flags & NAT_SLAVE) == 0))
+ if (appr_new(fin, nat) == -1)
+ return -1;
+#endif
+
+ if (nat6_insert(nat, fin->fin_rev, ifs) == 0) {
+ if (ifs->ifs_nat_logging)
+ nat_log(nat, (u_int)np->in_redir, ifs);
+ np->in_use++;
+ if (fr != NULL) {
+ MUTEX_ENTER(&fr->fr_lock);
+ fr->fr_ref++;
+ MUTEX_EXIT(&fr->fr_lock);
+ }
+ return 0;
+ }
+
+ /*
+ * nat6_insert failed, so cleanup time...
+ */
+ return -1;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat6_insert */
+/* Returns: int - 0 == sucess, -1 == failure */
+/* Parameters: nat(I) - pointer to NAT structure */
+/* rev(I) - flag indicating forward/reverse direction of packet */
+/* Write Lock: ipf_nat */
+/* */
+/* Insert a NAT entry into the hash tables for searching and add it to the */
+/* list of active NAT entries. Adjust global counters when complete. */
+/* ------------------------------------------------------------------------ */
+int nat6_insert(nat, rev, ifs)
+nat_t *nat;
+int rev;
+ipf_stack_t *ifs;
+{
+ u_int hv1, hv2;
+ nat_t **natp;
+
+ /*
+ * Try and return an error as early as possible, so calculate the hash
+ * entry numbers first and then proceed.
+ */
+ if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) {
+ hv1 = NAT_HASH_FN6(&nat->nat_inip6, nat->nat_inport,
+ 0xffffffff);
+ hv1 = NAT_HASH_FN6(&nat->nat_oip6, hv1 + nat->nat_oport,
+ ifs->ifs_ipf_nattable_sz);
+ hv2 = NAT_HASH_FN6(&nat->nat_outip6, nat->nat_outport,
+ 0xffffffff);
+ hv2 = NAT_HASH_FN6(&nat->nat_oip6, hv2 + nat->nat_oport,
+ ifs->ifs_ipf_nattable_sz);
+ } else {
+ hv1 = NAT_HASH_FN6(&nat->nat_inip6, 0, 0xffffffff);
+ hv1 = NAT_HASH_FN6(&nat->nat_oip6, hv1,
+ ifs->ifs_ipf_nattable_sz);
+ hv2 = NAT_HASH_FN6(&nat->nat_outip6, 0, 0xffffffff);
+ hv2 = NAT_HASH_FN6(&nat->nat_oip6, hv2,
+ ifs->ifs_ipf_nattable_sz);
+ }
+
+ if ((ifs->ifs_nat_stats.ns_bucketlen[0][hv1] >=
+ ifs->ifs_fr_nat_maxbucket) ||
+ (ifs->ifs_nat_stats.ns_bucketlen[1][hv2] >=
+ ifs->ifs_fr_nat_maxbucket)) {
+ return -1;
+ }
+
+ nat->nat_hv[0] = hv1;
+ nat->nat_hv[1] = hv2;
+
+ MUTEX_INIT(&nat->nat_lock, "nat entry lock");
+
+ nat->nat_rev = rev;
+ nat->nat_ref = 1;
+ nat->nat_bytes[0] = 0;
+ nat->nat_pkts[0] = 0;
+ nat->nat_bytes[1] = 0;
+ nat->nat_pkts[1] = 0;
+
+ nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0';
+ nat->nat_ifps[0] = fr_resolvenic(nat->nat_ifnames[0], 6, ifs);
+
+ if (nat->nat_ifnames[1][0] !='\0') {
+ nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
+ nat->nat_ifps[1] = fr_resolvenic(nat->nat_ifnames[1], 6, ifs);
+ } else {
+ (void) strncpy(nat->nat_ifnames[1], nat->nat_ifnames[0],
+ LIFNAMSIZ);
+ nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
+ nat->nat_ifps[1] = nat->nat_ifps[0];
+ }
+
+ nat->nat_next = ifs->ifs_nat_instances;
+ nat->nat_pnext = &ifs->ifs_nat_instances;
+ if (ifs->ifs_nat_instances)
+ ifs->ifs_nat_instances->nat_pnext = &nat->nat_next;
+ ifs->ifs_nat_instances = nat;
+
+ natp = &ifs->ifs_nat_table[0][hv1];
+ if (*natp)
+ (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
+ nat->nat_phnext[0] = natp;
+ nat->nat_hnext[0] = *natp;
+ *natp = nat;
+ ifs->ifs_nat_stats.ns_bucketlen[0][hv1]++;
+
+ natp = &ifs->ifs_nat_table[1][hv2];
+ if (*natp)
+ (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
+ nat->nat_phnext[1] = natp;
+ nat->nat_hnext[1] = *natp;
+ *natp = nat;
+ ifs->ifs_nat_stats.ns_bucketlen[1][hv2]++;
+
+ fr_setnatqueue(nat, rev, ifs);
+
+ ifs->ifs_nat_stats.ns_added++;
+ ifs->ifs_nat_stats.ns_inuse++;
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat6_icmperrorlookup */
+/* Returns: nat_t* - point to matching NAT structure */
+/* Parameters: fin(I) - pointer to packet information */
+/* dir(I) - direction of packet (in/out) */
+/* */
+/* Check if the ICMP error message is related to an existing TCP, UDP or */
+/* ICMP query nat entry. It is assumed that the packet is already of the */
+/* the required length. */
+/* ------------------------------------------------------------------------ */
+nat_t *nat6_icmperrorlookup(fin, dir)
+fr_info_t *fin;
+int dir;
+{
+ int flags = 0, minlen;
+ struct icmp6_hdr *orgicmp;
+ tcphdr_t *tcp = NULL;
+ u_short data[2];
+ nat_t *nat;
+ ip6_t *oip6;
+ u_int p;
+
+ minlen = 40;
+ /*
+ * Does it at least have the return (basic) IP header ?
+ * Only a basic IP header (no options) should be with an ICMP error
+ * header. Also, if it's not an error type, then return.
+ */
+ if (!(fin->fin_flx & FI_ICMPERR))
+ return NULL;
+
+ /*
+ * Check packet size
+ */
+ if (fin->fin_plen < ICMP6ERR_IPICMPHLEN)
+ return NULL;
+ oip6 = (ip6_t *)((char *)fin->fin_dp + 8);
+
+ /*
+ * Is the buffer big enough for all of it ? It's the size of the IP
+ * header claimed in the encapsulated part which is of concern. It
+ * may be too big to be in this buffer but not so big that it's
+ * outside the ICMP packet, leading to TCP deref's causing problems.
+ * This is possible because we don't know how big oip_hl is when we
+ * do the pullup early in fr_check() and thus can't gaurantee it is
+ * all here now.
+ */
+#ifdef _KERNEL
+ {
+ mb_t *m;
+
+ m = fin->fin_m;
+# if defined(MENTAT)
+ if ((char *)oip6 + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr)
+ return NULL;
+# else
+ if ((char *)oip6 + fin->fin_dlen - ICMPERR_ICMPHLEN >
+ (char *)fin->fin_ip + M_LEN(m))
+ return NULL;
+# endif
+ }
+#endif
+
+ if (IP6_NEQ(&fin->fin_dst6, &oip6->ip6_src))
+ return NULL;
+
+ p = oip6->ip6_nxt;
+ if (p == IPPROTO_TCP)
+ flags = IPN_TCP;
+ else if (p == IPPROTO_UDP)
+ flags = IPN_UDP;
+ else if (p == IPPROTO_ICMPV6) {
+ orgicmp = (struct icmp6_hdr *)(oip6 + 1);
+
+ /* see if this is related to an ICMP query */
+ if (nat_icmpquerytype6(orgicmp->icmp6_type)) {
+ data[0] = fin->fin_data[0];
+ data[1] = fin->fin_data[1];
+ fin->fin_data[0] = 0;
+ fin->fin_data[1] = orgicmp->icmp6_id;
+
+ flags = IPN_ICMPERR|IPN_ICMPQUERY;
+ /*
+ * NOTE : dir refers to the direction of the original
+ * ip packet. By definition the icmp error
+ * message flows in the opposite direction.
+ */
+ if (dir == NAT_INBOUND)
+ nat = nat6_inlookup(fin, flags, p,
+ &oip6->ip6_dst, &oip6->ip6_src);
+ else
+ nat = nat6_outlookup(fin, flags, p,
+ &oip6->ip6_dst, &oip6->ip6_src);
+ fin->fin_data[0] = data[0];
+ fin->fin_data[1] = data[1];
+ return nat;
+ }
+ }
+
+ if (flags & IPN_TCPUDP) {
+ minlen += 8; /* + 64bits of data to get ports */
+ if (fin->fin_plen < ICMPERR_ICMPHLEN + minlen)
+ return NULL;
+
+ data[0] = fin->fin_data[0];
+ data[1] = fin->fin_data[1];
+ tcp = (tcphdr_t *)(oip6 + 1);
+ fin->fin_data[0] = ntohs(tcp->th_dport);
+ fin->fin_data[1] = ntohs(tcp->th_sport);
+
+ if (dir == NAT_INBOUND) {
+ nat = nat6_inlookup(fin, flags, p,
+ &oip6->ip6_dst, &oip6->ip6_src);
+ } else {
+ nat = nat6_outlookup(fin, flags, p,
+ &oip6->ip6_dst, &oip6->ip6_src);
+ }
+ fin->fin_data[0] = data[0];
+ fin->fin_data[1] = data[1];
+ return nat;
+ }
+ if (dir == NAT_INBOUND)
+ return nat6_inlookup(fin, 0, p, &oip6->ip6_dst, &oip6->ip6_src);
+ else
+ return nat6_outlookup(fin, 0, p, &oip6->ip6_dst,
+ &oip6->ip6_src);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat6_icmperror */
+/* Returns: nat_t* - point to matching NAT structure */
+/* Parameters: fin(I) - pointer to packet information */
+/* nflags(I) - NAT flags for this packet */
+/* dir(I) - direction of packet (in/out) */
+/* */
+/* Fix up an ICMP packet which is an error message for an existing NAT */
+/* session. This will correct both packet header data and checksums. */
+/* */
+/* This should *ONLY* be used for incoming ICMP error packets to make sure */
+/* a NAT'd ICMP packet gets correctly recognised. */
+/* ------------------------------------------------------------------------ */
+nat_t *nat6_icmperror(fin, nflags, dir)
+fr_info_t *fin;
+u_int *nflags;
+int dir;
+{
+ u_32_t sum1, sum2, sumd, psum1, psum2, psumd, sumd1;
+ i6addr_t in;
+ struct icmp6_hdr *icmp6, *orgicmp;
+ int dlen;
+ udphdr_t *udp;
+ tcphdr_t *tcp;
+ nat_t *nat;
+ ip6_t *oip6;
+ if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY)))
+ return NULL;
+
+ /*
+ * nat6_icmperrorlookup() looks up nat entry associated with the
+ * offending IP packet and returns pointer to the entry, or NULL
+ * if packet wasn't natted or for `defective' packets.
+ */
+
+ if ((fin->fin_v != 6) || !(nat = nat6_icmperrorlookup(fin, dir)))
+ return NULL;
+
+ sumd1 = 0;
+ *nflags = IPN_ICMPERR;
+ icmp6 = fin->fin_dp;
+ oip6 = (ip6_t *)((char *)icmp6 + sizeof (*icmp6));
+ udp = (udphdr_t *)(((char *)oip6) + sizeof (*oip6));
+ tcp = (tcphdr_t *)udp;
+ dlen = fin->fin_plen - ((char *)udp - (char *)fin->fin_ip);
+
+ /*
+ * Need to adjust ICMP header to include the real IP#'s and
+ * port #'s. There are three steps required.
+ *
+ * Step 1
+ * No update needed for ip6 header checksum.
+ *
+ * Unlike IPv4, we need to update icmp_cksum for IPv6 address
+ * changes because there's no ip_sum change to cancel it.
+ */
+
+ if (IP6_EQ((i6addr_t *)&oip6->ip6_dst, &nat->nat_oip6)) {
+ sum1 = LONG_SUM6((i6addr_t *)&oip6->ip6_src);
+ in = nat->nat_inip6;
+ oip6->ip6_src = in.in6;
+ } else {
+ sum1 = LONG_SUM6((i6addr_t *)&oip6->ip6_dst);
+ in = nat->nat_outip6;
+ oip6->ip6_dst = in.in6;
+ }
+
+ sum2 = LONG_SUM6(&in);
+ CALC_SUMD(sum1, sum2, sumd);
+
+ /*
+ * Step 2
+ * Perform other adjustments based on protocol of offending packet.
+ */
+
+ switch (oip6->ip6_nxt) {
+ case IPPROTO_TCP :
+ case IPPROTO_UDP :
+
+ /*
+ * For offending TCP/UDP IP packets, translate the ports
+ * based on the NAT specification.
+ *
+ * Advance notice : Now it becomes complicated :-)
+ *
+ * Since the port and IP addresse fields are both part
+ * of the TCP/UDP checksum of the offending IP packet,
+ * we need to adjust that checksum as well.
+ *
+ * To further complicate things, the TCP/UDP checksum
+ * may not be present. We must check to see if the
+ * length of the data portion is big enough to hold
+ * the checksum. In the UDP case, a test to determine
+ * if the checksum is even set is also required.
+ *
+ * Any changes to an IP address, port or checksum within
+ * the ICMP packet requires a change to icmp_cksum.
+ *
+ * Be extremely careful here ... The change is dependent
+ * upon whether or not the TCP/UPD checksum is present.
+ *
+ * If TCP/UPD checksum is present, the icmp_cksum must
+ * compensate for checksum modification resulting from
+ * IP address change only. Port change and resulting
+ * data checksum adjustments cancel each other out.
+ *
+ * If TCP/UDP checksum is not present, icmp_cksum must
+ * compensate for port change only. The IP address
+ * change does not modify anything else in this case.
+ */
+
+ psum1 = 0;
+ psum2 = 0;
+ psumd = 0;
+
+ if ((tcp->th_dport == nat->nat_oport) &&
+ (tcp->th_sport != nat->nat_inport)) {
+
+ /*
+ * Translate the source port.
+ */
+
+ psum1 = ntohs(tcp->th_sport);
+ psum2 = ntohs(nat->nat_inport);
+ tcp->th_sport = nat->nat_inport;
+
+ } else if ((tcp->th_sport == nat->nat_oport) &&
+ (tcp->th_dport != nat->nat_outport)) {
+
+ /*
+ * Translate the destination port.
+ */
+
+ psum1 = ntohs(tcp->th_dport);
+ psum2 = ntohs(nat->nat_outport);
+ tcp->th_dport = nat->nat_outport;
+ }
+
+ if ((oip6->ip6_nxt == IPPROTO_TCP) && (dlen >= 18)) {
+
+ /*
+ * TCP checksum present.
+ *
+ * Adjust data checksum and icmp checksum to
+ * compensate for any IP address change.
+ */
+
+ sum1 = ntohs(tcp->th_sum);
+ fix_datacksum(&tcp->th_sum, sumd);
+ sum2 = ntohs(tcp->th_sum);
+ CALC_SUMD(sum1, sum2, sumd);
+ sumd1 += sumd;
+
+ /*
+ * Also make data checksum adjustment to
+ * compensate for any port change.
+ */
+
+ if (psum1 != psum2) {
+ CALC_SUMD(psum1, psum2, psumd);
+ fix_datacksum(&tcp->th_sum, psumd);
+ }
+
+ } else if ((oip6->ip6_nxt == IPPROTO_UDP) &&
+ (dlen >= 8) && (udp->uh_sum != 0)) {
+
+ /*
+ * The UDP checksum is present and set.
+ *
+ * Adjust data checksum and icmp checksum to
+ * compensate for any IP address change.
+ */
+
+ sum1 = ntohs(udp->uh_sum);
+ fix_datacksum(&udp->uh_sum, sumd);
+ sum2 = ntohs(udp->uh_sum);
+ CALC_SUMD(sum1, sum2, sumd);
+ sumd1 += sumd;
+
+ /*
+ * Also make data checksum adjustment to
+ * compensate for any port change.
+ */
+
+ if (psum1 != psum2) {
+ CALC_SUMD(psum1, psum2, psumd);
+ fix_datacksum(&udp->uh_sum, psumd);
+ }
+
+ } else {
+
+ /*
+ * Data checksum was not present.
+ *
+ * Compensate for any port change.
+ */
+
+ CALC_SUMD(psum2, psum1, psumd);
+ sumd1 += psumd;
+ }
+ break;
+
+ case IPPROTO_ICMPV6 :
+
+ orgicmp = (struct icmp6_hdr *)udp;
+
+ if ((nat->nat_dir == NAT_OUTBOUND) &&
+ (orgicmp->icmp6_id != nat->nat_inport) &&
+ (dlen >= 8)) {
+
+ /*
+ * Fix ICMP checksum (of the offening ICMP
+ * query packet) to compensate the change
+ * in the ICMP id of the offending ICMP
+ * packet.
+ *
+ * Since you modify orgicmp->icmp_id with
+ * a delta (say x) and you compensate that
+ * in origicmp->icmp_cksum with a delta
+ * minus x, you don't have to adjust the
+ * overall icmp->icmp_cksum
+ */
+
+ sum1 = ntohs(orgicmp->icmp6_id);
+ sum2 = ntohs(nat->nat_inport);
+ CALC_SUMD(sum1, sum2, sumd);
+ orgicmp->icmp6_id = nat->nat_inport;
+ fix_datacksum(&orgicmp->icmp6_cksum, sumd);
+
+ } /* nat_dir can't be NAT_INBOUND for icmp queries */
+
+ break;
+
+ default :
+
+ break;
+
+ } /* switch (oip6->ip6_nxt) */
+
+ /*
+ * Step 3
+ * Make the adjustments to icmp checksum.
+ */
+
+ if (sumd1 != 0) {
+ sumd1 = (sumd1 & 0xffff) + (sumd1 >> 16);
+ sumd1 = (sumd1 & 0xffff) + (sumd1 >> 16);
+ fix_incksum(&icmp6->icmp6_cksum, sumd1);
+ }
+ return nat;
+}
+
+
+/*
+ * NB: these lookups don't lock access to the list, it assumed that it has
+ * already been done!
+ */
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat6_inlookup */
+/* Returns: nat_t* - NULL == no match, */
+/* else pointer to matching NAT entry */
+/* Parameters: fin(I) - pointer to packet information */
+/* flags(I) - NAT flags for this packet */
+/* p(I) - protocol for this packet */
+/* src(I) - source IP address */
+/* mapdst(I) - destination IP address */
+/* */
+/* Lookup a nat entry based on the mapped destination ip address/port and */
+/* real source address/port. We use this lookup when receiving a packet, */
+/* we're looking for a table entry, based on the destination address. */
+/* */
+/* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */
+/* */
+/* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */
+/* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */
+/* */
+/* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */
+/* the packet is of said protocol */
+/* ------------------------------------------------------------------------ */
+nat_t *nat6_inlookup(fin, flags, p, src, mapdst)
+fr_info_t *fin;
+u_int flags, p;
+struct in6_addr *src, *mapdst;
+{
+ u_short sport, dport;
+ u_int sflags;
+ nat_t *nat;
+ int nflags;
+ i6addr_t dst;
+ void *ifp;
+ u_int hv;
+ ipf_stack_t *ifs = fin->fin_ifs;
+
+ if (fin != NULL)
+ ifp = fin->fin_ifp;
+ else
+ ifp = NULL;
+ sport = 0;
+ dport = 0;
+ dst.in6 = *mapdst;
+ sflags = flags & NAT_TCPUDPICMP;
+
+ switch (p)
+ {
+ case IPPROTO_TCP :
+ case IPPROTO_UDP :
+ sport = htons(fin->fin_data[0]);
+ dport = htons(fin->fin_data[1]);
+ break;
+ case IPPROTO_ICMPV6 :
+ if (flags & IPN_ICMPERR)
+ sport = fin->fin_data[1];
+ else
+ dport = fin->fin_data[1];
+ break;
+ default :
+ break;
+ }
+
+
+ if ((flags & SI_WILDP) != 0)
+ goto find_in_wild_ports;
+
+ hv = NAT_HASH_FN6(&dst, dport, 0xffffffff);
+ hv = NAT_HASH_FN6(src, hv + sport, ifs->ifs_ipf_nattable_sz);
+ nat = ifs->ifs_nat_table[1][hv];
+ for (; nat; nat = nat->nat_hnext[1]) {
+ if (nat->nat_v != 6)
+ continue;
+
+ if (nat->nat_ifps[0] != NULL) {
+ if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
+ continue;
+ } else if (ifp != NULL)
+ nat->nat_ifps[0] = ifp;
+
+ nflags = nat->nat_flags;
+
+ if (IP6_EQ(&nat->nat_oip6, src) &&
+ IP6_EQ(&nat->nat_outip6, &dst) &&
+ (((p == 0) &&
+ (sflags == (nat->nat_flags & IPN_TCPUDPICMP))) ||
+ (p == nat->nat_p))) {
+ switch (p)
+ {
+#if 0
+ case IPPROTO_GRE :
+ if (nat->nat_call[1] != fin->fin_data[0])
+ continue;
+ break;
+#endif
+ case IPPROTO_ICMPV6 :
+ if ((flags & IPN_ICMPERR) != 0) {
+ if (nat->nat_outport != sport)
+ continue;
+ } else {
+ if (nat->nat_outport != dport)
+ continue;
+ }
+ break;
+ case IPPROTO_TCP :
+ case IPPROTO_UDP :
+ if (nat->nat_oport != sport)
+ continue;
+ if (nat->nat_outport != dport)
+ continue;
+ break;
+ default :
+ break;
+ }
+
+#ifdef IPF_V6_PROXIES
+ ipn = nat->nat_ptr;
+ if ((ipn != NULL) && (nat->nat_aps != NULL))
+ if (appr_match(fin, nat) != 0)
+ continue;
+#endif
+ return nat;
+ }
+ }
+
+ /*
+ * So if we didn't find it but there are wildcard members in the hash
+ * table, go back and look for them. We do this search and update here
+ * because it is modifying the NAT table and we want to do this only
+ * for the first packet that matches. The exception, of course, is
+ * for "dummy" (FI_IGNORE) lookups.
+ */
+find_in_wild_ports:
+ if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH))
+ return NULL;
+ if (ifs->ifs_nat_stats.ns_wilds == 0)
+ return NULL;
+
+ RWLOCK_EXIT(&ifs->ifs_ipf_nat);
+
+ hv = NAT_HASH_FN6(&dst, 0, 0xffffffff);
+ hv = NAT_HASH_FN6(src, hv, ifs->ifs_ipf_nattable_sz);
+
+ WRITE_ENTER(&ifs->ifs_ipf_nat);
+
+ nat = ifs->ifs_nat_table[1][hv];
+ for (; nat; nat = nat->nat_hnext[1]) {
+ if (nat->nat_v != 6)
+ continue;
+
+ if (nat->nat_ifps[0] != NULL) {
+ if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
+ continue;
+ } else if (ifp != NULL)
+ nat->nat_ifps[0] = ifp;
+
+ if (nat->nat_p != fin->fin_p)
+ continue;
+ if (IP6_NEQ(&nat->nat_oip6, src) ||
+ IP6_NEQ(&nat->nat_outip6, &dst))
+ continue;
+
+ nflags = nat->nat_flags;
+ if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
+ continue;
+
+ if (nat_wildok(nat, (int)sport, (int)dport, nflags,
+ NAT_INBOUND) == 1) {
+ if ((fin->fin_flx & FI_IGNORE) != 0)
+ break;
+ if ((nflags & SI_CLONE) != 0) {
+ nat = fr_natclone(fin, nat);
+ if (nat == NULL)
+ break;
+ } else {
+ MUTEX_ENTER(&ifs->ifs_ipf_nat_new);
+ ifs->ifs_nat_stats.ns_wilds--;
+ MUTEX_EXIT(&ifs->ifs_ipf_nat_new);
+ }
+ nat->nat_oport = sport;
+ nat->nat_outport = dport;
+ nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
+ nat6_tabmove(nat, ifs);
+ break;
+ }
+ }
+
+ MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
+
+ return nat;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat6_tabmove */
+/* Returns: Nil */
+/* Parameters: nat(I) - pointer to NAT structure */
+/* Write Lock: ipf_nat */
+/* */
+/* This function is only called for TCP/UDP NAT table entries where the */
+/* original was placed in the table without hashing on the ports and we now */
+/* want to include hashing on port numbers. */
+/* ------------------------------------------------------------------------ */
+static void nat6_tabmove(nat, ifs)
+nat_t *nat;
+ipf_stack_t *ifs;
+{
+ nat_t **natp;
+ u_int hv;
+
+ if (nat->nat_flags & SI_CLONE)
+ return;
+
+ /*
+ * Remove the NAT entry from the old location
+ */
+ if (nat->nat_hnext[0])
+ nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
+ *nat->nat_phnext[0] = nat->nat_hnext[0];
+ ifs->ifs_nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--;
+
+ if (nat->nat_hnext[1])
+ nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
+ *nat->nat_phnext[1] = nat->nat_hnext[1];
+ ifs->ifs_nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--;
+
+ /*
+ * Add into the NAT table in the new position
+ */
+ hv = NAT_HASH_FN6(&nat->nat_inip6, nat->nat_inport, 0xffffffff);
+ hv = NAT_HASH_FN6(&nat->nat_oip6, hv + nat->nat_oport,
+ ifs->ifs_ipf_nattable_sz);
+ nat->nat_hv[0] = hv;
+ natp = &ifs->ifs_nat_table[0][hv];
+ if (*natp)
+ (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
+ nat->nat_phnext[0] = natp;
+ nat->nat_hnext[0] = *natp;
+ *natp = nat;
+ ifs->ifs_nat_stats.ns_bucketlen[0][hv]++;
+
+ hv = NAT_HASH_FN6(&nat->nat_outip6, nat->nat_outport, 0xffffffff);
+ hv = NAT_HASH_FN6(&nat->nat_oip6, hv + nat->nat_oport,
+ ifs->ifs_ipf_nattable_sz);
+ nat->nat_hv[1] = hv;
+ natp = &ifs->ifs_nat_table[1][hv];
+ if (*natp)
+ (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
+ nat->nat_phnext[1] = natp;
+ nat->nat_hnext[1] = *natp;
+ *natp = nat;
+ ifs->ifs_nat_stats.ns_bucketlen[1][hv]++;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat6_outlookup */
+/* Returns: nat_t* - NULL == no match, */
+/* else pointer to matching NAT entry */
+/* Parameters: fin(I) - pointer to packet information */
+/* flags(I) - NAT flags for this packet */
+/* p(I) - protocol for this packet */
+/* src(I) - source IP address */
+/* dst(I) - destination IP address */
+/* rw(I) - 1 == write lock on ipf_nat held, 0 == read lock. */
+/* */
+/* Lookup a nat entry based on the source 'real' ip address/port and */
+/* destination address/port. We use this lookup when sending a packet out, */
+/* we're looking for a table entry, based on the source address. */
+/* */
+/* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */
+/* */
+/* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */
+/* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */
+/* */
+/* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */
+/* the packet is of said protocol */
+/* ------------------------------------------------------------------------ */
+nat_t *nat6_outlookup(fin, flags, p, src, dst)
+fr_info_t *fin;
+u_int flags, p;
+struct in6_addr *src , *dst;
+{
+ u_short sport, dport;
+ u_int sflags;
+ nat_t *nat;
+ int nflags;
+ void *ifp;
+ u_int hv;
+ ipf_stack_t *ifs = fin->fin_ifs;
+
+ ifp = fin->fin_ifp;
+
+ sflags = flags & IPN_TCPUDPICMP;
+ sport = 0;
+ dport = 0;
+
+ switch (p)
+ {
+ case IPPROTO_TCP :
+ case IPPROTO_UDP :
+ sport = htons(fin->fin_data[0]);
+ dport = htons(fin->fin_data[1]);
+ break;
+ case IPPROTO_ICMPV6 :
+ if (flags & IPN_ICMPERR)
+ sport = fin->fin_data[1];
+ else
+ dport = fin->fin_data[1];
+ break;
+ default :
+ break;
+ }
+
+ if ((flags & SI_WILDP) != 0)
+ goto find_out_wild_ports;
+
+ hv = NAT_HASH_FN6(src, sport, 0xffffffff);
+ hv = NAT_HASH_FN6(dst, hv + dport, ifs->ifs_ipf_nattable_sz);
+ nat = ifs->ifs_nat_table[0][hv];
+ for (; nat; nat = nat->nat_hnext[0]) {
+ if (nat->nat_v != 6)
+ continue;
+
+ if (nat->nat_ifps[1] != NULL) {
+ if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
+ continue;
+ } else if (ifp != NULL)
+ nat->nat_ifps[1] = ifp;
+
+ nflags = nat->nat_flags;
+
+ if (IP6_EQ(&nat->nat_inip6, src) &&
+ IP6_EQ(&nat->nat_oip6, dst) &&
+ (((p == 0) && (sflags == (nflags & NAT_TCPUDPICMP))) ||
+ (p == nat->nat_p))) {
+ switch (p)
+ {
+#if 0
+ case IPPROTO_GRE :
+ if (nat->nat_call[1] != fin->fin_data[0])
+ continue;
+ break;
+#endif
+ case IPPROTO_TCP :
+ case IPPROTO_UDP :
+ if (nat->nat_oport != dport)
+ continue;
+ if (nat->nat_inport != sport)
+ continue;
+ break;
+ default :
+ break;
+ }
+
+#ifdef IPF_V6_PROXIES
+ ipn = nat->nat_ptr;
+ if ((ipn != NULL) && (nat->nat_aps != NULL))
+ if (appr_match(fin, nat) != 0)
+ continue;
+#endif
+ return nat;
+ }
+ }
+
+ /*
+ * So if we didn't find it but there are wildcard members in the hash
+ * table, go back and look for them. We do this search and update here
+ * because it is modifying the NAT table and we want to do this only
+ * for the first packet that matches. The exception, of course, is
+ * for "dummy" (FI_IGNORE) lookups.
+ */
+find_out_wild_ports:
+ if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH))
+ return NULL;
+ if (ifs->ifs_nat_stats.ns_wilds == 0)
+ return NULL;
+
+ RWLOCK_EXIT(&ifs->ifs_ipf_nat);
+
+ hv = NAT_HASH_FN6(src, 0, 0xffffffff);
+ hv = NAT_HASH_FN6(dst, hv, ifs->ifs_ipf_nattable_sz);
+
+ WRITE_ENTER(&ifs->ifs_ipf_nat);
+
+ nat = ifs->ifs_nat_table[0][hv];
+ for (; nat; nat = nat->nat_hnext[0]) {
+ if (nat->nat_v != 6)
+ continue;
+
+ if (nat->nat_ifps[1] != NULL) {
+ if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
+ continue;
+ } else if (ifp != NULL)
+ nat->nat_ifps[1] = ifp;
+
+ if (nat->nat_p != fin->fin_p)
+ continue;
+ if (IP6_NEQ(&nat->nat_inip6, src) ||
+ IP6_NEQ(&nat->nat_oip6, dst))
+ continue;
+
+ nflags = nat->nat_flags;
+ if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
+ continue;
+
+ if (nat_wildok(nat, (int)sport, (int)dport, nflags,
+ NAT_OUTBOUND) == 1) {
+ if ((fin->fin_flx & FI_IGNORE) != 0)
+ break;
+ if ((nflags & SI_CLONE) != 0) {
+ nat = fr_natclone(fin, nat);
+ if (nat == NULL)
+ break;
+ } else {
+ MUTEX_ENTER(&ifs->ifs_ipf_nat_new);
+ ifs->ifs_nat_stats.ns_wilds--;
+ MUTEX_EXIT(&ifs->ifs_ipf_nat_new);
+ }
+ nat->nat_inport = sport;
+ nat->nat_oport = dport;
+ if (nat->nat_outport == 0)
+ nat->nat_outport = sport;
+ nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
+ nat6_tabmove(nat, ifs);
+ break;
+ }
+ }
+
+ MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
+
+ return nat;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat6_lookupredir */
+/* Returns: nat_t* - NULL == no match, */
+/* else pointer to matching NAT entry */
+/* Parameters: np(I) - pointer to description of packet to find NAT table */
+/* entry for. */
+/* */
+/* Lookup the NAT tables to search for a matching redirect */
+/* ------------------------------------------------------------------------ */
+nat_t *nat6_lookupredir(np, ifs)
+natlookup_t *np;
+ipf_stack_t *ifs;
+{
+ fr_info_t fi;
+ nat_t *nat;
+
+ bzero((char *)&fi, sizeof (fi));
+ if (np->nl_flags & IPN_IN) {
+ fi.fin_data[0] = ntohs(np->nl_realport);
+ fi.fin_data[1] = ntohs(np->nl_outport);
+ } else {
+ fi.fin_data[0] = ntohs(np->nl_inport);
+ fi.fin_data[1] = ntohs(np->nl_outport);
+ }
+ if (np->nl_flags & IPN_TCP)
+ fi.fin_p = IPPROTO_TCP;
+ else if (np->nl_flags & IPN_UDP)
+ fi.fin_p = IPPROTO_UDP;
+ else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY))
+ fi.fin_p = IPPROTO_ICMPV6;
+
+ fi.fin_ifs = ifs;
+ /*
+ * We can do two sorts of lookups:
+ * - IPN_IN: we have the `real' and `out' address, look for `in'.
+ * - default: we have the `in' and `out' address, look for `real'.
+ */
+ if (np->nl_flags & IPN_IN) {
+ if ((nat = nat6_inlookup(&fi, np->nl_flags, fi.fin_p,
+ &np->nl_realip6, &np->nl_outip6))) {
+ np->nl_inipaddr = nat->nat_inip6;
+ np->nl_inport = nat->nat_inport;
+ }
+ } else {
+ /*
+ * If nl_inip is non null, this is a lookup based on the real
+ * ip address. Else, we use the fake.
+ */
+ if ((nat = nat6_outlookup(&fi, np->nl_flags, fi.fin_p,
+ &np->nl_inip6, &np->nl_outip6))) {
+ if ((np->nl_flags & IPN_FINDFORWARD) != 0) {
+ fr_info_t fin;
+ bzero((char *)&fin, sizeof (fin));
+ fin.fin_p = nat->nat_p;
+ fin.fin_data[0] = ntohs(nat->nat_outport);
+ fin.fin_data[1] = ntohs(nat->nat_oport);
+ fin.fin_ifs = ifs;
+ if (nat6_inlookup(&fin, np->nl_flags, fin.fin_p,
+ &nat->nat_outip6.in6,
+ &nat->nat_oip6.in6) != NULL) {
+ np->nl_flags &= ~IPN_FINDFORWARD;
+ }
+ }
+
+ np->nl_realip6 = nat->nat_outip6.in6;
+ np->nl_realport = nat->nat_outport;
+ }
+ }
+
+ return nat;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat6_match */
+/* Returns: int - 0 == no match, 1 == match */
+/* Parameters: fin(I) - pointer to packet information */
+/* np(I) - pointer to NAT rule */
+/* */
+/* Pull the matching of a packet against a NAT rule out of that complex */
+/* loop inside fr_checknat6in() and lay it out properly in its own function.*/
+/* ------------------------------------------------------------------------ */
+static int nat6_match(fin, np)
+fr_info_t *fin;
+ipnat_t *np;
+{
+ frtuc_t *ft;
+
+ if (fin->fin_v != 6)
+ return 0;
+
+ if (np->in_p && fin->fin_p != np->in_p)
+ return 0;
+
+ if (fin->fin_out) {
+ if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK)))
+ return 0;
+ if (IP6_MASKNEQ(&fin->fin_src6, &np->in_in[1], &np->in_in[0])
+ ^ ((np->in_flags & IPN_NOTSRC) != 0))
+ return 0;
+ if (IP6_MASKNEQ(&fin->fin_dst6, &np->in_src[1], &np->in_src[0])
+ ^ ((np->in_flags & IPN_NOTDST) != 0))
+ return 0;
+ } else {
+ if (!(np->in_redir & NAT_REDIRECT))
+ return 0;
+ if (IP6_MASKNEQ(&fin->fin_src6, &np->in_src[1], &np->in_src[0])
+ ^ ((np->in_flags & IPN_NOTSRC) != 0))
+ return 0;
+ if (IP6_MASKNEQ(&fin->fin_dst6, &np->in_out[1], &np->in_out[0])
+ ^ ((np->in_flags & IPN_NOTDST) != 0))
+ return 0;
+ }
+
+ ft = &np->in_tuc;
+ if (!(fin->fin_flx & FI_TCPUDP) ||
+ (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
+ if (ft->ftu_scmp || ft->ftu_dcmp)
+ return 0;
+ return 1;
+ }
+
+ return fr_tcpudpchk(fin, ft);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: fr_checknat6out */
+/* Returns: int - -1 == packet failed NAT checks so block it, */
+/* 0 == no packet translation occurred, */
+/* 1 == packet was successfully translated. */
+/* Parameters: fin(I) - pointer to packet information */
+/* passp(I) - pointer to filtering result flags */
+/* */
+/* Check to see if an outcoming packet should be changed. ICMP packets are */
+/* first checked to see if they match an existing entry (if an error), */
+/* otherwise a search of the current NAT table is made. If neither results */
+/* in a match then a search for a matching NAT rule is made. Create a new */
+/* NAT entry if a we matched a NAT rule. Lastly, actually change the */
+/* packet header(s) as required. */
+/* ------------------------------------------------------------------------ */
+int fr_checknat6out(fin, passp)
+fr_info_t *fin;
+u_32_t *passp;
+{
+ struct ifnet *ifp, *sifp;
+ int rval, natfailed;
+ ipnat_t *np = NULL;
+ u_int nflags = 0;
+ i6addr_t ipa, iph;
+ int natadd = 1;
+ frentry_t *fr;
+ nat_t *nat;
+ ipf_stack_t *ifs = fin->fin_ifs;
+
+ if (ifs->ifs_nat_stats.ns_rules == 0 || ifs->ifs_fr_nat_lock != 0)
+ return 0;
+
+ natfailed = 0;
+ fr = fin->fin_fr;
+ sifp = fin->fin_ifp;
+ if ((fr != NULL) && !(fr->fr_flags & FR_DUP) &&
+ fr->fr_tifs[fin->fin_rev].fd_ifp &&
+ fr->fr_tifs[fin->fin_rev].fd_ifp != (void *)-1)
+ fin->fin_ifp = fr->fr_tifs[fin->fin_rev].fd_ifp;
+ ifp = fin->fin_ifp;
+
+ if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
+ switch (fin->fin_p)
+ {
+ case IPPROTO_TCP :
+ nflags = IPN_TCP;
+ break;
+ case IPPROTO_UDP :
+ nflags = IPN_UDP;
+ break;
+ case IPPROTO_ICMPV6 :
+ /*
+ * This is an incoming packet, so the destination is
+ * the icmp6_id and the source port equals 0
+ */
+ if ((fin->fin_flx & FI_ICMPQUERY) != 0)
+ nflags = IPN_ICMPQUERY;
+ break;
+ default :
+ break;
+ }
+
+#ifdef IPF_V6_PROXIES
+ if ((nflags & IPN_TCPUDP))
+ tcp = fin->fin_dp;
+#endif
+ }
+
+ ipa = fin->fin_src6;
+
+ READ_ENTER(&ifs->ifs_ipf_nat);
+
+ if ((fin->fin_p == IPPROTO_ICMPV6) && !(nflags & IPN_ICMPQUERY) &&
+ (nat = nat6_icmperror(fin, &nflags, NAT_OUTBOUND)))
+ /*EMPTY*/;
+ else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin)))
+ natadd = 0;
+ else if ((nat = nat6_outlookup(fin, nflags|NAT_SEARCH,
+ (u_int)fin->fin_p, &fin->fin_src6.in6,
+ &fin->fin_dst6.in6))) {
+ nflags = nat->nat_flags;
+ } else {
+ u_32_t hv, nmsk;
+ i6addr_t msk;
+ int i;
+
+ /*
+ * If there is no current entry in the nat table for this IP#,
+ * create one for it (if there is a matching rule).
+ */
+ RWLOCK_EXIT(&ifs->ifs_ipf_nat);
+ i = 3;
+ msk.i6[0] = 0xffffffff;
+ msk.i6[1] = 0xffffffff;
+ msk.i6[2] = 0xffffffff;
+ msk.i6[3] = 0xffffffff;
+ nmsk = ifs->ifs_nat6_masks[3];
+ WRITE_ENTER(&ifs->ifs_ipf_nat);
+maskloop:
+ IP6_AND(&ipa, &msk, &iph);
+ hv = NAT_HASH_FN6(&iph, 0, ifs->ifs_ipf_natrules_sz);
+ for (np = ifs->ifs_nat_rules[hv]; np; np = np->in_mnext)
+ {
+ if ((np->in_ifps[1] && (np->in_ifps[1] != ifp)))
+ continue;
+ if (np->in_v != 6)
+ continue;
+ if (np->in_p && (np->in_p != fin->fin_p))
+ continue;
+ if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
+ continue;
+ if (np->in_flags & IPN_FILTER) {
+ if (!nat6_match(fin, np))
+ continue;
+ } else if (!IP6_MASKEQ(&ipa, &np->in_in[1],
+ &np->in_in[0]))
+ continue;
+
+ if ((fr != NULL) &&
+ !fr_matchtag(&np->in_tag, &fr->fr_nattag))
+ continue;
+
+#ifdef IPF_V6_PROXIES
+ if (*np->in_plabel != '\0') {
+ if (((np->in_flags & IPN_FILTER) == 0) &&
+ (np->in_dport != tcp->th_dport))
+ continue;
+ if (appr_ok(fin, tcp, np) == 0)
+ continue;
+ }
+#endif
+
+ if (nat = nat6_new(fin, np, NULL, nflags,
+ NAT_OUTBOUND)) {
+ np->in_hits++;
+ break;
+ } else
+ natfailed = -1;
+ }
+ if ((np == NULL) && (i >= 0)) {
+ while (i >= 0) {
+ while (nmsk) {
+ msk.i6[i] = htonl(ntohl(msk.i6[i])<<1);
+ if ((nmsk & 0x80000000) != 0) {
+ nmsk <<= 1;
+ goto maskloop;
+ }
+ nmsk <<= 1;
+ }
+ msk.i6[i--] = 0;
+ if (i >= 0) {
+ nmsk = ifs->ifs_nat6_masks[i];
+ if (nmsk != 0)
+ goto maskloop;
+ }
+ }
+ }
+ MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
+ }
+
+ if (nat != NULL) {
+ rval = fr_nat6out(fin, nat, natadd, nflags);
+ if (rval == 1) {
+ MUTEX_ENTER(&nat->nat_lock);
+ nat->nat_ref++;
+ MUTEX_EXIT(&nat->nat_lock);
+ nat->nat_touched = ifs->ifs_fr_ticks;
+ fin->fin_nat = nat;
+ }
+ } else
+ rval = natfailed;
+ RWLOCK_EXIT(&ifs->ifs_ipf_nat);
+
+ if (rval == -1) {
+ if (passp != NULL)
+ *passp = FR_BLOCK;
+ fin->fin_flx |= FI_BADNAT;
+ }
+ fin->fin_ifp = sifp;
+ return rval;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function: fr_nat6out */
+/* Returns: int - -1 == packet failed NAT checks so block it, */
+/* 1 == packet was successfully translated. */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to NAT structure */
+/* natadd(I) - flag indicating if it is safe to add frag cache */
+/* nflags(I) - NAT flags set for this packet */
+/* */
+/* Translate a packet coming "out" on an interface. */
+/* ------------------------------------------------------------------------ */
+int fr_nat6out(fin, nat, natadd, nflags)
+fr_info_t *fin;
+nat_t *nat;
+int natadd;
+u_32_t nflags;
+{
+ struct icmp6_hdr *icmp6;
+ u_short *csump;
+ tcphdr_t *tcp;
+ ipnat_t *np;
+ int i;
+ ipf_stack_t *ifs = fin->fin_ifs;
+
+#if SOLARIS && defined(_KERNEL)
+ net_data_t net_data_p = ifs->ifs_ipf_ipv6;
+#endif
+
+ tcp = NULL;
+ icmp6 = NULL;
+ csump = NULL;
+ np = nat->nat_ptr;
+
+ if ((natadd != 0) && (fin->fin_flx & FI_FRAG))
+ (void) fr_nat_newfrag(fin, 0, nat);
+
+ MUTEX_ENTER(&nat->nat_lock);
+ nat->nat_bytes[1] += fin->fin_plen;
+ nat->nat_pkts[1]++;
+ MUTEX_EXIT(&nat->nat_lock);
+
+ if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
+ if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) {
+ tcp = fin->fin_dp;
+
+ tcp->th_sport = nat->nat_outport;
+ fin->fin_data[0] = ntohs(nat->nat_outport);
+ }
+
+ if ((nat->nat_outport != 0) && (nflags & IPN_ICMPQUERY)) {
+ icmp6 = fin->fin_dp;
+ icmp6->icmp6_id = nat->nat_outport;
+ }
+
+ csump = nat_proto(fin, nat, nflags);
+ }
+
+ fin->fin_ip6->ip6_src = nat->nat_outip6.in6;
+ fin->fin_src6 = nat->nat_outip6;
+
+ nat_update(fin, nat, np);
+
+ /*
+ * TCP/UDP/ICMPv6 checksum needs to be adjusted.
+ */
+ if (csump != NULL && (!(nflags & IPN_TCPUDP) ||
+ !NET_IS_HCK_L4_FULL(net_data_p, fin->fin_m))) {
+ if (nflags & IPN_TCPUDP &&
+ NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) {
+ if (nat->nat_dir == NAT_OUTBOUND)
+ fix_outcksum(csump, nat->nat_sumd[1]);
+ else
+ fix_incksum(csump, nat->nat_sumd[1]);
+ } else {
+ if (nat->nat_dir == NAT_OUTBOUND)
+ fix_outcksum(csump, nat->nat_sumd[0]);
+ else
+ fix_incksum(csump, nat->nat_sumd[0]);
+ }
+ }
+#ifdef IPFILTER_SYNC
+ ipfsync_update(SMC_NAT, fin, nat->nat_sync);
+#endif
+ /* ------------------------------------------------------------- */
+ /* A few quick notes: */
+ /* Following are test conditions prior to calling the */
+ /* appr_check routine. */
+ /* */
+ /* A NULL tcp indicates a non TCP/UDP packet. When dealing */
+ /* with a redirect rule, we attempt to match the packet's */
+ /* source port against in_dport, otherwise we'd compare the */
+ /* packet's destination. */
+ /* ------------------------------------------------------------- */
+ if ((np != NULL) && (np->in_apr != NULL)) {
+ i = appr_check(fin, nat);
+ if (i == 0)
+ i = 1;
+ } else
+ i = 1;
+ ATOMIC_INCL(ifs->ifs_nat_stats.ns_mapped[1]);
+ fin->fin_flx |= FI_NATED;
+ return i;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: fr_checknat6in */
+/* Returns: int - -1 == packet failed NAT checks so block it, */
+/* 0 == no packet translation occurred, */
+/* 1 == packet was successfully translated. */
+/* Parameters: fin(I) - pointer to packet information */
+/* passp(I) - pointer to filtering result flags */
+/* */
+/* Check to see if an incoming packet should be changed. ICMP packets are */
+/* first checked to see if they match an existing entry (if an error), */
+/* otherwise a search of the current NAT table is made. If neither results */
+/* in a match then a search for a matching NAT rule is made. Create a new */
+/* NAT entry if a we matched a NAT rule. Lastly, actually change the */
+/* packet header(s) as required. */
+/* ------------------------------------------------------------------------ */
+int fr_checknat6in(fin, passp)
+fr_info_t *fin;
+u_32_t *passp;
+{
+ u_int nflags, natadd;
+ int rval, natfailed;
+ struct ifnet *ifp;
+ struct icmp6_hdr *icmp6;
+ tcphdr_t *tcp;
+ u_short dport;
+ ipnat_t *np;
+ nat_t *nat;
+ i6addr_t ipa, iph;
+ ipf_stack_t *ifs = fin->fin_ifs;
+
+ if (ifs->ifs_nat_stats.ns_rules == 0 || ifs->ifs_fr_nat_lock != 0)
+ return 0;
+
+ tcp = NULL;
+ icmp6 = NULL;
+ dport = 0;
+ natadd = 1;
+ nflags = 0;
+ natfailed = 0;
+ ifp = fin->fin_ifp;
+
+ if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
+ switch (fin->fin_p)
+ {
+ case IPPROTO_TCP :
+ nflags = IPN_TCP;
+ break;
+ case IPPROTO_UDP :
+ nflags = IPN_UDP;
+ break;
+ case IPPROTO_ICMPV6 :
+ icmp6 = fin->fin_dp;
+
+ /*
+ * This is an incoming packet, so the destination is
+ * the icmp_id and the source port equals 0
+ */
+ if ((fin->fin_flx & FI_ICMPQUERY) != 0) {
+ nflags = IPN_ICMPQUERY;
+ dport = icmp6->icmp6_id;
+ } break;
+ default :
+ break;
+ }
+
+ if ((nflags & IPN_TCPUDP)) {
+ tcp = fin->fin_dp;
+ dport = tcp->th_dport;
+ }
+ }
+
+ ipa = fin->fin_dst6;
+
+ READ_ENTER(&ifs->ifs_ipf_nat);
+
+ if ((fin->fin_p == IPPROTO_ICMPV6) && !(nflags & IPN_ICMPQUERY) &&
+ (nat = nat6_icmperror(fin, &nflags, NAT_INBOUND)))
+ /*EMPTY*/;
+ else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin)))
+ natadd = 0;
+ else if ((nat = nat6_inlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p,
+ &fin->fin_src6.in6, &ipa.in6))) {
+ nflags = nat->nat_flags;
+ } else {
+ u_32_t hv, rmsk;
+ i6addr_t msk;
+ int i;
+
+ RWLOCK_EXIT(&ifs->ifs_ipf_nat);
+ i = 3;
+ msk.i6[0] = 0xffffffff;
+ msk.i6[1] = 0xffffffff;
+ msk.i6[2] = 0xffffffff;
+ msk.i6[3] = 0xffffffff;
+ rmsk = ifs->ifs_rdr6_masks[3];
+ WRITE_ENTER(&ifs->ifs_ipf_nat);
+ /*
+ * If there is no current entry in the nat table for this IP#,
+ * create one for it (if there is a matching rule).
+ */
+maskloop:
+ IP6_AND(&ipa, &msk, &iph);
+ hv = NAT_HASH_FN6(&iph, 0, ifs->ifs_ipf_rdrrules_sz);
+ for (np = ifs->ifs_rdr_rules[hv]; np; np = np->in_rnext) {
+ if (np->in_ifps[0] && (np->in_ifps[0] != ifp))
+ continue;
+ if (np->in_v != fin->fin_v)
+ continue;
+ if (np->in_p && (np->in_p != fin->fin_p))
+ continue;
+ if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
+ continue;
+ if (np->in_flags & IPN_FILTER) {
+ if (!nat6_match(fin, np))
+ continue;
+ } else {
+ if (!IP6_MASKEQ(&ipa, &np->in_out[1],
+ &np->in_out[0]))
+ continue;
+ if (np->in_pmin &&
+ ((ntohs(np->in_pmax) < ntohs(dport)) ||
+ (ntohs(dport) < ntohs(np->in_pmin))))
+ continue;
+ }
+
+#ifdef IPF_V6_PROXIES
+ if (*np->in_plabel != '\0') {
+ if (!appr_ok(fin, tcp, np)) {
+ continue;
+ }
+ }
+#endif
+
+ nat = nat6_new(fin, np, NULL, nflags, NAT_INBOUND);
+ if (nat != NULL) {
+ np->in_hits++;
+ break;
+ } else
+ natfailed = -1;
+ }
+
+ if ((np == NULL) && (i >= 0)) {
+ while (i >= 0) {
+ while (rmsk) {
+ msk.i6[i] = htonl(ntohl(msk.i6[i])<<1);
+ if ((rmsk & 0x80000000) != 0) {
+ rmsk <<= 1;
+ goto maskloop;
+ }
+ rmsk <<= 1;
+ }
+ msk.i6[i--] = 0;
+ if (i >= 0) {
+ rmsk = ifs->ifs_rdr6_masks[i];
+ if (rmsk != 0)
+ goto maskloop;
+ }
+ }
+ }
+ MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
+ }
+ if (nat != NULL) {
+ rval = fr_nat6in(fin, nat, natadd, nflags);
+ if (rval == 1) {
+ MUTEX_ENTER(&nat->nat_lock);
+ nat->nat_ref++;
+ MUTEX_EXIT(&nat->nat_lock);
+ nat->nat_touched = ifs->ifs_fr_ticks;
+ fin->fin_nat = nat;
+ fin->fin_state = nat->nat_state;
+ }
+ } else
+ rval = natfailed;
+ RWLOCK_EXIT(&ifs->ifs_ipf_nat);
+
+ if (rval == -1) {
+ if (passp != NULL)
+ *passp = FR_BLOCK;
+ fin->fin_flx |= FI_BADNAT;
+ }
+ return rval;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: fr_nat6in */
+/* Returns: int - -1 == packet failed NAT checks so block it, */
+/* 1 == packet was successfully translated. */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to NAT structure */
+/* natadd(I) - flag indicating if it is safe to add frag cache */
+/* nflags(I) - NAT flags set for this packet */
+/* Locks Held: ipf_nat (READ) */
+/* */
+/* Translate a packet coming "in" on an interface. */
+/* ------------------------------------------------------------------------ */
+int fr_nat6in(fin, nat, natadd, nflags)
+fr_info_t *fin;
+nat_t *nat;
+int natadd;
+u_32_t nflags;
+{
+ struct icmp6_hdr *icmp6;
+ u_short *csump;
+ tcphdr_t *tcp;
+ ipnat_t *np;
+ ipf_stack_t *ifs = fin->fin_ifs;
+
+#if SOLARIS && defined(_KERNEL)
+ net_data_t net_data_p = ifs->ifs_ipf_ipv6;
+#endif
+
+ tcp = NULL;
+ csump = NULL;
+ np = nat->nat_ptr;
+ fin->fin_fr = nat->nat_fr;
+
+ if ((natadd != 0) && (fin->fin_flx & FI_FRAG))
+ (void) fr_nat_newfrag(fin, 0, nat);
+
+#ifdef IPF_V6_PROXIES
+ if (np != NULL) {
+
+ /* ------------------------------------------------------------- */
+ /* A few quick notes: */
+ /* Following are test conditions prior to calling the */
+ /* appr_check routine. */
+ /* */
+ /* A NULL tcp indicates a non TCP/UDP packet. When dealing */
+ /* with a map rule, we attempt to match the packet's */
+ /* source port against in_dport, otherwise we'd compare the */
+ /* packet's destination. */
+ /* ------------------------------------------------------------- */
+ if (np->in_apr != NULL) {
+ i = appr_check(fin, nat);
+ if (i == -1) {
+ return -1;
+ }
+ }
+ }
+#endif
+
+#ifdef IPFILTER_SYNC
+ ipfsync_update(SMC_NAT, fin, nat->nat_sync);
+#endif
+
+ MUTEX_ENTER(&nat->nat_lock);
+ nat->nat_bytes[0] += fin->fin_plen;
+ nat->nat_pkts[0]++;
+ MUTEX_EXIT(&nat->nat_lock);
+
+ fin->fin_ip6->ip6_dst = nat->nat_inip6.in6;
+ fin->fin_dst6 = nat->nat_inip6;
+
+ if (nflags & IPN_TCPUDP)
+ tcp = fin->fin_dp;
+
+ if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
+ if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) {
+ tcp->th_dport = nat->nat_inport;
+ fin->fin_data[1] = ntohs(nat->nat_inport);
+ }
+
+
+ if ((nat->nat_inport != 0) && (nflags & IPN_ICMPQUERY)) {
+ icmp6 = fin->fin_dp;
+
+ icmp6->icmp6_id = nat->nat_inport;
+ }
+
+ csump = nat_proto(fin, nat, nflags);
+ }
+
+ nat_update(fin, nat, np);
+
+ /*
+ * In case they are being forwarded, inbound packets always need to have
+ * their checksum adjusted even if hardware checksum validation said OK.
+ */
+ if (csump != NULL) {
+ if (nat->nat_dir == NAT_OUTBOUND)
+ fix_incksum(csump, nat->nat_sumd[0]);
+ else
+ fix_outcksum(csump, nat->nat_sumd[0]);
+ }
+
+#if SOLARIS && defined(_KERNEL)
+ if (nflags & IPN_TCPUDP &&
+ NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) {
+ /*
+ * Need to adjust the partial checksum result stored in
+ * db_cksum16, which will be used for validation in IP.
+ * See IP_CKSUM_RECV().
+ * Adjustment data should be the inverse of the IP address
+ * changes, because db_cksum16 is supposed to be the complement
+ * of the pesudo header.
+ */
+ csump = &fin->fin_m->b_datap->db_cksum16;
+ if (nat->nat_dir == NAT_OUTBOUND)
+ fix_outcksum(csump, nat->nat_sumd[1]);
+ else
+ fix_incksum(csump, nat->nat_sumd[1]);
+ }
+#endif
+
+ ATOMIC_INCL(ifs->ifs_nat_stats.ns_mapped[0]);
+ fin->fin_flx |= FI_NATED;
+ if (np != NULL && np->in_tag.ipt_num[0] != 0)
+ fin->fin_nattag = &np->in_tag;
+ return 1;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat_icmpquerytype6 */
+/* Returns: int - 1 == success, 0 == failure */
+/* Parameters: icmptype(I) - ICMP type number */
+/* */
+/* Tests to see if the ICMP type number passed is a query/response type or */
+/* not. */
+/* ------------------------------------------------------------------------ */
+static INLINE int nat_icmpquerytype6(icmptype)
+int icmptype;
+{
+
+ /*
+ * For the ICMP query NAT code, it is essential that both the query
+ * and the reply match on the NAT rule. Because the NAT structure
+ * does not keep track of the icmptype, and a single NAT structure
+ * is used for all icmp types with the same src, dest and id, we
+ * simply define the replies as queries as well. The funny thing is,
+ * altough it seems silly to call a reply a query, this is exactly
+ * as it is defined in the IPv4 specification
+ */
+
+ switch (icmptype)
+ {
+
+ case ICMP6_ECHO_REPLY:
+ case ICMP6_ECHO_REQUEST:
+ /* route aedvertisement/solliciation is currently unsupported: */
+ /* it would require rewriting the ICMP data section */
+ case ICMP6_MEMBERSHIP_QUERY:
+ case ICMP6_MEMBERSHIP_REPORT:
+ case ICMP6_MEMBERSHIP_REDUCTION:
+ case ICMP6_WRUREQUEST:
+ case ICMP6_WRUREPLY:
+ case MLD6_MTRACE_RESP:
+ case MLD6_MTRACE:
+ return 1;
+ default:
+ return 0;
+ }
+}
diff --git a/usr/src/uts/common/inet/ipf/ipf.h b/usr/src/uts/common/inet/ipf/ipf.h
index d60d89b70c..559349e3d9 100644
--- a/usr/src/uts/common/inet/ipf/ipf.h
+++ b/usr/src/uts/common/inet/ipf/ipf.h
@@ -6,7 +6,7 @@
* @(#)ipf.h 1.12 6/5/96
* $Id: ipf.h,v 2.71.2.7 2005/06/12 07:18:31 darrenr Exp $
*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -250,6 +250,7 @@ extern int ports __P((char ***, char *, u_short *, int *, u_short *, int));
extern int pri_findname __P((char *));
extern char *pri_toname __P((int));
extern void print_toif __P((char *, struct frdest *));
+extern void printaddr __P((int, int, char *, u_32_t *, u_32_t *));
extern void printaps __P((ap_session_t *, int));
extern void printbuf __P((char *, int, int));
extern void printfr __P((struct frentry *, ioctlfunc_t));
@@ -298,6 +299,7 @@ extern char *hostname __P((int, void *));
extern struct ipstate *printstate __P((struct ipstate *, int, u_long));
extern void printsbuf __P((char *));
extern void printnat __P((struct ipnat *, int));
+extern void printactiveaddress __P((int, char *, i6addr_t *, char *));
extern void printactivenat __P((struct nat *, int, int));
extern void printhostmap __P((struct hostmap *, u_int));
extern void printpacket __P((struct ip *));
diff --git a/usr/src/uts/common/inet/ipf/netinet/ip_fil.h b/usr/src/uts/common/inet/ipf/netinet/ip_fil.h
index dbdbaef7e9..0b98cf420a 100644
--- a/usr/src/uts/common/inet/ipf/netinet/ip_fil.h
+++ b/usr/src/uts/common/inet/ipf/netinet/ip_fil.h
@@ -131,7 +131,7 @@ typedef union i6addr {
void *vptr[2];
lookupfunc_t lptr[2];
} i6addr_t;
-#define in6_addr8 in6.s6_addr
+#define in6_addr8 in6.s6_addr
#else
typedef union i6addr {
u_32_t i6[4];
@@ -141,7 +141,7 @@ typedef union i6addr {
} i6addr_t;
#endif
-#define in4_addr in4.s_addr
+#define in4_addr in4.s_addr
#define iplookupnum i6[0]
#define iplookuptype i6[1]
/*
@@ -163,26 +163,34 @@ typedef union i6addr {
(I61(a) == I61(b)) && (I60(a) == I60(b)))
#define IP6_NEQ(a,b) ((I63(a) != I63(b)) || (I62(a) != I62(b)) || \
(I61(a) != I61(b)) || (I60(a) != I60(b)))
-#define IP6_ISZERO(a) ((I60(a) | I61(a) | I62(a) | I63(a)) == 0)
+#define IP6_ISZERO(a) ((I60(a) | I61(a) | I62(a) | I63(a)) == 0)
#define IP6_NOTZERO(a) ((I60(a) | I61(a) | I62(a) | I63(a)) != 0)
-#define IP6_GT(a,b) (HI60(a) > HI60(b) || (HI60(a) == HI60(b) && \
- (HI61(a) > HI61(b) || (HI61(a) == HI61(b) && \
- (HI62(a) > HI62(b) || (HI62(a) == HI62(b) && \
- HI63(a) > HI63(b)))))))
-#define IP6_LT(a,b) (HI60(a) < HI60(b) || (HI60(a) == HI60(b) && \
- (HI61(a) < HI61(b) || (HI61(a) == HI61(b) && \
- (HI62(a) < HI62(b) || (HI62(a) == HI62(b) && \
- HI63(a) < HI63(b)))))))
+#define IP6_ISONES(a) ((I63(a) == 0xffffffff) && (I62(a) == 0xffffffff) && \
+ (I61(a) == 0xffffffff) && (I60(a) == 0xffffffff))
+#define IP6_GT(a,b) (ntohl(HI60(a)) > ntohl(HI60(b)) || \
+ (HI60(a) == HI60(b) && \
+ (ntohl(HI61(a)) > ntohl(HI61(b)) || \
+ (HI61(a) == HI61(b) && \
+ (ntohl(HI62(a)) > ntohl(HI62(b)) || \
+ (HI62(a) == HI62(b) && \
+ ntohl(HI63(a)) > ntohl(HI63(b))))))))
+#define IP6_LT(a,b) (ntohl(HI60(a)) < ntohl(HI60(b)) || \
+ (HI60(a) == HI60(b) && \
+ (ntohl(HI61(a)) < ntohl(HI61(b)) || \
+ (HI61(a) == HI61(b) && \
+ (ntohl(HI62(a)) < ntohl(HI62(b)) || \
+ (HI62(a) == HI62(b) && \
+ ntohl(HI63(a)) < ntohl(HI63(b))))))))
#define NLADD(n,x) htonl(ntohl(n) + (x))
#define IP6_INC(a) \
{ i6addr_t *_i6 = (i6addr_t *)(a); \
- _i6->i6[0] = NLADD(_i6->i6[0], 1); \
- if (_i6->i6[0] == 0) { \
- _i6->i6[0] = NLADD(_i6->i6[1], 1); \
- if (_i6->i6[1] == 0) { \
- _i6->i6[0] = NLADD(_i6->i6[2], 1); \
- if (_i6->i6[2] == 0) { \
- _i6->i6[0] = NLADD(_i6->i6[3], 1); \
+ _i6->i6[3] = NLADD(_i6->i6[3], 1); \
+ if (_i6->i6[3] == 0) { \
+ _i6->i6[2] = NLADD(_i6->i6[2], 1); \
+ if (_i6->i6[2] == 0) { \
+ _i6->i6[1] = NLADD(_i6->i6[1], 1); \
+ if (_i6->i6[1] == 0) { \
+ _i6->i6[0] = NLADD(_i6->i6[0], 1); \
} \
} \
} \
@@ -190,25 +198,35 @@ typedef union i6addr {
#define IP6_ADD(a,x,d) \
{ i6addr_t *_s = (i6addr_t *)(a); \
i6addr_t *_d = (i6addr_t *)(d); \
- _d->i6[0] = NLADD(_s->i6[0], x); \
- if (ntohl(_d->i6[0]) < ntohl(_s->i6[0])) { \
- _d->i6[1] = NLADD(_d->i6[1], 1); \
- if (ntohl(_d->i6[1]) < ntohl(_s->i6[1])) { \
- _d->i6[2] = NLADD(_d->i6[2], 1); \
- if (ntohl(_d->i6[2]) < ntohl(_s->i6[2])) { \
- _d->i6[3] = NLADD(_d->i6[3], 1); \
+ _d->i6[3] = NLADD(_s->i6[3], x); \
+ if (ntohl(_d->i6[3]) < ntohl(_s->i6[3])) { \
+ _d->i6[2] = NLADD(_d->i6[2], 1); \
+ if (ntohl(_d->i6[2]) < ntohl(_s->i6[2])) { \
+ _d->i6[1] = NLADD(_d->i6[1], 1); \
+ if (ntohl(_d->i6[1]) < ntohl(_s->i6[1])) { \
+ _d->i6[0] = NLADD(_d->i6[0], 1); \
} \
} \
} \
}
#define IP6_AND(a,b,d) { i6addr_t *_s1 = (i6addr_t *)(a); \
- i6addr_t *_s2 = (i6addr_t *)(d); \
+ i6addr_t *_s2 = (i6addr_t *)(b); \
i6addr_t *_d = (i6addr_t *)(d); \
_d->i6[0] = _s1->i6[0] & _s2->i6[0]; \
_d->i6[1] = _s1->i6[1] & _s2->i6[1]; \
_d->i6[2] = _s1->i6[2] & _s2->i6[2]; \
_d->i6[3] = _s1->i6[3] & _s2->i6[3]; \
}
+#define IP6_MASKEQ(a,m,b) \
+ (((I60(a) & I60(m)) == I60(b)) && \
+ ((I61(a) & I61(m)) == I61(b)) && \
+ ((I62(a) & I62(m)) == I62(b)) && \
+ ((I63(a) & I63(m)) == I63(b)))
+#define IP6_MASKNEQ(a,m,b) \
+ (((I60(a) & I60(m)) != I60(b)) || \
+ ((I61(a) & I61(m)) != I61(b)) || \
+ ((I62(a) & I62(m)) != I62(b)) || \
+ ((I63(a) & I63(m)) != I63(b)))
#define IP6_MERGE(a,b,c) \
{ i6addr_t *_d, *_s1, *_s2; \
_d = (i6addr_t *)(a); \
@@ -217,7 +235,7 @@ typedef union i6addr {
_d->i6[0] |= _s1->i6[0] & ~_s2->i6[0]; \
_d->i6[1] |= _s1->i6[1] & ~_s2->i6[1]; \
_d->i6[2] |= _s1->i6[2] & ~_s2->i6[2]; \
- _d->i6[2] |= _s1->i6[3] & ~_s2->i6[3]; \
+ _d->i6[3] |= _s1->i6[3] & ~_s2->i6[3]; \
}
@@ -261,6 +279,7 @@ typedef struct fr_ip {
#define FI_WITH 0xeffe /* Not FI_TCPUDP */
#define FI_V6EXTHDR 0x10000
#define FI_COALESCE 0x20000
+#define FI_ICMPQUERY 0x40000
#define FI_NOCKSUM 0x20000000 /* don't do a L4 checksum validation */
#define FI_DONTCACHE 0x40000000 /* don't cache the result */
#define FI_IGNORE 0x80000000
@@ -323,7 +342,12 @@ typedef struct fr_info {
void *fin_nat;
void *fin_state;
void *fin_nattag;
- ip_t *fin_ip;
+ union {
+ ip_t *fip_ip;
+#ifdef USE_INET6
+ ip6_t *fip_ip6;
+#endif
+ } fin_ipu;
mb_t **fin_mp; /* pointer to pointer to mbuf */
mb_t *fin_m; /* pointer to mbuf */
#ifdef MENTAT
@@ -336,6 +360,8 @@ typedef struct fr_info {
#endif
} fr_info_t;
+#define fin_ip fin_ipu.fip_ip
+#define fin_ip6 fin_ipu.fip_ip6
#define fin_v fin_fi.fi_v
#define fin_p fin_fi.fi_p
#define fin_flx fin_fi.fi_flx
@@ -343,16 +369,21 @@ typedef struct fr_info {
#define fin_secmsk fin_fi.fi_secmsk
#define fin_auth fin_fi.fi_auth
#define fin_src fin_fi.fi_src.in4
-#define fin_src6 fin_fi.fi_src.in6
#define fin_saddr fin_fi.fi_saddr
#define fin_dst fin_fi.fi_dst.in4
-#define fin_dst6 fin_fi.fi_dst.in6
#define fin_daddr fin_fi.fi_daddr
#define fin_data fin_dat.fid_16
#define fin_sport fin_dat.fid_16[0]
#define fin_dport fin_dat.fid_16[1]
#define fin_ports fin_dat.fid_32
+#ifdef USE_INET6
+# define fin_src6 fin_fi.fi_src
+# define fin_dst6 fin_fi.fi_dst
+# define fin_dstip6 fin_fi.fi_dst.in6
+# define fin_srcip6 fin_fi.fi_src.in6
+#endif
+
#define IPF_IN 0
#define IPF_OUT 1
@@ -1397,7 +1428,8 @@ extern int copyoutptr __P((void *, void *, size_t));
extern int fr_fastroute __P((mb_t *, mb_t **, fr_info_t *, frdest_t *));
extern int fr_inobj __P((void *, void *, int));
extern int fr_inobjsz __P((void *, void *, int, int));
-extern int fr_ioctlswitch __P((int, void *, ioctlcmd_t, int, int, void *, ipf_stack_t *));
+extern int fr_ioctlswitch __P((int, void *, ioctlcmd_t, int, int, void *,
+ ipf_stack_t *));
extern int fr_ipftune __P((ioctlcmd_t, void *, ipf_stack_t *));
extern int fr_outobj __P((void *, void *, int));
extern int fr_outobjsz __P((void *, void *, int, int));
@@ -1414,8 +1446,10 @@ extern ipftq_t *fr_addtimeoutqueue __P((ipftq_t **, u_int, ipf_stack_t *));
extern void fr_deletequeueentry __P((ipftqent_t *));
extern int fr_deletetimeoutqueue __P((ipftq_t *));
extern void fr_freetimeoutqueue __P((ipftq_t *, ipf_stack_t *));
-extern void fr_movequeue __P((ipftqent_t *, ipftq_t *, ipftq_t *, ipf_stack_t *));
-extern void fr_queueappend __P((ipftqent_t *, ipftq_t *, void *, ipf_stack_t *));
+extern void fr_movequeue __P((ipftqent_t *, ipftq_t *, ipftq_t *,
+ ipf_stack_t *));
+extern void fr_queueappend __P((ipftqent_t *, ipftq_t *, void *,
+ ipf_stack_t *));
extern void fr_queueback __P((ipftqent_t *, ipf_stack_t *));
extern void fr_queuefront __P((ipftqent_t *));
extern void fr_checkv4sum __P((fr_info_t *));
@@ -1431,6 +1465,10 @@ extern int fr_ifpfillv6addr __P((int, struct sockaddr_in6 *,
struct in_addr *));
#endif
+#define IPFILTER_COMPAT
+extern int fr_incomptrans __P((ipfobj_t *, void *));
+extern int fr_outcomptrans __P((ipfobj_t *, void *));
+
extern int fr_addipftune __P((ipftuneable_t *, ipf_stack_t *));
extern int fr_delipftune __P((ipftuneable_t *, ipf_stack_t *));
@@ -1470,7 +1508,7 @@ extern void fr_lock __P((caddr_t, int *));
extern int fr_makefrip __P((int, ip_t *, fr_info_t *));
extern int fr_matchtag __P((ipftag_t *, ipftag_t *));
extern int fr_matchicmpqueryreply __P((int, icmpinfo_t *,
- struct icmp *, int));
+ struct icmp *, int));
extern u_32_t fr_newisn __P((fr_info_t *));
extern u_short fr_nextipid __P((fr_info_t *));
extern int fr_rulen __P((int, frentry_t *, ipf_stack_t *));
@@ -1479,12 +1517,14 @@ extern frentry_t *fr_srcgrpmap __P((fr_info_t *, u_32_t *));
extern int fr_tcpudpchk __P((fr_info_t *, frtuc_t *));
extern int fr_verifysrc __P((fr_info_t *fin));
extern int fr_zerostats __P((char *, ipf_stack_t *));
-extern ipftoken_t *ipf_findtoken __P((int, int, void *, ipf_stack_t *));
-extern int ipf_getnextrule __P((ipftoken_t *, void *, ipf_stack_t *));
+extern ipftoken_t *ipf_findtoken __P((int, int, void *, ipf_stack_t *));
+extern int ipf_getnextrule __P((ipftoken_t *, void *,
+ ipf_stack_t *));
extern void ipf_expiretokens __P((ipf_stack_t *));
-extern void ipf_freetoken __P((ipftoken_t *, ipf_stack_t *));
-extern int ipf_deltoken __P((int,int, void *, ipf_stack_t *));
-extern int ipf_genericiter __P((void *, int, void *, ipf_stack_t *));
+extern void ipf_freetoken __P((ipftoken_t *, ipf_stack_t *));
+extern int ipf_deltoken __P((int,int, void *, ipf_stack_t *));
+extern int ipf_genericiter __P((void *, int, void *,
+ ipf_stack_t *));
extern char ipfilter_version[];
#ifdef USE_INET6
diff --git a/usr/src/uts/common/inet/ipf/netinet/ip_nat.h b/usr/src/uts/common/inet/ipf/netinet/ip_nat.h
index 605af9b075..d7df16dba6 100644
--- a/usr/src/uts/common/inet/ipf/netinet/ip_nat.h
+++ b/usr/src/uts/common/inet/ipf/netinet/ip_nat.h
@@ -6,7 +6,7 @@
* @(#)ip_nat.h 1.5 2/4/96
* $Id: ip_nat.h,v 2.90.2.11 2005/06/18 02:41:32 darrenr Exp $
*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -30,7 +30,7 @@
#define SIOCGNATL _IOWR(r, 63, struct ipfobj)
#endif
-#undef LARGE_NAT /* define this if you're setting up a system to NAT
+#undef LARGE_NAT /* define this if you're setting up a system to NAT
* LARGE numbers of networks/hosts - i.e. in the
* hundreds or thousands. In such a case, you should
* also change the RDR_SIZE and NAT_SIZE below to more
@@ -114,7 +114,7 @@ typedef struct nat {
void *nat_sync;
ipftqent_t nat_tqe;
u_32_t nat_flags;
- u_32_t nat_sumd[2]; /* ip checksum delta for data segment*/
+ u_32_t nat_sumd[2]; /* ip checksum delta for data segment */
u_32_t nat_ipsumd; /* ip checksum delta for ip header */
u_32_t nat_mssclamp; /* if != zero clamp MSS to this */
i6addr_t nat_inip6;
@@ -136,6 +136,7 @@ typedef struct nat {
int nat_hv[2];
char nat_ifnames[2][LIFNAMSIZ];
int nat_rev; /* 0 = forward, 1 = reverse */
+ int nat_v;
int nat_redir; /* copy of in_redir */
} nat_t;
@@ -280,18 +281,26 @@ typedef struct ipnat {
#define MAPBLK_MINPORT 1024 /* don't use reserved ports for src port */
#define USABLE_PORTS (65536 - MAPBLK_MINPORT)
-#define IPN_CMPSIZ (sizeof(ipnat_t) - offsetof(ipnat_t, in_flags))
+#define IPN_CMPSIZ (sizeof (ipnat_t) - offsetof(ipnat_t, in_flags))
typedef struct natlookup {
- struct in_addr nl_inip;
- struct in_addr nl_outip;
- struct in_addr nl_realip;
- int nl_flags;
- u_short nl_inport;
- u_short nl_outport;
- u_short nl_realport;
+ i6addr_t nl_inipaddr;
+ i6addr_t nl_outipaddr;
+ i6addr_t nl_realipaddr;
+ int nl_v;
+ int nl_flags;
+ u_short nl_inport;
+ u_short nl_outport;
+ u_short nl_realport;
} natlookup_t;
+#define nl_inip nl_inipaddr.in4
+#define nl_outip nl_outipaddr.in4
+#define nl_realip nl_realipaddr.in4
+#define nl_inip6 nl_inipaddr.in6
+#define nl_outip6 nl_outipaddr.in6
+#define nl_realip6 nl_realipaddr.in6
+
typedef struct nat_save {
void *ipn_next;
@@ -341,21 +350,27 @@ typedef struct hostmap {
struct hostmap *hm_hnext;
struct hostmap **hm_phnext;
struct ipnat *hm_ipnat;
- struct in_addr hm_srcip;
- struct in_addr hm_dstip;
- struct in_addr hm_mapip;
+ i6addr_t hm_src;
+ i6addr_t hm_dst;
+ i6addr_t hm_map;
u_32_t hm_port;
int hm_ref;
+ int hm_v;
} hostmap_t;
+#define hm_srcip hm_src.in4
+#define hm_dstip hm_dst.in4
+#define hm_mapip hm_map.in4
+#define hm_srcip6 hm_src.in6
+#define hm_dstip6 hm_dst.in6
+#define hm_mapip6 hm_map.in6
+
/*
* Structure used to pass information in to nat_newmap and nat_newrdr.
*/
typedef struct natinfo {
ipnat_t *nai_np;
- u_32_t nai_sum1;
- u_32_t nai_sum2;
u_32_t nai_nflags;
u_32_t nai_flags;
struct in_addr nai_ip;
@@ -395,17 +410,18 @@ typedef struct natstat {
} natstat_t;
typedef struct natlog {
- struct in_addr nl_origip;
- struct in_addr nl_outip;
- struct in_addr nl_inip;
- u_short nl_origport;
- u_short nl_outport;
- u_short nl_inport;
- u_short nl_type;
- int nl_rule;
- U_QUAD_T nl_pkts[2];
- U_QUAD_T nl_bytes[2];
- u_char nl_p;
+ i6addr_t nlg_origip;
+ i6addr_t nlg_outip;
+ i6addr_t nlg_inip;
+ u_short nlg_origport;
+ u_short nlg_outport;
+ u_short nlg_inport;
+ u_short nlg_type;
+ int nlg_rule;
+ U_QUAD_T nlg_pkts[2];
+ U_QUAD_T nlg_bytes[2];
+ u_char nlg_p;
+ int nlg_v;
} natlog_t;
@@ -417,9 +433,22 @@ typedef struct natlog {
#define NL_FLUSH 0xfffe
#define NL_EXPIRE 0xffff
-#define NAT_HASH_FN(k,l,m) (((k) + ((k) >> 12) + l) % (m))
+#define NAT_HASH_FN(k, l, m) (((k) + ((k) >> 12) + l) % (m))
+#define NAT_HASH_FN6(k, l, m) ((((u_32_t *)(k))[3] \
+ + (((u_32_t *)(k))[3] >> 12) \
+ + (((u_32_t *)(k))[2]) \
+ + (((u_32_t *)(k))[2] >> 12) \
+ + (((u_32_t *)(k))[1]) \
+ + (((u_32_t *)(k))[1] >> 12) \
+ + (((u_32_t *)(k))[0]) \
+ + (((u_32_t *)(k))[0] >> 12) \
+ + l) % (m))
#define LONG_SUM(in) (((in) & 0xffff) + ((in) >> 16))
+#define LONG_SUM6(in) (LONG_SUM(ntohl(((u_32_t *)(in))[0])) + \
+ LONG_SUM(ntohl(((u_32_t *)(in))[1])) + \
+ LONG_SUM(ntohl(((u_32_t *)(in))[2])) + \
+ LONG_SUM(ntohl(((u_32_t *)(in))[3])))
#define CALC_SUMD(s1, s2, sd) { \
(s1) = ((s1) & 0xffff) + ((s1) >> 16); \
@@ -436,8 +465,8 @@ typedef struct natlog {
#define NAT_LOCKHELD 0x40000000
extern void fr_natsync __P((void *, ipf_stack_t *));
-extern void fr_nataddrsync __P((void *, struct in_addr *, ipf_stack_t *));
-extern void fr_natifpsync __P((int, void *, char *, ipf_stack_t *));
+extern void fr_nataddrsync __P((int, void *, void *, ipf_stack_t *));
+extern void fr_natifpsync __P((int, int, void *, char *, ipf_stack_t *));
#if defined(__OpenBSD__)
extern void nat_ifdetach __P((void *, ipf_stack_t *));
@@ -474,4 +503,28 @@ extern void nat_update __P((fr_info_t *, nat_t *, ipnat_t *));
extern void fr_setnatqueue __P((nat_t *, int, ipf_stack_t *));
extern void fr_hostmapdel __P((hostmap_t **));
+extern nat_t *fr_natclone __P((fr_info_t *, nat_t *));
+extern void nat_delrdr __P((struct ipnat *));
+extern void nat_delnat __P((struct ipnat *));
+extern int nat_wildok __P((nat_t *, int, int, int, int));
+extern void nat_calc_chksum_diffs __P((nat_t *));
+
+#ifdef USE_INET6
+extern void nat6_addnat __P((ipnat_t *, ipf_stack_t *));
+extern void nat6_addrdr __P((ipnat_t *, ipf_stack_t *));
+extern nat_t *nat6_new __P((fr_info_t *, ipnat_t *, nat_t **, u_int, int));
+extern nat_t *nat6_outlookup __P((fr_info_t *, u_int, u_int,
+ struct in6_addr *, struct in6_addr *));
+extern nat_t *nat6_inlookup __P((fr_info_t *, u_int, u_int,
+ struct in6_addr *, struct in6_addr *));
+extern nat_t *nat6_lookupredir __P((natlookup_t *, ipf_stack_t *));
+extern nat_t *nat6_icmperrorlookup __P((fr_info_t *, int));
+extern nat_t *nat6_icmperror __P((fr_info_t *, u_int *, int));
+extern int nat6_insert __P((nat_t *, int, ipf_stack_t *));
+extern int fr_checknat6out __P((fr_info_t *, u_32_t *));
+extern int fr_nat6out __P((fr_info_t *, nat_t *, int, u_32_t));
+extern int fr_checknat6in __P((fr_info_t *, u_32_t *));
+extern int fr_nat6in __P((fr_info_t *, nat_t *, int, u_32_t));
+#endif
+
#endif /* __IP_NAT_H__ */
diff --git a/usr/src/uts/common/inet/ipf/netinet/ipf_stack.h b/usr/src/uts/common/inet/ipf/netinet/ipf_stack.h
index 23f291c866..44ef0ace0f 100644
--- a/usr/src/uts/common/inet/ipf/netinet/ipf_stack.h
+++ b/usr/src/uts/common/inet/ipf/netinet/ipf_stack.h
@@ -3,7 +3,7 @@
*
* See the IPFILTER.LICENCE file for details on licencing.
*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -212,6 +212,8 @@ struct ipf_stack {
uint_t ifs_fr_nat_maxbucket_reset;
uint32_t ifs_nat_masks;
uint32_t ifs_rdr_masks;
+ uint32_t ifs_nat6_masks[4];
+ uint32_t ifs_rdr6_masks[4];
ipnat_t **ifs_nat_rules;
ipnat_t **ifs_rdr_rules;
hostmap_t **ifs_maptable;
diff --git a/usr/src/uts/common/inet/ipf/netinet/ipl.h b/usr/src/uts/common/inet/ipf/netinet/ipl.h
index df2c0b4f3b..8c8b1337dc 100644
--- a/usr/src/uts/common/inet/ipf/netinet/ipl.h
+++ b/usr/src/uts/common/inet/ipf/netinet/ipl.h
@@ -6,7 +6,7 @@
* @(#)ipl.h 1.21 6/5/96
* $Id: ipl.h,v 2.52.2.10 2005/08/13 05:42:49 darrenr Exp $
*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -18,6 +18,6 @@
#define IPL_VERSION "IP Filter: v4.1.9"
-#define IPFILTER_VERSION 4010900
+#define IPFILTER_VERSION 4010901
#endif