aboutsummaryrefslogtreecommitdiff
path: root/contrib/ipfilter/ip_nat.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ipfilter/ip_nat.c')
-rw-r--r--contrib/ipfilter/ip_nat.c468
1 files changed, 284 insertions, 184 deletions
diff --git a/contrib/ipfilter/ip_nat.c b/contrib/ipfilter/ip_nat.c
index eb6e133bfc0f..5c10bc4ba3f3 100644
--- a/contrib/ipfilter/ip_nat.c
+++ b/contrib/ipfilter/ip_nat.c
@@ -9,6 +9,9 @@
#define _KERNEL
#endif
+#ifdef __sgi
+# include <sys/ptimers.h>
+#endif
#include <sys/errno.h>
#include <sys/types.h>
#include <sys/param.h>
@@ -30,7 +33,6 @@
# include <sys/ioctl.h>
#endif
#include <sys/fcntl.h>
-#include <sys/uio.h>
#ifndef linux
# include <sys/protosw.h>
#endif
@@ -92,10 +94,10 @@ extern struct ifnet vpnif;
#include "netinet/ip_compat.h"
#include <netinet/tcpip.h>
#include "netinet/ip_fil.h"
-#include "netinet/ip_proxy.h"
#include "netinet/ip_nat.h"
#include "netinet/ip_frag.h"
#include "netinet/ip_state.h"
+#include "netinet/ip_proxy.h"
#if (__FreeBSD_version >= 300000)
# include <sys/malloc.h>
#endif
@@ -107,7 +109,7 @@ extern struct ifnet vpnif;
#if !defined(lint)
static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed";
-static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.44 2001/07/21 07:17:22 darrenr Exp $";
+static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.63 2002/03/06 09:44:11 darrenr Exp $";
#endif
nat_t **nat_table[2] = { NULL, NULL },
@@ -133,7 +135,6 @@ extern KRWLOCK_T ipf_nat;
#endif
static int nat_flushtable __P((void));
-static int nat_clearlist __P((void));
static void nat_addnat __P((struct ipnat *));
static void nat_addrdr __P((struct ipnat *));
static void nat_delete __P((struct nat *));
@@ -142,7 +143,7 @@ static void nat_delnat __P((struct ipnat *));
static int fr_natgetent __P((caddr_t));
static int fr_natgetsz __P((caddr_t));
static int fr_natputent __P((caddr_t));
-static void nat_tabmove __P((nat_t *, u_32_t));
+static void nat_tabmove __P((fr_info_t *, nat_t *));
static int nat_match __P((fr_info_t *, ipnat_t *, ip_t *));
static hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr,
struct in_addr));
@@ -501,7 +502,7 @@ int mode;
if (!n->in_ifp)
n->in_ifp = (void *)-1;
if (n->in_plabel[0] != '\0') {
- n->in_apr = appr_match(n->in_p, n->in_plabel);
+ n->in_apr = appr_lookup(n->in_p, n->in_plabel);
if (!n->in_apr) {
error = ENOENT;
break;
@@ -900,7 +901,9 @@ caddr_t data;
nat->nat_aps = NULL;
in = nat->nat_ptr;
nat->nat_ptr = NULL;
+ nat->nat_hm = NULL;
nat->nat_data = NULL;
+ nat->nat_ifp = GETUNIT(nat->nat_ifname, 4);
/*
* Restore the rule associated with this nat session
@@ -922,7 +925,7 @@ caddr_t data;
in->in_pmnext = NULL;
in->in_ifp = GETUNIT(in->in_ifname, 4);
if (in->in_plabel[0] != '\0') {
- in->in_apr = appr_match(in->in_p, in->in_plabel);
+ in->in_apr = appr_lookup(in->in_p, in->in_plabel);
}
}
@@ -1015,6 +1018,8 @@ struct nat *natd;
if (natd->nat_hnext[1])
natd->nat_hnext[1]->nat_phnext[1] = natd->nat_phnext[1];
*natd->nat_phnext[1] = natd->nat_hnext[1];
+ if (natd->nat_me != NULL)
+ *natd->nat_me = NULL;
if (natd->nat_fr != NULL) {
ATOMIC_DEC32(natd->nat_fr->fr_ref);
@@ -1054,6 +1059,7 @@ struct nat *natd;
/*
* nat_flushtable - clear the NAT table of all mapping entries.
+ * (this is for the dynamic mappings)
*/
static int nat_flushtable()
{
@@ -1086,8 +1092,9 @@ static int nat_flushtable()
/*
* nat_clearlist - delete all rules in the active NAT mapping list.
+ * (this is for NAT/RDR rules)
*/
-static int nat_clearlist()
+int nat_clearlist()
{
register ipnat_t *n, **np = &nat_list;
int i = 0;
@@ -1118,22 +1125,25 @@ static int nat_clearlist()
/*
* Create a new NAT table entry.
- * NOTE: assumes write lock on ipf_nat has been obtained already.
+ * NOTE: Assumes write lock on ipf_nat has been obtained already.
+ * If you intend on changing this, beware: appr_new() may call nat_new()
+ * recursively!
*/
-nat_t *nat_new(np, ip, fin, flags, direction)
-ipnat_t *np;
-ip_t *ip;
+nat_t *nat_new(fin, ip, np, natsave, flags, direction)
fr_info_t *fin;
+ip_t *ip;
+ipnat_t *np;
+nat_t **natsave;
u_int flags;
int direction;
{
register u_32_t sum1, sum2, sumd, l;
u_short port = 0, sport = 0, dport = 0, nport = 0;
struct in_addr in, inb;
+ u_short nflags, sp, dp;
tcphdr_t *tcp = NULL;
hostmap_t *hm = NULL;
nat_t *nat, *natl;
- u_short nflags;
#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
qif_t *qf = fin->fin_qif;
#endif
@@ -1141,8 +1151,8 @@ int direction;
nflags = flags & np->in_flags;
if (flags & IPN_TCPUDP) {
tcp = (tcphdr_t *)fin->fin_dp;
- sport = tcp->th_sport;
- dport = tcp->th_dport;
+ sport = htons(fin->fin_data[0]);
+ dport = htons(fin->fin_data[1]);
}
/* Give me a new nat */
@@ -1182,7 +1192,7 @@ int direction;
* Check to see if there is an existing NAT
* setup for this IP address pair.
*/
- hm = nat_hostmap(np, ip->ip_src, in);
+ hm = nat_hostmap(np, fin->fin_src, in);
if (hm != NULL)
in.s_addr = hm->hm_mapip.s_addr;
} else if ((l == 1) && (hm != NULL)) {
@@ -1206,7 +1216,7 @@ int direction;
/*
* map-block - Calculate destination address.
*/
- in.s_addr = ntohl(ip->ip_src.s_addr);
+ in.s_addr = ntohl(fin->fin_saddr);
in.s_addr &= ntohl(~np->in_inmsk);
inb.s_addr = in.s_addr;
in.s_addr /= np->in_ippip;
@@ -1239,7 +1249,7 @@ int direction;
*/
if (l > 0)
goto badnat;
- in.s_addr = ntohl(ip->ip_src.s_addr);
+ in.s_addr = ntohl(fin->fin_saddr);
} else if ((np->in_outmsk != 0xffffffff) &&
(np->in_pnext == 0) &&
((l > 0) || (hm == NULL)))
@@ -1261,7 +1271,7 @@ int direction;
port += (l % np->in_ppip);
port %= np->in_ppip;
port += np->in_ppip *
- (ntohl(ip->ip_src.s_addr) %
+ (ntohl(fin->fin_saddr) %
np->in_ippip);
port += MAPBLK_MINPORT;
port = htons(port);
@@ -1301,9 +1311,15 @@ int direction;
* this is appropriate.
*/
inb.s_addr = htonl(in.s_addr);
- natl = nat_inlookup(fin->fin_ifp, flags & ~FI_WILDP,
- (u_int)ip->ip_p, ip->ip_dst, inb,
- (port << 16) | dport, 1);
+ 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 = nat_inlookup(fin, flags & ~FI_WILDP,
+ (u_int)fin->fin_p, fin->fin_dst,
+ inb, 1);
+ fin->fin_data[0] = sp;
+ fin->fin_data[1] = dp;
/*
* Has the search wrapped around and come back to the
@@ -1320,14 +1336,14 @@ int direction;
np->in_space--;
/* Setup the NAT table */
- nat->nat_inip = ip->ip_src;
+ nat->nat_inip = fin->fin_src;
nat->nat_outip.s_addr = htonl(in.s_addr);
- nat->nat_oip = ip->ip_dst;
+ nat->nat_oip = fin->fin_dst;
if (nat->nat_hm == NULL)
- nat->nat_hm = nat_hostmap(np, ip->ip_src,
+ nat->nat_hm = nat_hostmap(np, fin->fin_src,
nat->nat_outip);
- sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr)) + ntohs(sport);
+ sum1 = LONG_SUM(ntohl(fin->fin_saddr)) + ntohs(sport);
sum2 = LONG_SUM(in.s_addr) + ntohs(port);
if (flags & IPN_TCPUDP) {
@@ -1367,27 +1383,26 @@ int direction;
* Whilst not optimized for the case where
* pmin == pmax, the gain is not significant.
*/
- nport = ntohs(dport) - ntohs(np->in_pmin) +
- ntohs(np->in_pnext);
- nport = htons(nport);
+ if (np->in_pmin != np->in_pmax) {
+ nport = ntohs(dport) - ntohs(np->in_pmin) +
+ ntohs(np->in_pnext);
+ nport = ntohs(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.
+ * assume a blank `forwarding' of the packet.
*/
- if (in.s_addr == 0) {
- if (nport == dport)
- goto badnat;
- in.s_addr = ntohl(ip->ip_dst.s_addr);
- }
+ if (in.s_addr == 0)
+ in.s_addr = ntohl(fin->fin_daddr);
nat->nat_inip.s_addr = htonl(in.s_addr);
- nat->nat_outip = ip->ip_dst;
- nat->nat_oip = ip->ip_src;
+ nat->nat_outip = fin->fin_dst;
+ nat->nat_oip = fin->fin_src;
- sum1 = LONG_SUM(ntohl(ip->ip_dst.s_addr)) + ntohs(dport);
+ sum1 = LONG_SUM(ntohl(fin->fin_daddr)) + ntohs(dport);
sum2 = LONG_SUM(in.s_addr) + ntohs(nport);
if (flags & IPN_TCPUDP) {
@@ -1405,8 +1420,8 @@ int direction;
if (direction == NAT_OUTBOUND)
sum1 = LONG_SUM(ntohl(in.s_addr));
else
- sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr));
- sum1 += LONG_SUM(ntohl(ip->ip_dst.s_addr));
+ sum1 = LONG_SUM(ntohl(fin->fin_saddr));
+ sum1 += LONG_SUM(ntohl(fin->fin_daddr));
sum1 += IPPROTO_TCP;
sum1 = (sum1 & 0xffff) + (sum1 >> 16);
nat->nat_sumd[1] = NAT_HW_CKSUM|(sum1 & 0xffff);
@@ -1416,9 +1431,9 @@ int direction;
if ((flags & IPN_TCPUDP) && ((sport != port) || (dport != nport))) {
if (direction == NAT_OUTBOUND)
- sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr));
+ sum1 = LONG_SUM(ntohl(fin->fin_saddr));
else
- sum1 = LONG_SUM(ntohl(ip->ip_dst.s_addr));
+ sum1 = LONG_SUM(ntohl(fin->fin_daddr));
sum2 = LONG_SUM(in.s_addr);
@@ -1429,15 +1444,13 @@ int direction;
in.s_addr = htonl(in.s_addr);
-#ifdef _KERNEL
strncpy(nat->nat_ifname, IFNAME(fin->fin_ifp), IFNAMSIZ);
-#endif
- nat_insert(nat);
+ nat->nat_me = natsave;
nat->nat_dir = direction;
nat->nat_ifp = fin->fin_ifp;
nat->nat_ptr = np;
- nat->nat_p = ip->ip_p;
+ nat->nat_p = fin->fin_p;
nat->nat_bytes = 0;
nat->nat_pkts = 0;
nat->nat_fr = fin->fin_fr;
@@ -1451,6 +1464,13 @@ int direction;
if (flags & IPN_TCPUDP)
tcp->th_dport = nport;
}
+
+ nat_insert(nat);
+
+ if ((np->in_apr != NULL) && (np->in_dport == 0 ||
+ (tcp != NULL && dport == np->in_dport)))
+ (void) appr_new(fin, ip, nat);
+
np->in_use++;
#ifdef IPFILTER_LOG
nat_log(nat, (u_int)np->in_redir);
@@ -1465,6 +1485,10 @@ badnat:
}
+/*
+ * 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.
+ */
void nat_insert(nat)
nat_t *nat;
{
@@ -1492,10 +1516,10 @@ nat_t *nat;
hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2 + nat->nat_oport,
ipf_nattable_sz);
} else {
- hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, 0, 0xffffffff);
- hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1, ipf_nattable_sz);
- hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, 0, 0xffffffff);
- hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2, ipf_nattable_sz);
+ hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, nat->nat_inip.s_addr,
+ ipf_nattable_sz);
+ hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, nat->nat_outip.s_addr,
+ ipf_nattable_sz);
}
natp = &nat_table[0][hv1];
@@ -1581,25 +1605,36 @@ int dir;
else if (oip->ip_p == IPPROTO_UDP)
flags = IPN_UDP;
if (flags & IPN_TCPUDP) {
+ u_short data[2];
+ nat_t *nat;
+
minlen += 8; /* + 64bits of data to get ports */
if (ip->ip_len < ICMPERR_IPICMPHLEN + minlen)
return NULL;
+
+ data[0] = fin->fin_data[0];
+ data[1] = fin->fin_data[1];
tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2));
- if (dir == NAT_INBOUND)
- return nat_inlookup(fin->fin_ifp, flags,
- (u_int)oip->ip_p, oip->ip_dst, oip->ip_src,
- (tcp->th_sport << 16) | tcp->th_dport, 0);
- else
- return nat_outlookup(fin->fin_ifp, flags,
- (u_int)oip->ip_p, oip->ip_dst, oip->ip_src,
- (tcp->th_sport << 16) | tcp->th_dport, 0);
+ fin->fin_data[0] = ntohs(tcp->th_dport);
+ fin->fin_data[1] = ntohs(tcp->th_sport);
+
+ if (dir == NAT_INBOUND) {
+ nat = nat_inlookup(fin, flags, (u_int)oip->ip_p,
+ oip->ip_dst, oip->ip_src, 0);
+ } else {
+ nat = nat_outlookup(fin, flags, (u_int)oip->ip_p,
+ oip->ip_dst, oip->ip_src, 0);
+ }
+ fin->fin_data[0] = data[0];
+ fin->fin_data[1] = data[1];
+ return nat;
}
if (dir == NAT_INBOUND)
- return nat_inlookup(fin->fin_ifp, 0, (u_int)oip->ip_p,
- oip->ip_dst, oip->ip_src, 0, 0);
+ return nat_inlookup(fin, 0, (u_int)oip->ip_p,
+ oip->ip_dst, oip->ip_src, 0);
else
- return nat_outlookup(fin->fin_ifp, 0, (u_int)oip->ip_p,
- oip->ip_dst, oip->ip_src, 0, 0);
+ return nat_outlookup(fin, 0, (u_int)oip->ip_p,
+ oip->ip_dst, oip->ip_src, 0);
}
@@ -1619,7 +1654,7 @@ int dir;
udphdr_t *udp;
nat_t *nat;
ip_t *oip;
- int flags = 0;
+ int flags;
if ((fin->fin_fl & FI_SHORT) || (fin->fin_off != 0))
return NULL;
@@ -1628,6 +1663,8 @@ int dir;
*/
if ((ip->ip_v != 4) || !(nat = nat_icmplookup(ip, fin, dir)))
return NULL;
+
+ flags = 0;
*nflags = IPN_ICMPERR;
icmp = (icmphdr_t *)fin->fin_dp;
oip = (ip_t *)&icmp->icmp_ip;
@@ -1917,23 +1954,32 @@ int dir;
* we're looking for a table entry, based on the destination address.
* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.
*/
-nat_t *nat_inlookup(ifp, flags, p, src, mapdst, ports, rw)
-void *ifp;
+nat_t *nat_inlookup(fin, flags, p, src, mapdst, rw)
+fr_info_t *fin;
register u_int flags, p;
struct in_addr src , mapdst;
-u_32_t ports;
int rw;
{
register u_short sport, dport;
register nat_t *nat;
register int nflags;
register u_32_t dst;
+ ipnat_t *ipn;
+ void *ifp;
u_int hv;
+ if (fin != NULL)
+ ifp = fin->fin_ifp;
+ else
+ ifp = NULL;
dst = mapdst.s_addr;
- dport = ports >> 16;
- sport = ports & 0xffff;
- flags &= IPN_TCPUDP;
+ if (flags & IPN_TCPUDP) {
+ sport = htons(fin->fin_data[0]);
+ dport = htons(fin->fin_data[1]);
+ } else {
+ sport = 0;
+ dport = 0;
+ }
hv = NAT_HASH_FN(dst, dport, 0xffffffff);
hv = NAT_HASH_FN(src.s_addr, hv + sport, ipf_nattable_sz);
@@ -1943,19 +1989,34 @@ int rw;
if ((!ifp || ifp == nat->nat_ifp) &&
nat->nat_oip.s_addr == src.s_addr &&
nat->nat_outip.s_addr == dst &&
- (((p == 0) && (flags == (nat->nat_flags & IPN_TCPUDP)))
- || (p == nat->nat_p)) && (!flags ||
- (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) &&
- ((nat->nat_outport == dport) || (nflags & FI_W_SPORT)))))
+ ((p == 0) || (p == nat->nat_p))) {
+ switch (p)
+ {
+ case IPPROTO_TCP :
+ case IPPROTO_UDP :
+ if (nat->nat_oport != sport)
+ continue;
+ if (nat->nat_outport != dport)
+ continue;
+ break;
+ default :
+ break;
+ }
+
+ ipn = nat->nat_ptr;
+ if ((ipn != NULL) && (nat->nat_aps != NULL))
+ if (appr_match(fin, nat) != 0)
+ continue;
return nat;
+ }
}
- if (!nat_stats.ns_wilds || !(flags & IPN_TCPUDP))
+ if (!nat_stats.ns_wilds || !(flags & FI_WILDP))
return NULL;
if (!rw) {
RWLOCK_EXIT(&ipf_nat);
}
hv = NAT_HASH_FN(dst, 0, 0xffffffff);
- hv = NAT_HASH_FN(src.s_addr, hv, ipf_nattable_sz);
+ hv = NAT_HASH_FN(src.s_addr, dst, ipf_nattable_sz);
if (!rw) {
WRITE_ENTER(&ipf_nat);
}
@@ -1964,8 +2025,6 @@ int rw;
nflags = nat->nat_flags;
if (ifp && ifp != nat->nat_ifp)
continue;
- if (!(nflags & IPN_TCPUDP))
- continue;
if (!(nflags & FI_WILDP))
continue;
if (nat->nat_oip.s_addr != src.s_addr ||
@@ -1973,7 +2032,7 @@ int rw;
continue;
if (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) &&
((nat->nat_outport == dport) || (nflags & FI_W_SPORT))) {
- nat_tabmove(nat, ports);
+ nat_tabmove(fin, nat);
break;
}
}
@@ -1989,21 +2048,18 @@ int rw;
* original was placed in the table without hashing on the ports and we now
* want to include hashing on port numbers.
*/
-static void nat_tabmove(nat, ports)
+static void nat_tabmove(fin, nat)
+fr_info_t *fin;
nat_t *nat;
-u_32_t ports;
{
register u_short sport, dport;
+ u_int hv, nflags;
nat_t **natp;
- u_int hv;
- dport = ports >> 16;
- sport = ports & 0xffff;
+ nflags = nat->nat_flags;
- if (nat->nat_oport == dport) {
- nat->nat_inport = sport;
- nat->nat_outport = sport;
- }
+ sport = ntohs(fin->fin_data[0]);
+ dport = ntohs(fin->fin_data[1]);
/*
* Remove the NAT entry from the old location
@@ -2045,23 +2101,29 @@ u_32_t ports;
* we're looking for a table entry, based on the source address.
* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.
*/
-nat_t *nat_outlookup(ifp, flags, p, src, dst, ports, rw)
-void *ifp;
+nat_t *nat_outlookup(fin, flags, p, src, dst, rw)
+fr_info_t *fin;
register u_int flags, p;
struct in_addr src , dst;
-u_32_t ports;
int rw;
{
register u_short sport, dport;
register nat_t *nat;
register int nflags;
+ ipnat_t *ipn;
u_32_t srcip;
+ void *ifp;
u_int hv;
- sport = ports & 0xffff;
- dport = ports >> 16;
- flags &= IPN_TCPUDP;
+ ifp = fin->fin_ifp;
srcip = src.s_addr;
+ if (flags & IPN_TCPUDP) {
+ sport = ntohs(fin->fin_data[0]);
+ dport = ntohs(fin->fin_data[1]);
+ } else {
+ sport = 0;
+ dport = 0;
+ }
hv = NAT_HASH_FN(srcip, sport, 0xffffffff);
hv = NAT_HASH_FN(dst.s_addr, hv + dport, ipf_nattable_sz);
@@ -2072,19 +2134,34 @@ int rw;
if ((!ifp || ifp == nat->nat_ifp) &&
nat->nat_inip.s_addr == srcip &&
nat->nat_oip.s_addr == dst.s_addr &&
- (((p == 0) && (flags == (nflags & IPN_TCPUDP)))
- || (p == nat->nat_p)) && (!flags ||
- ((nat->nat_inport == sport || nflags & FI_W_SPORT) &&
- (nat->nat_oport == dport || nflags & FI_W_DPORT))))
+ ((p == 0) || (p == nat->nat_p))) {
+ switch (p)
+ {
+ case IPPROTO_TCP :
+ case IPPROTO_UDP :
+ if (nat->nat_oport != dport)
+ continue;
+ if (nat->nat_inport != sport)
+ continue;
+ break;
+ default :
+ break;
+ }
+
+ ipn = nat->nat_ptr;
+ if ((ipn != NULL) && (nat->nat_aps != NULL))
+ if (appr_match(fin, nat) != 0)
+ continue;
return nat;
+ }
}
- if (!nat_stats.ns_wilds || !(flags & IPN_TCPUDP))
+ if (!nat_stats.ns_wilds || !(flags & FI_WILDP))
return NULL;
if (!rw) {
RWLOCK_EXIT(&ipf_nat);
}
- hv = NAT_HASH_FN(srcip, 0, ipf_nattable_sz);
- hv = NAT_HASH_FN(dst.s_addr, hv, ipf_nattable_sz);
+
+ hv = NAT_HASH_FN(dst.s_addr, srcip, ipf_nattable_sz);
if (!rw) {
WRITE_ENTER(&ipf_nat);
}
@@ -2093,8 +2170,6 @@ int rw;
nflags = nat->nat_flags;
if (ifp && ifp != nat->nat_ifp)
continue;
- if (!(nflags & IPN_TCPUDP))
- continue;
if (!(nflags & FI_WILDP))
continue;
if ((nat->nat_inip.s_addr != srcip) ||
@@ -2102,7 +2177,7 @@ int rw;
continue;
if (((nat->nat_inport == sport) || (nflags & FI_W_SPORT)) &&
((nat->nat_oport == dport) || (nflags & FI_W_DPORT))) {
- nat_tabmove(nat, ports);
+ nat_tabmove(fin, nat);
break;
}
}
@@ -2119,16 +2194,19 @@ int rw;
nat_t *nat_lookupredir(np)
register natlookup_t *np;
{
- u_32_t ports;
nat_t *nat;
+ fr_info_t fi;
+
+ bzero((char *)&fi, sizeof(fi));
+ fi.fin_data[0] = np->nl_inport;
+ fi.fin_data[1] = np->nl_outport;
- ports = (np->nl_outport << 16) | np->nl_inport;
/*
* If nl_inip is non null, this is a lookup based on the real
* ip address. Else, we use the fake.
*/
- if ((nat = nat_outlookup(NULL, np->nl_flags, 0, np->nl_inip,
- np->nl_outip, ports, 0))) {
+ if ((nat = nat_outlookup(&fi, np->nl_flags, 0, np->nl_inip,
+ np->nl_outip, 0))) {
np->nl_realip = nat->nat_outip;
np->nl_realport = nat->nat_outport;
}
@@ -2146,7 +2224,7 @@ ip_t *ip;
if (ip->ip_v != 4)
return 0;
- if (np->in_p && ip->ip_p != np->in_p)
+ if (np->in_p && fin->fin_p != np->in_p)
return 0;
if (fin->fin_out) {
if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK)))
@@ -2196,6 +2274,7 @@ fr_info_t *fin;
u_int nflags = 0, hv, msk;
struct ifnet *ifp;
frentry_t *fr;
+ void *sifp;
u_32_t iph;
nat_t *nat;
@@ -2203,15 +2282,17 @@ fr_info_t *fin;
return 0;
if ((fr = fin->fin_fr) && !(fr->fr_flags & FR_DUP) &&
- fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1)
- ifp = fr->fr_tif.fd_ifp;
- else
- ifp = fin->fin_ifp;
+ fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1) {
+ sifp = fin->fin_ifp;
+ fin->fin_ifp = fr->fr_tif.fd_ifp;
+ } else
+ sifp = fin->fin_ifp;
+ ifp = fin->fin_ifp;
if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) {
- if (ip->ip_p == IPPROTO_TCP)
+ if (fin->fin_p == IPPROTO_TCP)
nflags = IPN_TCP;
- else if (ip->ip_p == IPPROTO_UDP)
+ else if (fin->fin_p == IPPROTO_UDP)
nflags = IPN_UDP;
if ((nflags & IPN_TCPUDP)) {
tcp = (tcphdr_t *)fin->fin_dp;
@@ -2220,27 +2301,28 @@ fr_info_t *fin;
}
}
- ipa = ip->ip_src.s_addr;
+ ipa = fin->fin_saddr;
READ_ENTER(&ipf_nat);
- if ((ip->ip_p == IPPROTO_ICMP) &&
+ if ((fin->fin_p == IPPROTO_ICMP) &&
(nat = nat_icmp(ip, fin, &nflags, NAT_OUTBOUND)))
icmpset = 1;
else if ((fin->fin_fl & FI_FRAG) &&
(nat = ipfr_nat_knownfrag(ip, fin)))
natadd = 0;
- else if ((nat = nat_outlookup(ifp, nflags, (u_int)ip->ip_p,
- ip->ip_src, ip->ip_dst,
- (dport << 16) | sport, 0))) {
+ else if ((nat = nat_outlookup(fin, nflags|FI_WILDP|FI_WILDA,
+ (u_int)fin->fin_p, fin->fin_src,
+ fin->fin_dst, 0))) {
nflags = nat->nat_flags;
if ((nflags & (FI_W_SPORT|FI_W_DPORT)) != 0) {
if ((nflags & FI_W_SPORT) &&
(nat->nat_inport != sport))
nat->nat_inport = sport;
- else if ((nflags & FI_W_DPORT) &&
- (nat->nat_oport != dport))
+ if ((nflags & FI_W_DPORT) &&
+ (nat->nat_oport != dport))
nat->nat_oport = dport;
+
if (nat->nat_outport == 0)
nat->nat_outport = sport;
nat->nat_flags &= ~(FI_W_DPORT|FI_W_SPORT);
@@ -2249,13 +2331,15 @@ fr_info_t *fin;
}
} else {
RWLOCK_EXIT(&ipf_nat);
+
+ msk = 0xffffffff;
+ i = 32;
+
WRITE_ENTER(&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).
*/
- msk = 0xffffffff;
- i = 32;
maskloop:
iph = ipa & htonl(msk);
hv = NAT_HASH_FN(iph, 0, ipf_natrules_sz);
@@ -2271,22 +2355,13 @@ maskloop:
continue;
} else if ((ipa & np->in_inmsk) != np->in_inip)
continue;
- if (np->in_redir & (NAT_MAP|NAT_MAPBLK)) {
- if (*np->in_plabel && !appr_ok(ip, tcp, np))
- continue;
- /*
- * If it's a redirection, then we don't want to
- * create new outgoing port stuff.
- * Redirections are only for incoming
- * connections.
- */
- if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK)))
- continue;
- if ((nat = nat_new(np, ip, fin, (u_int)nflags,
- NAT_OUTBOUND))) {
- np->in_hits++;
- break;
- }
+ if (*np->in_plabel && !appr_ok(ip, tcp, np))
+ continue;
+ nat = nat_new(fin, ip, np, NULL,
+ (u_int)nflags, NAT_OUTBOUND);
+ if (nat != NULL) {
+ np->in_hits++;
+ break;
}
}
if ((np == NULL) && (i > 0)) {
@@ -2308,7 +2383,14 @@ maskloop:
if (natadd && (fin->fin_fl & FI_FRAG) && np)
ipfr_nat_newfrag(ip, fin, 0, nat);
MUTEX_ENTER(&nat->nat_lock);
- nat->nat_age = fr_defnatage;
+ if (fin->fin_p != IPPROTO_TCP) {
+ if (np && np->in_age[1])
+ nat->nat_age = np->in_age[1];
+ else if (!icmpset && (fin->fin_p == IPPROTO_ICMP))
+ nat->nat_age = fr_defnaticmpage;
+ else
+ nat->nat_age = fr_defnatage;
+ }
nat->nat_bytes += ip->ip_len;
nat->nat_pkts++;
MUTEX_EXIT(&nat->nat_lock);
@@ -2320,16 +2402,16 @@ maskloop:
if (nflags == IPN_ICMPERR) {
u_32_t s1, s2, sumd;
- s1 = LONG_SUM(ntohl(ip->ip_src.s_addr));
+ s1 = LONG_SUM(ntohl(fin->fin_saddr));
s2 = LONG_SUM(ntohl(nat->nat_outip.s_addr));
CALC_SUMD(s1, s2, sumd);
if (nat->nat_dir == NAT_OUTBOUND)
- fix_incksum(fin, &ip->ip_sum, sumd);
- else
fix_outcksum(fin, &ip->ip_sum, sumd);
+ else
+ fix_incksum(fin, &ip->ip_sum, sumd);
}
-#if SOLARIS || defined(__sgi)
+#if (SOLARIS || defined(__sgi)) && defined(_KERNEL)
else {
if (nat->nat_dir == NAT_OUTBOUND)
fix_outcksum(fin, &ip->ip_sum, nat->nat_ipsumd);
@@ -2337,16 +2419,19 @@ maskloop:
fix_incksum(fin, &ip->ip_sum, nat->nat_ipsumd);
}
#endif
+ /*
+ * Only change the packet contents, not what is filtered upon.
+ */
ip->ip_src = nat->nat_outip;
if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) {
- if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) {
+ if ((nat->nat_outport != 0) && (tcp != NULL)) {
tcp->th_sport = nat->nat_outport;
fin->fin_data[0] = ntohs(tcp->th_sport);
}
- if (ip->ip_p == IPPROTO_TCP) {
+ if (fin->fin_p == IPPROTO_TCP) {
csump = &tcp->th_sum;
MUTEX_ENTER(&nat->nat_lock);
fr_tcp_age(&nat->nat_age,
@@ -2366,25 +2451,24 @@ maskloop:
if (nat->nat_age == fr_tcpclosed)
nat->nat_age = fr_tcplastack;
MUTEX_EXIT(&nat->nat_lock);
- } else if (ip->ip_p == IPPROTO_UDP) {
+ } else if (fin->fin_p == IPPROTO_UDP) {
udphdr_t *udp = (udphdr_t *)tcp;
if (udp->uh_sum)
csump = &udp->uh_sum;
- } else if (ip->ip_p == IPPROTO_ICMP) {
- if (!icmpset)
- nat->nat_age = fr_defnaticmpage;
}
if (csump) {
if (nat->nat_dir == NAT_OUTBOUND)
- fix_outcksum(fin, csump, nat->nat_sumd[1]);
+ fix_outcksum(fin, csump,
+ nat->nat_sumd[1]);
else
- fix_incksum(fin, csump, nat->nat_sumd[1]);
+ fix_incksum(fin, csump,
+ nat->nat_sumd[1]);
}
}
- if ((np->in_apr != NULL) && (np->in_dport == 0 ||
+ if (np && (np->in_apr != NULL) && (np->in_dport == 0 ||
(tcp != NULL && dport == np->in_dport))) {
i = appr_check(ip, fin, nat);
if (i == 0)
@@ -2393,9 +2477,11 @@ maskloop:
i = 1;
ATOMIC_INCL(nat_stats.ns_mapped[1]);
RWLOCK_EXIT(&ipf_nat); /* READ */
+ fin->fin_ifp = sifp;
return i;
}
RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */
+ fin->fin_ifp = sifp;
return 0;
}
@@ -2423,37 +2509,36 @@ fr_info_t *fin;
return 0;
if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) {
- if (ip->ip_p == IPPROTO_TCP)
+ if (fin->fin_p == IPPROTO_TCP)
nflags = IPN_TCP;
- else if (ip->ip_p == IPPROTO_UDP)
+ else if (fin->fin_p == IPPROTO_UDP)
nflags = IPN_UDP;
if ((nflags & IPN_TCPUDP)) {
tcp = (tcphdr_t *)fin->fin_dp;
- dport = tcp->th_dport;
sport = tcp->th_sport;
+ dport = tcp->th_dport;
}
}
- in = ip->ip_dst;
+ in = fin->fin_dst;
/* make sure the source address is to be redirected */
- src = ip->ip_src;
+ src = fin->fin_src;
READ_ENTER(&ipf_nat);
- if ((ip->ip_p == IPPROTO_ICMP) &&
+ if ((fin->fin_p == IPPROTO_ICMP) &&
(nat = nat_icmp(ip, fin, &nflags, NAT_INBOUND)))
icmpset = 1;
else if ((fin->fin_fl & FI_FRAG) &&
(nat = ipfr_nat_knownfrag(ip, fin)))
natadd = 0;
- else if ((nat = nat_inlookup(fin->fin_ifp, nflags, (u_int)ip->ip_p,
- ip->ip_src, in, (dport << 16) | sport,
- 0))) {
+ else if ((nat = nat_inlookup(fin, nflags|FI_WILDP|FI_WILDA,
+ (u_int)fin->fin_p, fin->fin_src, in, 0))) {
nflags = nat->nat_flags;
if ((nflags & (FI_W_SPORT|FI_W_DPORT)) != 0) {
if ((nat->nat_oport != sport) && (nflags & FI_W_DPORT))
nat->nat_oport = sport;
- else if ((nat->nat_outport != dport) &&
+ if ((nat->nat_outport != dport) &&
(nflags & FI_W_SPORT))
nat->nat_outport = dport;
nat->nat_flags &= ~(FI_W_SPORT|FI_W_DPORT);
@@ -2462,19 +2547,21 @@ fr_info_t *fin;
}
} else {
RWLOCK_EXIT(&ipf_nat);
+
+ msk = 0xffffffff;
+ i = 32;
+
WRITE_ENTER(&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).
*/
- msk = 0xffffffff;
- i = 32;
maskloop:
iph = in.s_addr & htonl(msk);
hv = NAT_HASH_FN(iph, 0, ipf_rdrrules_sz);
for (np = rdr_rules[hv]; np; np = np->in_rnext) {
if ((np->in_ifp && (np->in_ifp != ifp)) ||
- (np->in_p && (np->in_p != ip->ip_p)) ||
+ (np->in_p && (np->in_p != fin->fin_p)) ||
(np->in_flags && !(nflags & np->in_flags)))
continue;
if (np->in_flags & IPN_FILTER) {
@@ -2482,11 +2569,10 @@ maskloop:
continue;
} else if ((in.s_addr & np->in_outmsk) != np->in_outip)
continue;
- if ((np->in_redir & NAT_REDIRECT) &&
- (!np->in_pmin || (np->in_flags & IPN_FILTER) ||
+ if ((!np->in_pmin || (np->in_flags & IPN_FILTER) ||
((ntohs(np->in_pmax) >= ntohs(dport)) &&
(ntohs(dport) >= ntohs(np->in_pmin)))))
- if ((nat = nat_new(np, ip, fin, nflags,
+ if ((nat = nat_new(fin, ip, np, NULL, nflags,
NAT_INBOUND))) {
np->in_hits++;
break;
@@ -2512,8 +2598,8 @@ maskloop:
fin->fin_fr = nat->nat_fr;
if (natadd && (fin->fin_fl & FI_FRAG) && np)
ipfr_nat_newfrag(ip, fin, 0, nat);
- if ((np->in_apr != NULL) && (np->in_dport == 0 ||
- (tcp != NULL && sport == np->in_dport))) {
+ if (np && (np->in_apr != NULL) && (np->in_dport == 0 ||
+ (tcp != NULL && sport == np->in_dport))) {
i = appr_check(ip, fin, nat);
if (i == -1) {
RWLOCK_EXIT(&ipf_nat);
@@ -2522,9 +2608,14 @@ maskloop:
}
MUTEX_ENTER(&nat->nat_lock);
- if (nflags != IPN_ICMPERR)
- nat->nat_age = fr_defnatage;
-
+ if (fin->fin_p != IPPROTO_TCP) {
+ if (np && np->in_age[0])
+ nat->nat_age = np->in_age[0];
+ else if (!icmpset && (fin->fin_p == IPPROTO_ICMP))
+ nat->nat_age = fr_defnaticmpage;
+ else
+ nat->nat_age = fr_defnatage;
+ }
nat->nat_bytes += ip->ip_len;
nat->nat_pkts++;
MUTEX_EXIT(&nat->nat_lock);
@@ -2535,7 +2626,7 @@ maskloop:
* Fix up checksums, not by recalculating them, but
* simply computing adjustments.
*/
-#if SOLARIS || defined(__sgi)
+#if (SOLARIS || defined(__sgi)) && defined(_KERNEL)
if (nat->nat_dir == NAT_OUTBOUND)
fix_incksum(fin, &ip->ip_sum, nat->nat_ipsumd);
else
@@ -2543,12 +2634,12 @@ maskloop:
#endif
if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) {
- if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) {
+ if ((nat->nat_inport != 0) && (tcp != NULL)) {
tcp->th_dport = nat->nat_inport;
fin->fin_data[1] = ntohs(tcp->th_dport);
}
- if (ip->ip_p == IPPROTO_TCP) {
+ if (fin->fin_p == IPPROTO_TCP) {
csump = &tcp->th_sum;
MUTEX_ENTER(&nat->nat_lock);
fr_tcp_age(&nat->nat_age,
@@ -2568,21 +2659,20 @@ maskloop:
if (nat->nat_age == fr_tcpclosed)
nat->nat_age = fr_tcplastack;
MUTEX_EXIT(&nat->nat_lock);
- } else if (ip->ip_p == IPPROTO_UDP) {
+ } else if (fin->fin_p == IPPROTO_UDP) {
udphdr_t *udp = (udphdr_t *)tcp;
if (udp->uh_sum)
csump = &udp->uh_sum;
- } else if (ip->ip_p == IPPROTO_ICMP) {
- if (!icmpset)
- nat->nat_age = fr_defnaticmpage;
}
if (csump) {
if (nat->nat_dir == NAT_OUTBOUND)
- fix_incksum(fin, csump, nat->nat_sumd[0]);
+ fix_incksum(fin, csump,
+ nat->nat_sumd[0]);
else
- fix_outcksum(fin, csump, nat->nat_sumd[0]);
+ fix_outcksum(fin, csump,
+ nat->nat_sumd[0]);
}
}
ATOMIC_INCL(nat_stats.ns_mapped[0]);
@@ -2757,3 +2847,13 @@ u_int type;
(void) ipllog(IPL_LOGNAT, NULL, items, sizes, types, 1);
}
#endif
+
+
+#if defined(__OpenBSD__)
+void nat_ifdetach(ifp)
+void *ifp;
+{
+ frsync();
+ return;
+}
+#endif