summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authordarrenr <darrenr@FreeBSD.org>2000-10-26 12:33:42 +0000
committerdarrenr <darrenr@FreeBSD.org>2000-10-26 12:33:42 +0000
commit1a1de29bc037bc05ce4aec3d225e476799ab5a27 (patch)
tree50760b3edd676bcf8b9bc65cbfd7839eb1866c95 /sys
parenta21e3405e2f118d575c74cf92c09a22eaee4c261 (diff)
downloadFreeBSD-src-1a1de29bc037bc05ce4aec3d225e476799ab5a27.zip
FreeBSD-src-1a1de29bc037bc05ce4aec3d225e476799ab5a27.tar.gz
fix conflicts from rcsids
Diffstat (limited to 'sys')
-rw-r--r--sys/contrib/ipfilter/netinet/fil.c59
-rw-r--r--sys/contrib/ipfilter/netinet/ip_auth.h2
-rw-r--r--sys/contrib/ipfilter/netinet/ip_compat.h36
-rw-r--r--sys/contrib/ipfilter/netinet/ip_fil.c37
-rw-r--r--sys/contrib/ipfilter/netinet/ip_frag.c21
-rw-r--r--sys/contrib/ipfilter/netinet/ip_frag.h2
-rw-r--r--sys/contrib/ipfilter/netinet/ip_ftp_pxy.c22
-rw-r--r--sys/contrib/ipfilter/netinet/ip_nat.c437
-rw-r--r--sys/contrib/ipfilter/netinet/ip_nat.h12
-rw-r--r--sys/contrib/ipfilter/netinet/ip_raudio_pxy.c2
-rw-r--r--sys/contrib/ipfilter/netinet/ip_state.c142
-rw-r--r--sys/contrib/ipfilter/netinet/ip_state.h1
-rw-r--r--sys/contrib/ipfilter/netinet/ipl.h2
-rw-r--r--sys/contrib/ipfilter/netinet/mlfk_ipl.c2
-rw-r--r--sys/netinet/fil.c59
-rw-r--r--sys/netinet/ip_auth.h2
-rw-r--r--sys/netinet/ip_compat.h36
-rw-r--r--sys/netinet/ip_fil.c37
-rw-r--r--sys/netinet/ip_frag.c21
-rw-r--r--sys/netinet/ip_frag.h2
-rw-r--r--sys/netinet/ip_ftp_pxy.c22
-rw-r--r--sys/netinet/ip_nat.c437
-rw-r--r--sys/netinet/ip_nat.h12
-rw-r--r--sys/netinet/ip_raudio_pxy.c2
-rw-r--r--sys/netinet/ip_state.c142
-rw-r--r--sys/netinet/ip_state.h1
-rw-r--r--sys/netinet/ipl.h2
-rw-r--r--sys/netinet/mlfk_ipl.c2
28 files changed, 1198 insertions, 356 deletions
diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c
index 1fb4b6c..12993ca 100644
--- a/sys/contrib/ipfilter/netinet/fil.c
+++ b/sys/contrib/ipfilter/netinet/fil.c
@@ -277,6 +277,16 @@ fr_info_t *fin;
int minicmpsz = sizeof(struct icmp);
icmphdr_t *icmp;
+ if (fin->fin_dlen > 1)
+ fin->fin_data[0] = *(u_short *)tcp;
+
+ if ((!(plen >= hlen + minicmpsz) && !off) ||
+ (off && off < sizeof(struct icmp))) {
+ fi->fi_fl |= FI_SHORT;
+ if (fin->fin_dlen < 2)
+ break;
+ }
+
icmp = (icmphdr_t *)tcp;
if (!off && (icmp->icmp_type == ICMP_ECHOREPLY ||
@@ -294,11 +304,6 @@ fr_info_t *fin;
icmp->icmp_type == ICMP_MASKREPLY))
minicmpsz = 12;
- if ((!(plen >= hlen + minicmpsz) && !off) ||
- (off && off < sizeof(struct icmp)))
- fi->fi_fl |= FI_SHORT;
- if (fin->fin_dlen > 1)
- fin->fin_data[0] = *(u_short *)tcp;
break;
}
case IPPROTO_TCP :
@@ -743,6 +748,7 @@ int out;
#ifdef _KERNEL
mb_t *mc = NULL;
+ int p, len;
# if !defined(__SVR4) && !defined(__svr4__)
# ifdef __sgi
char hbuf[(0xf << 2) + sizeof(struct icmp) + sizeof(ip_t) + 8];
@@ -767,13 +773,26 @@ int out;
}
# endif /* CSUM_DELAY_DATA */
+# ifdef USE_INET6
+ if (v == 6) {
+ len = ntohs(((ip6_t*)ip)->ip6_plen);
+ p = ((ip6_t *)ip)->ip6_nxt;
+ } else
+# endif
+ {
+ p = ip->ip_p;
+ len = ip->ip_len;
+ }
- if ((ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP ||
- ip->ip_p == IPPROTO_ICMP)) {
+ if ((p == IPPROTO_TCP || p == IPPROTO_UDP || p == IPPROTO_ICMP
+# ifdef USE_INET6
+ || (v == 6 && p == IPPROTO_ICMPV6)
+# endif
+ )) {
int plen = 0;
- if ((ip->ip_off & IP_OFFMASK) == 0)
- switch(ip->ip_p)
+ if ((v == 6) || (ip->ip_off & IP_OFFMASK) == 0)
+ switch(p)
{
case IPPROTO_TCP:
plen = sizeof(tcphdr_t);
@@ -783,10 +802,13 @@ int out;
break;
/* 96 - enough for complete ICMP error IP header */
case IPPROTO_ICMP:
+# ifdef USE_INET6
+ case IPPROTO_ICMPV6 :
+# endif
plen = ICMPERR_MAXPKTLEN - sizeof(ip_t);
break;
}
- up = MIN(hlen + plen, ip->ip_len);
+ up = MIN(hlen + plen, len);
if (up > m->m_len) {
# ifdef __sgi
@@ -835,8 +857,8 @@ int out;
#endif
changed = 0;
- fin->fin_v = v;
fin->fin_ifp = ifp;
+ fin->fin_v = v;
fin->fin_out = out;
fin->fin_mp = mp;
fr_makefrip(hlen, ip, fin);
@@ -1383,7 +1405,7 @@ nodata:
* SUCH DAMAGE.
*
* @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94
- * $Id: fil.c,v 2.35.2.20 2000/08/13 04:15:43 darrenr Exp $
+ * $Id: fil.c,v 2.35.2.26 2000/10/24 11:58:17 darrenr Exp $
*/
/*
* Copy data from an mbuf chain starting "off" bytes from the beginning,
@@ -1862,7 +1884,7 @@ size_t c;
int err;
#if SOLARIS
- if (copyin(a, &ca, sizeof(ca)))
+ if (copyin(a, (char *)&ca, sizeof(ca)))
return EFAULT;
#else
bcopy(a, &ca, sizeof(ca));
@@ -1882,7 +1904,7 @@ size_t c;
int err;
#if SOLARIS
- if (copyin(b, &ca, sizeof(ca)))
+ if (copyin(b, (char *)&ca, sizeof(ca)))
return EFAULT;
#else
bcopy(b, &ca, sizeof(ca));
@@ -1976,6 +1998,15 @@ friostat_t *fiop;
fiop->f_acctin6[1] = ipacct6[0][1];
fiop->f_acctout6[0] = ipacct6[1][0];
fiop->f_acctout6[1] = ipacct6[1][1];
+#else
+ fiop->f_fin6[0] = NULL;
+ fiop->f_fin6[1] = NULL;
+ fiop->f_fout6[0] = NULL;
+ fiop->f_fout6[1] = NULL;
+ fiop->f_acctin6[0] = NULL;
+ fiop->f_acctin6[1] = NULL;
+ fiop->f_acctout6[0] = NULL;
+ fiop->f_acctout6[1] = NULL;
#endif
fiop->f_active = fr_active;
fiop->f_froute[0] = ipl_frouteok[0];
diff --git a/sys/contrib/ipfilter/netinet/ip_auth.h b/sys/contrib/ipfilter/netinet/ip_auth.h
index 8be860c..2851c3d 100644
--- a/sys/contrib/ipfilter/netinet/ip_auth.h
+++ b/sys/contrib/ipfilter/netinet/ip_auth.h
@@ -47,8 +47,6 @@ typedef struct fr_authstat {
extern frentry_t *ipauth;
extern struct fr_authstat fr_authstats;
extern int fr_defaultauthage;
-extern int fr_authstart;
-extern int fr_authend;
extern int fr_authsize;
extern int fr_authused;
extern int fr_auth_lock;
diff --git a/sys/contrib/ipfilter/netinet/ip_compat.h b/sys/contrib/ipfilter/netinet/ip_compat.h
index 1c3e245..d313952 100644
--- a/sys/contrib/ipfilter/netinet/ip_compat.h
+++ b/sys/contrib/ipfilter/netinet/ip_compat.h
@@ -264,6 +264,12 @@ union i6addr {
#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL))
+# ifdef IPFILTER_LKM
+# include <osreldate.h>
+# define ACTUALLY_LKM_NOT_KERNEL
+# else
+# include <sys/osreldate.h>
+# endif
# if __FreeBSD__ < 3
# include <machine/spl.h>
# else
@@ -289,6 +295,19 @@ union i6addr {
# define ATOMIC_DEC32 ATOMIC_DEC
# define ATOMIC_DEC16 ATOMIC_DEC
#endif
+#ifdef __sgi
+# define hz HZ
+# include <sys/ksynch.h>
+# define IPF_LOCK_PL plhi
+# include <sys/sema.h>
+#undef kmutex_t
+typedef struct {
+ lock_t *l;
+ int pl;
+} kmutex_t;
+# undef MUTEX_INIT
+# undef MUTEX_DESTROY
+#endif
#ifdef KERNEL
# if SOLARIS
# if SOLARIS2 >= 6
@@ -338,8 +357,8 @@ union i6addr {
# define MUTEX_DESTROY(x) mutex_destroy(x)
# define MUTEX_EXIT(x) mutex_exit(x)
# define MTOD(m,t) (t)((m)->b_rptr)
-# define IRCOPY(a,b,c) copyin((a), (b), (c))
-# define IWCOPY(a,b,c) copyout((a), (b), (c))
+# define IRCOPY(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c))
+# define IWCOPY(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c))
# define IRCOPYPTR ircopyptr
# define IWCOPYPTR iwcopyptr
# define FREE_MB_T(m) freemsg(m)
@@ -384,15 +403,6 @@ extern ill_t *get_unit __P((char *, int));
# define IFNAME(x) ((ill_t *)x)->ill_name
# else /* SOLARIS */
# if defined(__sgi)
-# define hz HZ
-# include <sys/ksynch.h>
-# define IPF_LOCK_PL plhi
-# include <sys/sema.h>
-#undef kmutex_t
-typedef struct {
- lock_t *l;
- int pl;
-} kmutex_t;
# define ATOMIC_INC(x) { MUTEX_ENTER(&ipf_rw); \
(x)++; MUTEX_EXIT(&ipf_rw); }
# define ATOMIC_DEC(x) { MUTEX_ENTER(&ipf_rw); \
@@ -405,8 +415,8 @@ typedef struct {
# define MUTEX_DOWNGRADE(x) ;
# define RWLOCK_EXIT(x) MUTEX_EXIT(x)
# define MUTEX_EXIT(x) UNLOCK((x)->l, (x)->pl);
-# define MUTEX_INIT(x,y,z) (x).l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP)
-# define MUTEX_DESTROY(x) LOCK_DEALLOC((x).l)
+# define MUTEX_INIT(x,y,z) (x)->l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP)
+# define MUTEX_DESTROY(x) LOCK_DEALLOC((x)->l)
# else /* __sgi */
# define ATOMIC_INC(x) (x)++
# define ATOMIC_DEC(x) (x)--
diff --git a/sys/contrib/ipfilter/netinet/ip_fil.c b/sys/contrib/ipfilter/netinet/ip_fil.c
index 27aca2f..797e599 100644
--- a/sys/contrib/ipfilter/netinet/ip_fil.c
+++ b/sys/contrib/ipfilter/netinet/ip_fil.c
@@ -173,6 +173,9 @@ struct callout_handle ipfr_slowtimer_ch;
# include <sys/callout.h>
struct callout ipfr_slowtimer_ch;
#endif
+#if defined(__sgi) && defined(_KERNEL)
+toid_t ipfr_slowtimer_ch;
+#endif
#if (_BSDI_VERSION >= 199510) && defined(_KERNEL)
# include <sys/device.h>
@@ -322,7 +325,7 @@ pfil_error:
callout_init(&ipfr_slowtimer_ch);
callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL);
# else
-# if (__FreeBSD_version >= 300000) && defined(_KERNEL)
+# if (__FreeBSD_version >= 300000) || defined(__sgi)
ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2);
# else
timeout(ipfr_slowtimer, NULL, hz/2);
@@ -353,7 +356,7 @@ int ipldetach()
untimeout(ipfr_slowtimer, NULL, ipfr_slowtimer_ch);
# else
# ifdef __sgi
- untimeout(ipfr_slowtimer);
+ untimeout(ipfr_slowtimer_ch);
# else
untimeout(ipfr_slowtimer, NULL);
# endif
@@ -980,8 +983,10 @@ fr_info_t *fin;
if (m == NULL)
return -1;
- if (tcp->th_flags & TH_SYN)
- tlen = 1;
+ tlen = oip->ip_len - fin->fin_hlen - (tcp->th_off << 2) +
+ ((tcp->th_flags & TH_SYN) ? 1 : 0) +
+ ((tcp->th_flags & TH_FIN) ? 1 : 0);
+
#ifdef USE_INET6
hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t);
#else
@@ -1002,11 +1007,16 @@ fr_info_t *fin;
tcp2->th_sport = tcp->th_dport;
tcp2->th_dport = tcp->th_sport;
- tcp2->th_ack = ntohl(tcp->th_seq);
- tcp2->th_ack += tlen;
- tcp2->th_ack = htonl(tcp2->th_ack);
+ if (tcp->th_flags & TH_ACK) {
+ tcp2->th_seq = tcp->th_ack;
+ tcp2->th_flags = TH_RST;
+ } else {
+ tcp2->th_ack = ntohl(tcp->th_seq);
+ tcp2->th_ack += tlen;
+ tcp2->th_ack = htonl(tcp2->th_ack);
+ tcp2->th_flags = TH_RST|TH_ACK;
+ }
tcp2->th_off = sizeof(*tcp2) >> 2;
- tcp2->th_flags = TH_RST|TH_ACK;
# ifdef USE_INET6
if (fin->fin_v == 6) {
ip6->ip6_plen = htons(sizeof(struct tcphdr));
@@ -1148,7 +1158,12 @@ int dst;
m_freem(m);
return ENOBUFS;
}
+# ifdef M_TRAILINGSPACE
+ m->m_len = 0;
+ avail = M_TRAILINGSPACE(m);
+# else
avail = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN;
+# endif
xtra = MIN(ntohs(oip6->ip6_plen) + sizeof(ip6_t),
avail - hlen - sizeof(*icmp) - max_linkhdr);
if (dst == 0) {
@@ -1182,6 +1197,12 @@ int dst;
icmp->icmp_type = type;
icmp->icmp_code = fin->fin_icode;
icmp->icmp_cksum = 0;
+#ifdef icmp_nextmtu
+ if (type == ICMP_UNREACH &&
+ fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp)
+ icmp->icmp_nextmtu = htons(((struct ifnet *) ifp)->if_mtu);
+#endif
+
if (avail) {
bcopy((char *)oip, (char *)&icmp->icmp_ip, MIN(ohlen, avail));
avail -= MIN(ohlen, avail);
diff --git a/sys/contrib/ipfilter/netinet/ip_frag.c b/sys/contrib/ipfilter/netinet/ip_frag.c
index 8d2bbc5..2a10988 100644
--- a/sys/contrib/ipfilter/netinet/ip_frag.c
+++ b/sys/contrib/ipfilter/netinet/ip_frag.c
@@ -215,7 +215,7 @@ u_int pass;
ipfr_t *ipf;
if ((ip->ip_v != 4) || (fr_frag_lock))
- return NULL;
+ return -1;
WRITE_ENTER(&ipf_frag);
ipf = ipfr_new(ip, fin, pass, ipfr_heads);
RWLOCK_EXIT(&ipf_frag);
@@ -232,7 +232,7 @@ nat_t *nat;
ipfr_t *ipf;
if ((ip->ip_v != 4) || (fr_frag_lock))
- return NULL;
+ return -1;
WRITE_ENTER(&ipf_natfrag);
ipf = ipfr_new(ip, fin, pass, ipfr_nattab);
if (ipf != NULL) {
@@ -329,13 +329,16 @@ fr_info_t *fin;
ipf = ipfr_lookup(ip, fin, ipfr_nattab);
if (ipf != NULL) {
nat = ipf->ipfr_data;
- /*
- * This is the last fragment for this packet.
- */
- if ((ipf->ipfr_ttl == 1) && (nat != NULL)) {
- nat->nat_data = NULL;
- ipf->ipfr_data = NULL;
- }
+ if (nat->nat_ifp == fin->fin_ifp) {
+ /*
+ * This is the last fragment for this packet.
+ */
+ if ((ipf->ipfr_ttl == 1) && (nat != NULL)) {
+ nat->nat_data = NULL;
+ ipf->ipfr_data = NULL;
+ }
+ } else
+ nat = NULL;
} else
nat = NULL;
RWLOCK_EXIT(&ipf_natfrag);
diff --git a/sys/contrib/ipfilter/netinet/ip_frag.h b/sys/contrib/ipfilter/netinet/ip_frag.h
index 4fb3597..48144af 100644
--- a/sys/contrib/ipfilter/netinet/ip_frag.h
+++ b/sys/contrib/ipfilter/netinet/ip_frag.h
@@ -61,6 +61,6 @@ extern void ipfr_slowtimer __P((void *));
# endif
#else
extern int ipfr_slowtimer __P((void));
-#endif
+#endif /* (BSD >= 199306) || SOLARIS */
#endif /* __IP_FIL_H__ */
diff --git a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c
index ce06851..c68361a 100644
--- a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c
+++ b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c
@@ -145,6 +145,7 @@ int dlen;
} else
return 0;
a5 >>= 8;
+ a5 &= 0xff;
/*
* Calculate new address parts for PORT command
*/
@@ -213,7 +214,7 @@ int dlen;
sum2 -= sum1;
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
- fix_outcksum(&ip->ip_sum, sum2, 0);
+ fix_outcksum(&ip->ip_sum, sum2);
#endif
ip->ip_len += inc;
}
@@ -440,7 +441,7 @@ int dlen;
sum2 -= sum1;
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
- fix_outcksum(&ip->ip_sum, sum2, 0);
+ fix_outcksum(&ip->ip_sum, sum2);
#endif /* SOLARIS || defined(__sgi) */
ip->ip_len += inc;
}
@@ -669,15 +670,18 @@ int rv;
while ((rptr < wptr) && (*rptr != '\r'))
rptr++;
- if ((*rptr == '\r') && (rptr + 1 < wptr)) {
- if (*(rptr + 1) == '\n') {
- rptr += 2;
- f->ftps_junk = 0;
+ if (*rptr == '\r') {
+ if (rptr + 1 < wptr) {
+ if (*(rptr + 1) == '\n') {
+ rptr += 2;
+ f->ftps_junk = 0;
+ } else
+ rptr++;
} else
- rptr++;
+ break;
}
- f->ftps_rptr = rptr;
}
+ f->ftps_rptr = rptr;
if (rptr == wptr) {
rptr = wptr = f->ftps_buf;
@@ -761,5 +765,7 @@ char **ptr;
j += c - '0';
}
*ptr = s;
+ i &= 0xff;
+ j &= 0xff;
return (i << 8) | j;
}
diff --git a/sys/contrib/ipfilter/netinet/ip_nat.c b/sys/contrib/ipfilter/netinet/ip_nat.c
index 47c5f6a..ca3a27f 100644
--- a/sys/contrib/ipfilter/netinet/ip_nat.c
+++ b/sys/contrib/ipfilter/netinet/ip_nat.c
@@ -119,6 +119,7 @@ u_int ipf_nattable_sz = NAT_TABLE_SZ;
u_int ipf_natrules_sz = NAT_SIZE;
u_int ipf_rdrrules_sz = RDR_SIZE;
u_int ipf_hostmap_sz = HOSTMAP_SIZE;
+int nat_wilds = 0;
u_32_t nat_masks = 0;
u_32_t rdr_masks = 0;
ipnat_t **nat_rules = NULL;
@@ -144,6 +145,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_int));
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));
@@ -301,10 +303,9 @@ struct hostmap *hm;
}
-void fix_outcksum(sp, n , len)
+void fix_outcksum(sp, n)
u_short *sp;
u_32_t n;
-int len;
{
register u_short sumshort;
register u_32_t sum1;
@@ -327,10 +328,9 @@ int len;
}
-void fix_incksum(sp, n , len)
+void fix_incksum(sp, n)
u_short *sp;
u_32_t n;
-int len;
{
register u_short sumshort;
register u_32_t sum1;
@@ -358,6 +358,38 @@ int len;
/*
+ * fix_datacksum is used *only* for the adjustments of checksums in the data
+ * section of an IP packet.
+ *
+ * The only situation in which you need to do this is when NAT'ing an
+ * ICMP error message. Such a message, contains in its body the IP header
+ * of the original IP packet, that causes the error.
+ *
+ * You can't use fix_incksum or fix_outcksum in that case, because for the
+ * kernel the data section of the ICMP error is just data, and no special
+ * processing like hardware cksum or ntohs processing have been done by the
+ * kernel on the data section.
+ */
+void fix_datacksum(sp, n)
+u_short *sp;
+u_32_t n;
+{
+ register u_short sumshort;
+ register u_32_t sum1;
+
+ if (!n)
+ return;
+
+ sum1 = (~ntohs(*sp)) & 0xffff;
+ sum1 += (n);
+ sum1 = (sum1 >> 16) + (sum1 & 0xffff);
+ /* Again */
+ sum1 = (sum1 >> 16) + (sum1 & 0xffff);
+ sumshort = ~(u_short)sum1;
+ *(sp) = htons(sumshort);
+}
+
+/*
* How the NAT is organised and works.
*
* Inside (interface y) NAT Outside (interface x)
@@ -857,8 +889,8 @@ caddr_t data;
/*
* Initialize all these so that nat_delete() doesn't cause a crash.
*/
- nat->nat_hstart[0] = NULL;
- nat->nat_hstart[1] = NULL;
+ nat->nat_phnext[0] = NULL;
+ nat->nat_phnext[1] = NULL;
fr = nat->nat_fr;
nat->nat_fr = NULL;
aps = nat->nat_aps;
@@ -970,22 +1002,16 @@ junkput:
static void nat_delete(natd)
struct nat *natd;
{
- register struct nat **natp, *nat;
struct ipnat *ipn;
- for (natp = natd->nat_hstart[0]; natp && (nat = *natp);
- natp = &nat->nat_hnext[0])
- if (nat == natd) {
- *natp = nat->nat_hnext[0];
- break;
- }
-
- for (natp = natd->nat_hstart[1]; natp && (nat = *natp);
- natp = &nat->nat_hnext[1])
- if (nat == natd) {
- *natp = nat->nat_hnext[1];
- break;
- }
+ if (natd->nat_flags & FI_WILDP)
+ nat_wilds--;
+ if (natd->nat_hnext[0])
+ natd->nat_hnext[0]->nat_phnext[0] = natd->nat_phnext[0];
+ *natd->nat_phnext[0] = natd->nat_hnext[0];
+ 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_fr != NULL) {
ATOMIC_DEC32(natd->nat_fr->fr_ref);
@@ -1030,7 +1056,7 @@ static int nat_flushtable()
{
register nat_t *nat, **natp;
register int j = 0;
-
+
/*
* ALL NAT mappings deleted, so lets just make the deletions
* quicker.
@@ -1122,6 +1148,8 @@ int direction;
bzero((char *)nat, sizeof(*nat));
nat->nat_flags = flags;
+ if (flags & FI_WILDP)
+ nat_wilds++;
/*
* Search the current table for a match.
*/
@@ -1444,16 +1472,22 @@ nat_t *nat;
nat->nat_next = nat_instances;
nat_instances = nat;
+
hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport,
ipf_nattable_sz);
natp = &nat_table[0][hv];
- nat->nat_hstart[0] = natp;
+ if (*natp)
+ (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
+ nat->nat_phnext[0] = natp;
nat->nat_hnext[0] = *natp;
*natp = nat;
+
hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport,
ipf_nattable_sz);
natp = &nat_table[1][hv];
- nat->nat_hstart[1] = natp;
+ if (*natp)
+ (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
+ nat->nat_phnext[1] = natp;
nat->nat_hnext[1] = *natp;
*natp = nat;
@@ -1561,12 +1595,16 @@ int dir;
u_32_t sum1, sum2, sumd;
struct in_addr in;
icmphdr_t *icmp;
+ udphdr_t *udp;
nat_t *nat;
ip_t *oip;
int flags = 0;
if ((fin->fin_fi.fi_fl & FI_SHORT) || (ip->ip_off & IP_OFFMASK))
return NULL;
+ /*
+ * nat_icmplookup() will return NULL for `defective' packets.
+ */
if ((ip->ip_v != 4) || !(nat = nat_icmplookup(ip, fin, dir)))
return NULL;
*nflags = IPN_ICMPERR;
@@ -1576,16 +1614,33 @@ int dir;
flags = IPN_TCP;
else if (oip->ip_p == IPPROTO_UDP)
flags = IPN_UDP;
+ udp = (udphdr_t *)((((char *)oip) + (oip->ip_hl << 2)));
/*
* Need to adjust ICMP header to include the real IP#'s and
* port #'s. Only apply a checksum change relative to the
- * IP address change is it will be modified again in ip_natout
+ * IP address change as it will be modified again in ip_natout
* for both address and port. Two checksum changes are
* necessary for the two header address changes. Be careful
* to only modify the checksum once for the port # and twice
* for the IP#.
*/
+ /*
+ * Step 1
+ * Fix the IP addresses in the offending IP packet. You also need
+ * to adjust the IP header checksum of that offending IP packet
+ * and the ICMP checksum of the ICMP error message itself.
+ *
+ * Unfortunately, for UDP and TCP, the IP addresses are also contained
+ * in the pseudo header that is used to compute the UDP resp. TCP
+ * checksum. So, we must compensate that as well. Even worse, the
+ * change in the UDP and TCP checksums require yet another
+ * adjustment of the ICMP checksum of the ICMP error message.
+ *
+ * For the moment we forget about TCP, because that checksum is not
+ * in the first 8 bytes, so it will not be available in most cases.
+ */
+
if (nat->nat_dir == NAT_OUTBOUND) {
sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr));
in = nat->nat_inip;
@@ -1601,19 +1656,117 @@ int dir;
CALC_SUMD(sum1, sum2, sumd);
if (nat->nat_dir == NAT_OUTBOUND) {
- fix_incksum(&oip->ip_sum, sumd, 0);
+ /*
+ * Fix IP checksum of the offending IP packet to adjust for
+ * the change in the IP address.
+ *
+ * Normally, you would expect that the ICMP checksum of the
+ * ICMP error message needs to be adjusted as well for the
+ * IP address change in oip.
+ * However, this is a NOP, because the ICMP checksum is
+ * calculated over the complete ICMP packet, which includes the
+ * changed oip IP addresses and oip->ip_sum. However, these
+ * two changes cancel each other out (if the delta for
+ * the IP address is x, then the delta for ip_sum is minus x),
+ * so no change in the icmp_cksum is necessary.
+ *
+ * Be careful that nat_dir refers to the direction of the
+ * offending IP packet (oip), not to its ICMP response (icmp)
+ */
+ fix_datacksum(&oip->ip_sum, sumd);
- sumd += (sumd & 0xffff);
- while (sumd > 0xffff)
- sumd = (sumd & 0xffff) + (sumd >> 16);
- fix_outcksum(&icmp->icmp_cksum, sumd, 0);
+ /*
+ * Fix UDP pseudo header checksum to compensate for the
+ * IP address change.
+ */
+ if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) {
+ /*
+ * The UDP checksum is optional, only adjust it
+ * if it has been set.
+ */
+ sum1 = ntohs(udp->uh_sum);
+ fix_datacksum(&udp->uh_sum, sumd);
+ sum2 = ntohs(udp->uh_sum);
+
+ /*
+ * Fix ICMP checksum to compensate the UDP
+ * checksum adjustment.
+ */
+ CALC_SUMD(sum1, sum2, sumd);
+ fix_outcksum(&icmp->icmp_cksum, sumd);
+ }
+
+#if 0
+ /*
+ * Fix TCP pseudo header checksum to compensate for the
+ * IP address change. Before we can do the change, we
+ * must make sure that oip is sufficient large to hold
+ * the TCP checksum (normally it does not!).
+ */
+ if (oip->ip_p == IPPROTO_TCP) {
+
+ }
+#endif
} else {
- fix_outcksum(&oip->ip_sum, sumd, 0);
+
+ /*
+ * Fix IP checksum of the offending IP packet to adjust for
+ * the change in the IP address.
+ *
+ * Normally, you would expect that the ICMP checksum of the
+ * ICMP error message needs to be adjusted as well for the
+ * IP address change in oip.
+ * However, this is a NOP, because the ICMP checksum is
+ * calculated over the complete ICMP packet, which includes the
+ * changed oip IP addresses and oip->ip_sum. However, these
+ * two changes cancel each other out (if the delta for
+ * the IP address is x, then the delta for ip_sum is minus x),
+ * so no change in the icmp_cksum is necessary.
+ *
+ * Be careful that nat_dir refers to the direction of the
+ * offending IP packet (oip), not to its ICMP response (icmp)
+ */
+ fix_datacksum(&oip->ip_sum, sumd);
+
+/* XXX FV : without having looked at Solaris source code, it seems unlikely
+ * that SOLARIS would compensate this in the kernel (a body of an IP packet
+ * in the data section of an ICMP packet). I have the feeling that this should
+ * be unconditional, but I'm not in a position to check.
+ */
#if !SOLARIS && !defined(__sgi)
- sumd += (sumd & 0xffff);
- while (sumd > 0xffff)
- sumd = (sumd & 0xffff) + (sumd >> 16);
- fix_incksum(&icmp->icmp_cksum, sumd, 0);
+ /*
+ * Fix UDP pseudo header checksum to compensate for the
+ * IP address change.
+ */
+ if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) {
+ /*
+ * The UDP checksum is optional, only adjust it
+ * if it has been set
+ */
+ sum1 = ntohs(udp->uh_sum);
+ fix_datacksum(&udp->uh_sum, sumd);
+ sum2 = ntohs(udp->uh_sum);
+
+ /*
+ * Fix ICMP checksum to compensate the UDP
+ * checksum adjustment.
+ */
+ CALC_SUMD(sum1, sum2, sumd);
+ fix_incksum(&icmp->icmp_cksum, sumd);
+ }
+
+#if 0
+ /*
+ * Fix TCP pseudo header checksum to compensate for the
+ * IP address change. Before we can do the change, we
+ * must make sure that oip is sufficient large to hold
+ * the TCP checksum (normally it does not!).
+ */
+ if (oip->ip_p == IPPROTO_TCP) {
+
+ };
+#endif
+
#endif
}
@@ -1624,23 +1777,98 @@ int dir;
* XXX - what if this is bogus hl and we go off the end ?
* In this case, nat_icmpinlookup() will have returned NULL.
*/
- tcp = (tcphdr_t *)((((char *)oip) + (oip->ip_hl << 2)));
+ tcp = (tcphdr_t *)udp;
+
+ /*
+ * Step 2 :
+ * For offending TCP/UDP IP packets, translate the ports as
+ * well, based on the NAT specification. Of course such
+ * a change must be reflected in the ICMP checksum as well.
+ *
+ * Advance notice : Now it becomes complicated :-)
+ *
+ * Since the port fields are part of the TCP/UDP checksum
+ * of the offending IP packet, you need to adjust that checksum
+ * as well... but, if you change, you must change the icmp
+ * checksum *again*, to reflect that change.
+ *
+ * To further complicate: the TCP checksum is not in the first
+ * 8 bytes of the offending ip packet, so it most likely is not
+ * available (we might have to fix that if the encounter a
+ * device that returns more than 8 data bytes on icmp error)
+ */
if (nat->nat_dir == NAT_OUTBOUND) {
if (tcp->th_sport != nat->nat_inport) {
+ /*
+ * Fix ICMP checksum to compensate port
+ * adjustment.
+ */
sum1 = ntohs(tcp->th_sport);
sum2 = ntohs(nat->nat_inport);
CALC_SUMD(sum1, sum2, sumd);
tcp->th_sport = nat->nat_inport;
- fix_outcksum(&icmp->icmp_cksum, sumd, 0);
+ fix_outcksum(&icmp->icmp_cksum, sumd);
+
+ /*
+ * Fix udp checksum to compensate port
+ * adjustment. NOTE : the offending IP packet
+ * flows the other direction compared to the
+ * ICMP message.
+ *
+ * The UDP checksum is optional, only adjust
+ * it if it has been set.
+ */
+ if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) {
+
+ sum1 = ntohs(udp->uh_sum);
+ fix_datacksum(&udp->uh_sum, sumd);
+ sum2 = ntohs(udp->uh_sum);
+
+ /*
+ * Fix ICMP checksum to
+ * compensate UDP checksum
+ * adjustment.
+ */
+ CALC_SUMD(sum1, sum2, sumd);
+ fix_outcksum(&icmp->icmp_cksum, sumd);
+ }
}
} else {
+
if (tcp->th_dport != nat->nat_outport) {
+ /*
+ * Fix ICMP checksum to compensate port
+ * adjustment.
+ */
sum1 = ntohs(tcp->th_dport);
sum2 = ntohs(nat->nat_outport);
CALC_SUMD(sum1, sum2, sumd);
tcp->th_dport = nat->nat_outport;
- fix_incksum(&icmp->icmp_cksum, sumd, 0);
+ fix_incksum(&icmp->icmp_cksum, sumd);
+
+ /*
+ * Fix udp checksum to compensate port
+ * adjustment. NOTE : the offending IP
+ * packet flows the other direction compared
+ * to the ICMP message.
+ *
+ * The UDP checksum is optional, only adjust
+ * it if it has been set.
+ */
+ if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) {
+
+ sum1 = ntohs(udp->uh_sum);
+ fix_datacksum(&udp->uh_sum, sumd);
+ sum2 = ntohs(udp->uh_sum);
+
+ /*
+ * Fix ICMP checksum to compensate
+ * UDP checksum adjustment.
+ */
+ CALC_SUMD(sum1, sum2, sumd);
+ fix_incksum(&icmp->icmp_cksum, sumd);
+ }
}
}
}
@@ -1665,30 +1893,92 @@ register u_int flags, p;
struct in_addr src , mapdst;
u_32_t ports;
{
- register u_short sport, mapdport;
+ register u_short sport, dport;
register nat_t *nat;
register int nflags;
+ register u_32_t dst;
u_int hv;
- mapdport = ports >> 16;
+ dst = mapdst.s_addr;
+ dport = ports >> 16;
sport = ports & 0xffff;
flags &= IPN_TCPUDP;
- hv = NAT_HASH_FN(mapdst.s_addr, mapdport, ipf_nattable_sz);
+ hv = NAT_HASH_FN(dst, dport, ipf_nattable_sz);
nat = nat_table[1][hv];
for (; nat; nat = nat->nat_hnext[1]) {
nflags = nat->nat_flags;
if ((!ifp || ifp == nat->nat_ifp) &&
nat->nat_oip.s_addr == src.s_addr &&
- nat->nat_outip.s_addr == mapdst.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 == mapdport) ||
- (nflags & FI_W_SPORT)))))
+ ((nat->nat_outport == dport) || (nflags & FI_W_SPORT)))))
return nat;
}
- return NULL;
+ if (!nat_wilds || !(flags & IPN_TCPUDP))
+ return NULL;
+ RWLOCK_EXIT(&ipf_nat);
+ hv = NAT_HASH_FN(dst, 0, ipf_nattable_sz);
+ WRITE_ENTER(&ipf_nat);
+ nat = nat_table[1][hv];
+ for (; nat; nat = nat->nat_hnext[1]) {
+ 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 ||
+ nat->nat_outip.s_addr != dst)
+ continue;
+ if (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) &&
+ ((nat->nat_outport == dport) || (nflags & FI_W_SPORT))) {
+ hv = NAT_HASH_FN(dst, dport, ipf_nattable_sz);
+ nat_tabmove(nat, hv);
+ break;
+ }
+ }
+ MUTEX_DOWNGRADE(&ipf_nat);
+ return nat;
+}
+
+
+static void nat_tabmove(nat, hv)
+nat_t *nat;
+u_int hv;
+{
+ nat_t **natp;
+
+ /*
+ * 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];
+
+ if (nat->nat_hnext[1])
+ nat->nat_hnext[0]->nat_phnext[1] = nat->nat_phnext[1];
+ *nat->nat_phnext[1] = nat->nat_hnext[1];
+
+ natp = &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;
+
+ /*
+ * Add into the NAT table in the new position
+ */
+ natp = &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;
}
@@ -1707,19 +1997,21 @@ u_32_t ports;
register u_short sport, dport;
register nat_t *nat;
register int nflags;
+ u_32_t srcip;
u_int hv;
sport = ports & 0xffff;
dport = ports >> 16;
flags &= IPN_TCPUDP;
+ srcip = src.s_addr;
- hv = NAT_HASH_FN(src.s_addr, sport, ipf_nattable_sz);
+ hv = NAT_HASH_FN(srcip, sport, ipf_nattable_sz);
nat = nat_table[0][hv];
for (; nat; nat = nat->nat_hnext[0]) {
nflags = nat->nat_flags;
if ((!ifp || ifp == nat->nat_ifp) &&
- nat->nat_inip.s_addr == src.s_addr &&
+ nat->nat_inip.s_addr == srcip &&
nat->nat_oip.s_addr == dst.s_addr &&
(((p == 0) && (flags == (nat->nat_flags & IPN_TCPUDP)))
|| (p == nat->nat_p)) && (!flags ||
@@ -1727,7 +2019,32 @@ u_32_t ports;
(nat->nat_oport == dport || nflags & FI_W_DPORT))))
return nat;
}
- return NULL;
+ if (!nat_wilds || !(flags & IPN_TCPUDP))
+ return NULL;
+ RWLOCK_EXIT(&ipf_nat);
+ hv = NAT_HASH_FN(srcip, 0, ipf_nattable_sz);
+ WRITE_ENTER(&ipf_nat);
+ nat = nat_table[0][hv];
+ for (; nat; nat = nat->nat_hnext[0]) {
+ 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) ||
+ (nat->nat_oip.s_addr != dst.s_addr))
+ continue;
+ if (((nat->nat_inport == sport) || (nflags & FI_W_DPORT)) &&
+ ((nat->nat_oport == dport) || (nflags & FI_W_SPORT))) {
+ hv = NAT_HASH_FN(srcip, sport, ipf_nattable_sz);
+ nat_tabmove(nat, hv);
+ break;
+ }
+ }
+ MUTEX_DOWNGRADE(&ipf_nat);
+ return nat;
}
@@ -1863,6 +2180,7 @@ fr_info_t *fin;
nat->nat_outport = sport;
nat->nat_flags &= ~(FI_W_DPORT|FI_W_SPORT);
nflags = nat->nat_flags;
+ nat_wilds--;
}
} else {
RWLOCK_EXIT(&ipf_nat);
@@ -1943,16 +2261,16 @@ maskloop:
CALC_SUMD(s1, s2, sumd);
if (nat->nat_dir == NAT_OUTBOUND)
- fix_incksum(&ip->ip_sum, sumd, 0);
+ fix_incksum(&ip->ip_sum, sumd);
else
- fix_outcksum(&ip->ip_sum, sumd, 0);
+ fix_outcksum(&ip->ip_sum, sumd);
}
#if SOLARIS || defined(__sgi)
else {
if (nat->nat_dir == NAT_OUTBOUND)
- fix_outcksum(&ip->ip_sum, nat->nat_ipsumd, 0);
+ fix_outcksum(&ip->ip_sum, nat->nat_ipsumd);
else
- fix_incksum(&ip->ip_sum, nat->nat_ipsumd, 0);
+ fix_incksum(&ip->ip_sum, nat->nat_ipsumd);
}
#endif
ip->ip_src = nat->nat_outip;
@@ -1996,11 +2314,9 @@ maskloop:
if (csump) {
if (nat->nat_dir == NAT_OUTBOUND)
- fix_outcksum(csump, nat->nat_sumd[1],
- ip->ip_len);
+ fix_outcksum(csump, nat->nat_sumd[1]);
else
- fix_incksum(csump, nat->nat_sumd[1],
- ip->ip_len);
+ fix_incksum(csump, nat->nat_sumd[1]);
}
}
@@ -2077,6 +2393,7 @@ fr_info_t *fin;
nat->nat_outport = dport;
nat->nat_flags &= ~(FI_W_SPORT|FI_W_DPORT);
nflags = nat->nat_flags;
+ nat_wilds--;
}
} else {
RWLOCK_EXIT(&ipf_nat);
@@ -2154,9 +2471,9 @@ maskloop:
*/
#if SOLARIS || defined(__sgi)
if (nat->nat_dir == NAT_OUTBOUND)
- fix_incksum(&ip->ip_sum, nat->nat_ipsumd, 0);
+ fix_incksum(&ip->ip_sum, nat->nat_ipsumd);
else
- fix_outcksum(&ip->ip_sum, nat->nat_ipsumd, 0);
+ fix_outcksum(&ip->ip_sum, nat->nat_ipsumd);
#endif
if (!(ip->ip_off & IP_OFFMASK) &&
!(fin->fin_fi.fi_fl & FI_SHORT)) {
@@ -2197,11 +2514,9 @@ maskloop:
if (csump) {
if (nat->nat_dir == NAT_OUTBOUND)
- fix_incksum(csump, nat->nat_sumd[0],
- 0);
+ fix_incksum(csump, nat->nat_sumd[0]);
else
- fix_outcksum(csump, nat->nat_sumd[0],
- 0);
+ fix_outcksum(csump, nat->nat_sumd[0]);
}
}
ATOMIC_INCL(nat_stats.ns_mapped[0]);
diff --git a/sys/contrib/ipfilter/netinet/ip_nat.h b/sys/contrib/ipfilter/netinet/ip_nat.h
index b5d53e8..4b24d81 100644
--- a/sys/contrib/ipfilter/netinet/ip_nat.h
+++ b/sys/contrib/ipfilter/netinet/ip_nat.h
@@ -82,7 +82,7 @@ typedef struct nat {
struct hostmap *nat_hm;
struct nat *nat_next;
struct nat *nat_hnext[2];
- struct nat **nat_hstart[2];
+ struct nat **nat_phnext[2];
void *nat_ifp;
int nat_dir;
char nat_ifname[IFNAMSIZ];
@@ -142,6 +142,11 @@ typedef struct ipnat {
#define NAT_REDIRECT 0x02
#define NAT_BIMAP (NAT_MAP|NAT_REDIRECT)
#define NAT_MAPBLK 0x04
+/* 0x100 reserved for FI_W_SPORT */
+/* 0x200 reserved for FI_W_DPORT */
+/* 0x400 reserved for FI_W_SADDR */
+/* 0x800 reserved for FI_W_DADDR */
+/* 0x1000 reserved for FI_W_NEWFR */
#define MAPBLK_MINPORT 1024 /* don't use reserved ports for src port */
#define USABLE_PORTS (65536 - MAPBLK_MINPORT)
@@ -294,7 +299,8 @@ extern int ip_natout __P((ip_t *, fr_info_t *));
extern int ip_natin __P((ip_t *, fr_info_t *));
extern void ip_natunload __P((void)), ip_natexpire __P((void));
extern void nat_log __P((struct nat *, u_int));
-extern void fix_incksum __P((u_short *, u_32_t, int));
-extern void fix_outcksum __P((u_short *, u_32_t, int));
+extern void fix_incksum __P((u_short *, u_32_t));
+extern void fix_outcksum __P((u_short *, u_32_t));
+extern void fix_datacksum __P((u_short *, u_32_t));
#endif /* __IP_NAT_H__ */
diff --git a/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c b/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c
index fd62033..ee527a3 100644
--- a/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c
+++ b/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c
@@ -171,8 +171,8 @@ nat_t *nat;
tcphdr_t *tcp, tcph, *tcp2 = &tcph;
raudio_t *rap = aps->aps_data;
struct in_addr swa, swb;
- u_int a1, a2, a3, a4;
int off, dlen, slen;
+ int a1, a2, a3, a4;
u_short sp, dp;
fr_info_t fi;
tcp_seq seq;
diff --git a/sys/contrib/ipfilter/netinet/ip_state.c b/sys/contrib/ipfilter/netinet/ip_state.c
index 01fc030..ec0fb7c 100644
--- a/sys/contrib/ipfilter/netinet/ip_state.c
+++ b/sys/contrib/ipfilter/netinet/ip_state.c
@@ -106,6 +106,7 @@ static const char rcsid[] = "@(#)$FreeBSD$";
static ipstate_t **ips_table = NULL;
static ipstate_t *ips_list = NULL;
static int ips_num = 0;
+static int ips_wild = 0;
static ips_stat_t ips_stats;
#if (SOLARIS || defined(__sgi)) && defined(_KERNEL)
extern KRWLOCK_T ipf_state, ipf_mutex;
@@ -123,6 +124,7 @@ static int fr_state_flush __P((int));
static ips_stat_t *fr_statetstats __P((void));
static void fr_delstate __P((ipstate_t *));
static int fr_state_remove __P((caddr_t));
+static void fr_ipsmove __P((ipstate_t **, ipstate_t *, u_int));
int fr_stputent __P((caddr_t));
int fr_stgetent __P((caddr_t));
void fr_stinsert __P((ipstate_t *));
@@ -135,7 +137,8 @@ u_long fr_tcpidletimeout = FIVE_DAYS,
fr_tcpclosewait = 2 * TCP_MSL,
fr_tcplastack = 2 * TCP_MSL,
fr_tcptimeout = 2 * TCP_MSL,
- fr_tcpclosed = 1,
+ fr_tcpclosed = 120,
+ fr_tcphalfclosed = 2 * 2 * 3600, /* 2 hours */
fr_udptimeout = 240,
fr_icmptimeout = 120;
int fr_statemax = IPSTATE_MAX,
@@ -240,9 +243,12 @@ caddr_t data;
for (sp = ips_list; sp; sp = sp->is_next)
if ((sp->is_p == st.is_p) && (sp->is_v == st.is_v) &&
- !bcmp(&sp->is_src, &st.is_src, sizeof(st.is_src)) &&
- !bcmp(&sp->is_dst, &st.is_src, sizeof(st.is_dst)) &&
- !bcmp(&sp->is_ps, &st.is_ps, sizeof(st.is_ps))) {
+ !bcmp((char *)&sp->is_src, (char *)&st.is_src,
+ sizeof(st.is_src)) &&
+ !bcmp((char *)&sp->is_dst, (char *)&st.is_src,
+ sizeof(st.is_dst)) &&
+ !bcmp((char *)&sp->is_ps, (char *)&st.is_ps,
+ sizeof(st.is_ps))) {
WRITE_ENTER(&ipf_state);
#ifdef IPFILTER_LOG
ipstate_log(sp, ISL_REMOVE);
@@ -590,8 +596,8 @@ u_int flags;
hv += tcp->th_dport;
hv += tcp->th_sport;
}
- is->is_send = ntohl(tcp->th_seq) + ip->ip_len -
- fin->fin_hlen - (tcp->th_off << 2) +
+ is->is_send = ntohl(tcp->th_seq) + fin->fin_dlen -
+ (tcp->th_off << 2) +
((tcp->th_flags & TH_SYN) ? 1 : 0) +
((tcp->th_flags & TH_FIN) ? 1 : 0);
is->is_maxsend = is->is_send;
@@ -660,6 +666,8 @@ u_int flags;
is->is_flags = fin->fin_fi.fi_fl & FI_CMP;
is->is_flags |= FI_CMP << 4;
is->is_flags |= flags & (FI_WILDP|FI_WILDA);
+ if (flags & (FI_WILDP|FI_WILDA))
+ ips_wild++;
is->is_ifp[1 - out] = NULL;
is->is_ifp[out] = fin->fin_ifp;
#ifdef _KERNEL
@@ -718,6 +726,7 @@ tcphdr_t *tcp;
((tcp->th_flags & TH_SYN) ? 1 : 0) +
((tcp->th_flags & TH_FIN) ? 1 : 0);
+ MUTEX_ENTER(&is->is_lock);
if (fdata->td_end == 0) {
/*
* Must be a (outgoing) SYN-ACK in reply to a SYN.
@@ -783,12 +792,11 @@ tcphdr_t *tcp;
/*
* Nearing end of connection, start timeout.
*/
- MUTEX_ENTER(&is->is_lock);
/* source ? 0 : 1 -> !source */
fr_tcp_age(&is->is_age, is->is_state, fin, !source);
- MUTEX_EXIT(&is->is_lock);
ret = 1;
}
+ MUTEX_EXIT(&is->is_lock);
return ret;
}
@@ -892,6 +900,7 @@ tcphdr_t *tcp;
is->is_maxdend = is->is_dend + 1;
}
is->is_flags &= ~(FI_W_SPORT|FI_W_DPORT);
+ ips_wild--;
}
ret = -1;
@@ -983,7 +992,7 @@ fr_info_t *fin;
* Only a basic IP header (no options) should be with
* an ICMP error header.
*/
- if (((ip->ip_v != 4) && (ip->ip_hl != 5)) ||
+ if (((ip->ip_v != 4) || (ip->ip_hl != 5)) ||
(fin->fin_plen < ICMPERR_MINPKTLEN))
return NULL;
ic = (struct icmp *)fin->fin_dp;
@@ -1037,8 +1046,8 @@ fr_info_t *fin;
* the IP6EQ and IP6NEQ macros produce the wrong results because
* of the 'junk' in the unused part of the union
*/
- bzero(&src, sizeof(src));
- bzero(&dst, sizeof(dst));
+ bzero((char *)&src, sizeof(src));
+ bzero((char *)&dst, sizeof(dst));
if (oip->ip_p == IPPROTO_ICMP) {
icmp = (icmphdr_t *)((char *)oip + (oip->ip_hl << 2));
@@ -1158,6 +1167,38 @@ fr_info_t *fin;
return NULL;
}
+
+static void fr_ipsmove(isp, is, hv)
+ipstate_t **isp, *is;
+u_int hv;
+{
+ u_int hvm;
+
+ hvm = is->is_hv;
+ /*
+ * Remove the hash from the old location...
+ */
+ if (is->is_hnext)
+ is->is_hnext->is_phnext = isp;
+ *isp = is->is_hnext;
+ if (ips_table[hvm] == NULL)
+ ips_stats.iss_inuse--;
+
+ /*
+ * ...and put the hash in the new one.
+ */
+ hvm = hv % fr_statesize;
+ isp = &ips_table[hvm];
+ if (*isp)
+ (*isp)->is_phnext = &is->is_hnext;
+ else
+ ips_stats.iss_inuse++;
+ is->is_phnext = isp;
+ is->is_hnext = *isp;
+ *isp = is;
+}
+
+
/*
* Check if a packet has a registered state.
*/
@@ -1240,7 +1281,7 @@ fr_info_t *fin;
break;
case IPPROTO_TCP :
{
- register u_short dport = tcp->th_dport, sport = tcp->th_sport;
+ register u_short dport, sport;
register int i;
i = tcp->th_flags;
@@ -1250,57 +1291,42 @@ fr_info_t *fin;
if ((i & TH_RST) &&
((i & (TH_FIN|TH_SYN|TH_RST)) != TH_RST))
break;
+ case IPPROTO_UDP :
+ dport = tcp->th_dport;
+ sport = tcp->th_sport;
tryagain = 0;
-retry_tcp:
- hvm = hv % fr_statesize;
- WRITE_ENTER(&ipf_state);
- for (isp = &ips_table[hvm]; (is = *isp);
- isp = &is->is_hnext)
-
-
- if ((is->is_p == pr) && (is->is_v == v) &&
- fr_matchsrcdst(is, src, dst, fin, tcp)) {
- if (fr_tcpstate(is, fin, ip, tcp))
- break;
- is = NULL;
- break;
- }
- if (is != NULL)
- break;
- RWLOCK_EXIT(&ipf_state);
hv += dport;
hv += sport;
- if (tryagain == 0) {
- tryagain = 1;
- goto retry_tcp;
- }
- break;
- }
- case IPPROTO_UDP :
- {
- register u_short dport = tcp->th_dport, sport = tcp->th_sport;
-
- tryagain = 0;
-retry_udp:
- hvm = hv % fr_statesize;
- /*
- * Nothing else to match on but ports. and IP#'s
- */
READ_ENTER(&ipf_state);
- for (is = ips_table[hvm]; is; is = is->is_hnext)
+retry_tcpudp:
+ hvm = hv % fr_statesize;
+ for (isp = &ips_table[hvm]; (is = *isp); isp = &is->is_hnext)
if ((is->is_p == pr) && (is->is_v == v) &&
fr_matchsrcdst(is, src, dst, fin, tcp)) {
- is->is_age = fr_udptimeout;
+ if ((pr == IPPROTO_TCP)) {
+ if (!fr_tcpstate(is, fin, ip, tcp)) {
+ continue;
+ }
+ }
break;
}
- if (is != NULL)
+ if (is != NULL) {
+ if (tryagain &&
+ !(is->is_flags & (FI_WILDP|FI_WILDA))) {
+ hv += dport;
+ hv += sport;
+ fr_ipsmove(isp, is, hv);
+ MUTEX_DOWNGRADE(&ipf_state);
+ }
break;
+ }
RWLOCK_EXIT(&ipf_state);
- hv += dport;
- hv += sport;
- if (tryagain == 0) {
+ if (!tryagain && ips_wild) {
+ hv -= dport;
+ hv -= sport;
tryagain = 1;
- goto retry_udp;
+ WRITE_ENTER(&ipf_state);
+ goto retry_tcpudp;
}
break;
}
@@ -1357,6 +1383,8 @@ ipstate_t *is;
{
frentry_t *fr;
+ if (is->is_flags & (FI_WILDP|FI_WILDA))
+ ips_wild--;
if (is->is_next)
is->is_next->is_pnext = is->is_pnext;
*is->is_pnext = is->is_next;
@@ -1566,7 +1594,7 @@ int dir;
* SYN_RECEIVED -> FIN_WAIT_1
*/
state[dir] = TCPS_FIN_WAIT_1;
- *age = fr_tcpidletimeout; /* or fr_tcptimeout? */
+ *age = fr_tcpidletimeout;
}
break;
@@ -1578,7 +1606,7 @@ int dir;
* ESTABLISHED -> FIN_WAIT_1
*/
state[dir] = TCPS_FIN_WAIT_1;
- *age = fr_tcpidletimeout;
+ *age = fr_tcphalfclosed;
} else if (flags & TH_ACK) {
/* an ACK, should we exclude other flags here? */
if (ostate == TCPS_FIN_WAIT_1) {
@@ -1590,7 +1618,7 @@ int dir;
* a half-closed connection
*/
state[dir] = TCPS_CLOSE_WAIT;
- *age = fr_tcpidletimeout;
+ *age = fr_tcphalfclosed;
} else if (ostate < TCPS_CLOSE_WAIT)
/*
* Still a fully established connection,
@@ -1614,7 +1642,7 @@ int dir;
* closed already and we did not close our side yet;
* reset timeout
*/
- *age = fr_tcpidletimeout;
+ *age = fr_tcphalfclosed;
}
break;
@@ -1638,7 +1666,7 @@ int dir;
* other side is still active (ESTABLISHED/CLOSE_WAIT);
* continue with this half-closed connection
*/
- *age = fr_tcpidletimeout;
+ *age = fr_tcphalfclosed;
break;
case TCPS_CLOSING: /* 7 */
diff --git a/sys/contrib/ipfilter/netinet/ip_state.h b/sys/contrib/ipfilter/netinet/ip_state.h
index 2374068..765709c 100644
--- a/sys/contrib/ipfilter/netinet/ip_state.h
+++ b/sys/contrib/ipfilter/netinet/ip_state.h
@@ -174,6 +174,7 @@ extern u_long fr_tcpclosewait;
extern u_long fr_tcplastack;
extern u_long fr_tcptimeout;
extern u_long fr_tcpclosed;
+extern u_long fr_tcphalfclosed;
extern u_long fr_udptimeout;
extern u_long fr_icmptimeout;
extern int fr_state_lock;
diff --git a/sys/contrib/ipfilter/netinet/ipl.h b/sys/contrib/ipfilter/netinet/ipl.h
index edb4dc9..67cbf31 100644
--- a/sys/contrib/ipfilter/netinet/ipl.h
+++ b/sys/contrib/ipfilter/netinet/ipl.h
@@ -12,6 +12,6 @@
#ifndef __IPL_H__
#define __IPL_H__
-#define IPL_VERSION "IP Filter: v3.4.9"
+#define IPL_VERSION "IP Filter: v3.4.12"
#endif
diff --git a/sys/contrib/ipfilter/netinet/mlfk_ipl.c b/sys/contrib/ipfilter/netinet/mlfk_ipl.c
index e92360d..1be8916 100644
--- a/sys/contrib/ipfilter/netinet/mlfk_ipl.c
+++ b/sys/contrib/ipfilter/netinet/mlfk_ipl.c
@@ -65,6 +65,8 @@ SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RW,
&fr_tcptimeout, 0, "");
SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RW,
&fr_tcpclosed, 0, "");
+SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RW,
+ &fr_tcphalfclosed, 0, "");
SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RW,
&fr_udptimeout, 0, "");
SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RW,
diff --git a/sys/netinet/fil.c b/sys/netinet/fil.c
index 1fb4b6c..12993ca 100644
--- a/sys/netinet/fil.c
+++ b/sys/netinet/fil.c
@@ -277,6 +277,16 @@ fr_info_t *fin;
int minicmpsz = sizeof(struct icmp);
icmphdr_t *icmp;
+ if (fin->fin_dlen > 1)
+ fin->fin_data[0] = *(u_short *)tcp;
+
+ if ((!(plen >= hlen + minicmpsz) && !off) ||
+ (off && off < sizeof(struct icmp))) {
+ fi->fi_fl |= FI_SHORT;
+ if (fin->fin_dlen < 2)
+ break;
+ }
+
icmp = (icmphdr_t *)tcp;
if (!off && (icmp->icmp_type == ICMP_ECHOREPLY ||
@@ -294,11 +304,6 @@ fr_info_t *fin;
icmp->icmp_type == ICMP_MASKREPLY))
minicmpsz = 12;
- if ((!(plen >= hlen + minicmpsz) && !off) ||
- (off && off < sizeof(struct icmp)))
- fi->fi_fl |= FI_SHORT;
- if (fin->fin_dlen > 1)
- fin->fin_data[0] = *(u_short *)tcp;
break;
}
case IPPROTO_TCP :
@@ -743,6 +748,7 @@ int out;
#ifdef _KERNEL
mb_t *mc = NULL;
+ int p, len;
# if !defined(__SVR4) && !defined(__svr4__)
# ifdef __sgi
char hbuf[(0xf << 2) + sizeof(struct icmp) + sizeof(ip_t) + 8];
@@ -767,13 +773,26 @@ int out;
}
# endif /* CSUM_DELAY_DATA */
+# ifdef USE_INET6
+ if (v == 6) {
+ len = ntohs(((ip6_t*)ip)->ip6_plen);
+ p = ((ip6_t *)ip)->ip6_nxt;
+ } else
+# endif
+ {
+ p = ip->ip_p;
+ len = ip->ip_len;
+ }
- if ((ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP ||
- ip->ip_p == IPPROTO_ICMP)) {
+ if ((p == IPPROTO_TCP || p == IPPROTO_UDP || p == IPPROTO_ICMP
+# ifdef USE_INET6
+ || (v == 6 && p == IPPROTO_ICMPV6)
+# endif
+ )) {
int plen = 0;
- if ((ip->ip_off & IP_OFFMASK) == 0)
- switch(ip->ip_p)
+ if ((v == 6) || (ip->ip_off & IP_OFFMASK) == 0)
+ switch(p)
{
case IPPROTO_TCP:
plen = sizeof(tcphdr_t);
@@ -783,10 +802,13 @@ int out;
break;
/* 96 - enough for complete ICMP error IP header */
case IPPROTO_ICMP:
+# ifdef USE_INET6
+ case IPPROTO_ICMPV6 :
+# endif
plen = ICMPERR_MAXPKTLEN - sizeof(ip_t);
break;
}
- up = MIN(hlen + plen, ip->ip_len);
+ up = MIN(hlen + plen, len);
if (up > m->m_len) {
# ifdef __sgi
@@ -835,8 +857,8 @@ int out;
#endif
changed = 0;
- fin->fin_v = v;
fin->fin_ifp = ifp;
+ fin->fin_v = v;
fin->fin_out = out;
fin->fin_mp = mp;
fr_makefrip(hlen, ip, fin);
@@ -1383,7 +1405,7 @@ nodata:
* SUCH DAMAGE.
*
* @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94
- * $Id: fil.c,v 2.35.2.20 2000/08/13 04:15:43 darrenr Exp $
+ * $Id: fil.c,v 2.35.2.26 2000/10/24 11:58:17 darrenr Exp $
*/
/*
* Copy data from an mbuf chain starting "off" bytes from the beginning,
@@ -1862,7 +1884,7 @@ size_t c;
int err;
#if SOLARIS
- if (copyin(a, &ca, sizeof(ca)))
+ if (copyin(a, (char *)&ca, sizeof(ca)))
return EFAULT;
#else
bcopy(a, &ca, sizeof(ca));
@@ -1882,7 +1904,7 @@ size_t c;
int err;
#if SOLARIS
- if (copyin(b, &ca, sizeof(ca)))
+ if (copyin(b, (char *)&ca, sizeof(ca)))
return EFAULT;
#else
bcopy(b, &ca, sizeof(ca));
@@ -1976,6 +1998,15 @@ friostat_t *fiop;
fiop->f_acctin6[1] = ipacct6[0][1];
fiop->f_acctout6[0] = ipacct6[1][0];
fiop->f_acctout6[1] = ipacct6[1][1];
+#else
+ fiop->f_fin6[0] = NULL;
+ fiop->f_fin6[1] = NULL;
+ fiop->f_fout6[0] = NULL;
+ fiop->f_fout6[1] = NULL;
+ fiop->f_acctin6[0] = NULL;
+ fiop->f_acctin6[1] = NULL;
+ fiop->f_acctout6[0] = NULL;
+ fiop->f_acctout6[1] = NULL;
#endif
fiop->f_active = fr_active;
fiop->f_froute[0] = ipl_frouteok[0];
diff --git a/sys/netinet/ip_auth.h b/sys/netinet/ip_auth.h
index 8be860c..2851c3d 100644
--- a/sys/netinet/ip_auth.h
+++ b/sys/netinet/ip_auth.h
@@ -47,8 +47,6 @@ typedef struct fr_authstat {
extern frentry_t *ipauth;
extern struct fr_authstat fr_authstats;
extern int fr_defaultauthage;
-extern int fr_authstart;
-extern int fr_authend;
extern int fr_authsize;
extern int fr_authused;
extern int fr_auth_lock;
diff --git a/sys/netinet/ip_compat.h b/sys/netinet/ip_compat.h
index 1c3e245..d313952 100644
--- a/sys/netinet/ip_compat.h
+++ b/sys/netinet/ip_compat.h
@@ -264,6 +264,12 @@ union i6addr {
#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL))
+# ifdef IPFILTER_LKM
+# include <osreldate.h>
+# define ACTUALLY_LKM_NOT_KERNEL
+# else
+# include <sys/osreldate.h>
+# endif
# if __FreeBSD__ < 3
# include <machine/spl.h>
# else
@@ -289,6 +295,19 @@ union i6addr {
# define ATOMIC_DEC32 ATOMIC_DEC
# define ATOMIC_DEC16 ATOMIC_DEC
#endif
+#ifdef __sgi
+# define hz HZ
+# include <sys/ksynch.h>
+# define IPF_LOCK_PL plhi
+# include <sys/sema.h>
+#undef kmutex_t
+typedef struct {
+ lock_t *l;
+ int pl;
+} kmutex_t;
+# undef MUTEX_INIT
+# undef MUTEX_DESTROY
+#endif
#ifdef KERNEL
# if SOLARIS
# if SOLARIS2 >= 6
@@ -338,8 +357,8 @@ union i6addr {
# define MUTEX_DESTROY(x) mutex_destroy(x)
# define MUTEX_EXIT(x) mutex_exit(x)
# define MTOD(m,t) (t)((m)->b_rptr)
-# define IRCOPY(a,b,c) copyin((a), (b), (c))
-# define IWCOPY(a,b,c) copyout((a), (b), (c))
+# define IRCOPY(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c))
+# define IWCOPY(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c))
# define IRCOPYPTR ircopyptr
# define IWCOPYPTR iwcopyptr
# define FREE_MB_T(m) freemsg(m)
@@ -384,15 +403,6 @@ extern ill_t *get_unit __P((char *, int));
# define IFNAME(x) ((ill_t *)x)->ill_name
# else /* SOLARIS */
# if defined(__sgi)
-# define hz HZ
-# include <sys/ksynch.h>
-# define IPF_LOCK_PL plhi
-# include <sys/sema.h>
-#undef kmutex_t
-typedef struct {
- lock_t *l;
- int pl;
-} kmutex_t;
# define ATOMIC_INC(x) { MUTEX_ENTER(&ipf_rw); \
(x)++; MUTEX_EXIT(&ipf_rw); }
# define ATOMIC_DEC(x) { MUTEX_ENTER(&ipf_rw); \
@@ -405,8 +415,8 @@ typedef struct {
# define MUTEX_DOWNGRADE(x) ;
# define RWLOCK_EXIT(x) MUTEX_EXIT(x)
# define MUTEX_EXIT(x) UNLOCK((x)->l, (x)->pl);
-# define MUTEX_INIT(x,y,z) (x).l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP)
-# define MUTEX_DESTROY(x) LOCK_DEALLOC((x).l)
+# define MUTEX_INIT(x,y,z) (x)->l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP)
+# define MUTEX_DESTROY(x) LOCK_DEALLOC((x)->l)
# else /* __sgi */
# define ATOMIC_INC(x) (x)++
# define ATOMIC_DEC(x) (x)--
diff --git a/sys/netinet/ip_fil.c b/sys/netinet/ip_fil.c
index 27aca2f..797e599 100644
--- a/sys/netinet/ip_fil.c
+++ b/sys/netinet/ip_fil.c
@@ -173,6 +173,9 @@ struct callout_handle ipfr_slowtimer_ch;
# include <sys/callout.h>
struct callout ipfr_slowtimer_ch;
#endif
+#if defined(__sgi) && defined(_KERNEL)
+toid_t ipfr_slowtimer_ch;
+#endif
#if (_BSDI_VERSION >= 199510) && defined(_KERNEL)
# include <sys/device.h>
@@ -322,7 +325,7 @@ pfil_error:
callout_init(&ipfr_slowtimer_ch);
callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL);
# else
-# if (__FreeBSD_version >= 300000) && defined(_KERNEL)
+# if (__FreeBSD_version >= 300000) || defined(__sgi)
ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2);
# else
timeout(ipfr_slowtimer, NULL, hz/2);
@@ -353,7 +356,7 @@ int ipldetach()
untimeout(ipfr_slowtimer, NULL, ipfr_slowtimer_ch);
# else
# ifdef __sgi
- untimeout(ipfr_slowtimer);
+ untimeout(ipfr_slowtimer_ch);
# else
untimeout(ipfr_slowtimer, NULL);
# endif
@@ -980,8 +983,10 @@ fr_info_t *fin;
if (m == NULL)
return -1;
- if (tcp->th_flags & TH_SYN)
- tlen = 1;
+ tlen = oip->ip_len - fin->fin_hlen - (tcp->th_off << 2) +
+ ((tcp->th_flags & TH_SYN) ? 1 : 0) +
+ ((tcp->th_flags & TH_FIN) ? 1 : 0);
+
#ifdef USE_INET6
hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t);
#else
@@ -1002,11 +1007,16 @@ fr_info_t *fin;
tcp2->th_sport = tcp->th_dport;
tcp2->th_dport = tcp->th_sport;
- tcp2->th_ack = ntohl(tcp->th_seq);
- tcp2->th_ack += tlen;
- tcp2->th_ack = htonl(tcp2->th_ack);
+ if (tcp->th_flags & TH_ACK) {
+ tcp2->th_seq = tcp->th_ack;
+ tcp2->th_flags = TH_RST;
+ } else {
+ tcp2->th_ack = ntohl(tcp->th_seq);
+ tcp2->th_ack += tlen;
+ tcp2->th_ack = htonl(tcp2->th_ack);
+ tcp2->th_flags = TH_RST|TH_ACK;
+ }
tcp2->th_off = sizeof(*tcp2) >> 2;
- tcp2->th_flags = TH_RST|TH_ACK;
# ifdef USE_INET6
if (fin->fin_v == 6) {
ip6->ip6_plen = htons(sizeof(struct tcphdr));
@@ -1148,7 +1158,12 @@ int dst;
m_freem(m);
return ENOBUFS;
}
+# ifdef M_TRAILINGSPACE
+ m->m_len = 0;
+ avail = M_TRAILINGSPACE(m);
+# else
avail = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN;
+# endif
xtra = MIN(ntohs(oip6->ip6_plen) + sizeof(ip6_t),
avail - hlen - sizeof(*icmp) - max_linkhdr);
if (dst == 0) {
@@ -1182,6 +1197,12 @@ int dst;
icmp->icmp_type = type;
icmp->icmp_code = fin->fin_icode;
icmp->icmp_cksum = 0;
+#ifdef icmp_nextmtu
+ if (type == ICMP_UNREACH &&
+ fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp)
+ icmp->icmp_nextmtu = htons(((struct ifnet *) ifp)->if_mtu);
+#endif
+
if (avail) {
bcopy((char *)oip, (char *)&icmp->icmp_ip, MIN(ohlen, avail));
avail -= MIN(ohlen, avail);
diff --git a/sys/netinet/ip_frag.c b/sys/netinet/ip_frag.c
index 8d2bbc5..2a10988 100644
--- a/sys/netinet/ip_frag.c
+++ b/sys/netinet/ip_frag.c
@@ -215,7 +215,7 @@ u_int pass;
ipfr_t *ipf;
if ((ip->ip_v != 4) || (fr_frag_lock))
- return NULL;
+ return -1;
WRITE_ENTER(&ipf_frag);
ipf = ipfr_new(ip, fin, pass, ipfr_heads);
RWLOCK_EXIT(&ipf_frag);
@@ -232,7 +232,7 @@ nat_t *nat;
ipfr_t *ipf;
if ((ip->ip_v != 4) || (fr_frag_lock))
- return NULL;
+ return -1;
WRITE_ENTER(&ipf_natfrag);
ipf = ipfr_new(ip, fin, pass, ipfr_nattab);
if (ipf != NULL) {
@@ -329,13 +329,16 @@ fr_info_t *fin;
ipf = ipfr_lookup(ip, fin, ipfr_nattab);
if (ipf != NULL) {
nat = ipf->ipfr_data;
- /*
- * This is the last fragment for this packet.
- */
- if ((ipf->ipfr_ttl == 1) && (nat != NULL)) {
- nat->nat_data = NULL;
- ipf->ipfr_data = NULL;
- }
+ if (nat->nat_ifp == fin->fin_ifp) {
+ /*
+ * This is the last fragment for this packet.
+ */
+ if ((ipf->ipfr_ttl == 1) && (nat != NULL)) {
+ nat->nat_data = NULL;
+ ipf->ipfr_data = NULL;
+ }
+ } else
+ nat = NULL;
} else
nat = NULL;
RWLOCK_EXIT(&ipf_natfrag);
diff --git a/sys/netinet/ip_frag.h b/sys/netinet/ip_frag.h
index 4fb3597..48144af 100644
--- a/sys/netinet/ip_frag.h
+++ b/sys/netinet/ip_frag.h
@@ -61,6 +61,6 @@ extern void ipfr_slowtimer __P((void *));
# endif
#else
extern int ipfr_slowtimer __P((void));
-#endif
+#endif /* (BSD >= 199306) || SOLARIS */
#endif /* __IP_FIL_H__ */
diff --git a/sys/netinet/ip_ftp_pxy.c b/sys/netinet/ip_ftp_pxy.c
index ce06851..c68361a 100644
--- a/sys/netinet/ip_ftp_pxy.c
+++ b/sys/netinet/ip_ftp_pxy.c
@@ -145,6 +145,7 @@ int dlen;
} else
return 0;
a5 >>= 8;
+ a5 &= 0xff;
/*
* Calculate new address parts for PORT command
*/
@@ -213,7 +214,7 @@ int dlen;
sum2 -= sum1;
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
- fix_outcksum(&ip->ip_sum, sum2, 0);
+ fix_outcksum(&ip->ip_sum, sum2);
#endif
ip->ip_len += inc;
}
@@ -440,7 +441,7 @@ int dlen;
sum2 -= sum1;
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
- fix_outcksum(&ip->ip_sum, sum2, 0);
+ fix_outcksum(&ip->ip_sum, sum2);
#endif /* SOLARIS || defined(__sgi) */
ip->ip_len += inc;
}
@@ -669,15 +670,18 @@ int rv;
while ((rptr < wptr) && (*rptr != '\r'))
rptr++;
- if ((*rptr == '\r') && (rptr + 1 < wptr)) {
- if (*(rptr + 1) == '\n') {
- rptr += 2;
- f->ftps_junk = 0;
+ if (*rptr == '\r') {
+ if (rptr + 1 < wptr) {
+ if (*(rptr + 1) == '\n') {
+ rptr += 2;
+ f->ftps_junk = 0;
+ } else
+ rptr++;
} else
- rptr++;
+ break;
}
- f->ftps_rptr = rptr;
}
+ f->ftps_rptr = rptr;
if (rptr == wptr) {
rptr = wptr = f->ftps_buf;
@@ -761,5 +765,7 @@ char **ptr;
j += c - '0';
}
*ptr = s;
+ i &= 0xff;
+ j &= 0xff;
return (i << 8) | j;
}
diff --git a/sys/netinet/ip_nat.c b/sys/netinet/ip_nat.c
index 47c5f6a..ca3a27f 100644
--- a/sys/netinet/ip_nat.c
+++ b/sys/netinet/ip_nat.c
@@ -119,6 +119,7 @@ u_int ipf_nattable_sz = NAT_TABLE_SZ;
u_int ipf_natrules_sz = NAT_SIZE;
u_int ipf_rdrrules_sz = RDR_SIZE;
u_int ipf_hostmap_sz = HOSTMAP_SIZE;
+int nat_wilds = 0;
u_32_t nat_masks = 0;
u_32_t rdr_masks = 0;
ipnat_t **nat_rules = NULL;
@@ -144,6 +145,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_int));
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));
@@ -301,10 +303,9 @@ struct hostmap *hm;
}
-void fix_outcksum(sp, n , len)
+void fix_outcksum(sp, n)
u_short *sp;
u_32_t n;
-int len;
{
register u_short sumshort;
register u_32_t sum1;
@@ -327,10 +328,9 @@ int len;
}
-void fix_incksum(sp, n , len)
+void fix_incksum(sp, n)
u_short *sp;
u_32_t n;
-int len;
{
register u_short sumshort;
register u_32_t sum1;
@@ -358,6 +358,38 @@ int len;
/*
+ * fix_datacksum is used *only* for the adjustments of checksums in the data
+ * section of an IP packet.
+ *
+ * The only situation in which you need to do this is when NAT'ing an
+ * ICMP error message. Such a message, contains in its body the IP header
+ * of the original IP packet, that causes the error.
+ *
+ * You can't use fix_incksum or fix_outcksum in that case, because for the
+ * kernel the data section of the ICMP error is just data, and no special
+ * processing like hardware cksum or ntohs processing have been done by the
+ * kernel on the data section.
+ */
+void fix_datacksum(sp, n)
+u_short *sp;
+u_32_t n;
+{
+ register u_short sumshort;
+ register u_32_t sum1;
+
+ if (!n)
+ return;
+
+ sum1 = (~ntohs(*sp)) & 0xffff;
+ sum1 += (n);
+ sum1 = (sum1 >> 16) + (sum1 & 0xffff);
+ /* Again */
+ sum1 = (sum1 >> 16) + (sum1 & 0xffff);
+ sumshort = ~(u_short)sum1;
+ *(sp) = htons(sumshort);
+}
+
+/*
* How the NAT is organised and works.
*
* Inside (interface y) NAT Outside (interface x)
@@ -857,8 +889,8 @@ caddr_t data;
/*
* Initialize all these so that nat_delete() doesn't cause a crash.
*/
- nat->nat_hstart[0] = NULL;
- nat->nat_hstart[1] = NULL;
+ nat->nat_phnext[0] = NULL;
+ nat->nat_phnext[1] = NULL;
fr = nat->nat_fr;
nat->nat_fr = NULL;
aps = nat->nat_aps;
@@ -970,22 +1002,16 @@ junkput:
static void nat_delete(natd)
struct nat *natd;
{
- register struct nat **natp, *nat;
struct ipnat *ipn;
- for (natp = natd->nat_hstart[0]; natp && (nat = *natp);
- natp = &nat->nat_hnext[0])
- if (nat == natd) {
- *natp = nat->nat_hnext[0];
- break;
- }
-
- for (natp = natd->nat_hstart[1]; natp && (nat = *natp);
- natp = &nat->nat_hnext[1])
- if (nat == natd) {
- *natp = nat->nat_hnext[1];
- break;
- }
+ if (natd->nat_flags & FI_WILDP)
+ nat_wilds--;
+ if (natd->nat_hnext[0])
+ natd->nat_hnext[0]->nat_phnext[0] = natd->nat_phnext[0];
+ *natd->nat_phnext[0] = natd->nat_hnext[0];
+ 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_fr != NULL) {
ATOMIC_DEC32(natd->nat_fr->fr_ref);
@@ -1030,7 +1056,7 @@ static int nat_flushtable()
{
register nat_t *nat, **natp;
register int j = 0;
-
+
/*
* ALL NAT mappings deleted, so lets just make the deletions
* quicker.
@@ -1122,6 +1148,8 @@ int direction;
bzero((char *)nat, sizeof(*nat));
nat->nat_flags = flags;
+ if (flags & FI_WILDP)
+ nat_wilds++;
/*
* Search the current table for a match.
*/
@@ -1444,16 +1472,22 @@ nat_t *nat;
nat->nat_next = nat_instances;
nat_instances = nat;
+
hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport,
ipf_nattable_sz);
natp = &nat_table[0][hv];
- nat->nat_hstart[0] = natp;
+ if (*natp)
+ (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
+ nat->nat_phnext[0] = natp;
nat->nat_hnext[0] = *natp;
*natp = nat;
+
hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport,
ipf_nattable_sz);
natp = &nat_table[1][hv];
- nat->nat_hstart[1] = natp;
+ if (*natp)
+ (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
+ nat->nat_phnext[1] = natp;
nat->nat_hnext[1] = *natp;
*natp = nat;
@@ -1561,12 +1595,16 @@ int dir;
u_32_t sum1, sum2, sumd;
struct in_addr in;
icmphdr_t *icmp;
+ udphdr_t *udp;
nat_t *nat;
ip_t *oip;
int flags = 0;
if ((fin->fin_fi.fi_fl & FI_SHORT) || (ip->ip_off & IP_OFFMASK))
return NULL;
+ /*
+ * nat_icmplookup() will return NULL for `defective' packets.
+ */
if ((ip->ip_v != 4) || !(nat = nat_icmplookup(ip, fin, dir)))
return NULL;
*nflags = IPN_ICMPERR;
@@ -1576,16 +1614,33 @@ int dir;
flags = IPN_TCP;
else if (oip->ip_p == IPPROTO_UDP)
flags = IPN_UDP;
+ udp = (udphdr_t *)((((char *)oip) + (oip->ip_hl << 2)));
/*
* Need to adjust ICMP header to include the real IP#'s and
* port #'s. Only apply a checksum change relative to the
- * IP address change is it will be modified again in ip_natout
+ * IP address change as it will be modified again in ip_natout
* for both address and port. Two checksum changes are
* necessary for the two header address changes. Be careful
* to only modify the checksum once for the port # and twice
* for the IP#.
*/
+ /*
+ * Step 1
+ * Fix the IP addresses in the offending IP packet. You also need
+ * to adjust the IP header checksum of that offending IP packet
+ * and the ICMP checksum of the ICMP error message itself.
+ *
+ * Unfortunately, for UDP and TCP, the IP addresses are also contained
+ * in the pseudo header that is used to compute the UDP resp. TCP
+ * checksum. So, we must compensate that as well. Even worse, the
+ * change in the UDP and TCP checksums require yet another
+ * adjustment of the ICMP checksum of the ICMP error message.
+ *
+ * For the moment we forget about TCP, because that checksum is not
+ * in the first 8 bytes, so it will not be available in most cases.
+ */
+
if (nat->nat_dir == NAT_OUTBOUND) {
sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr));
in = nat->nat_inip;
@@ -1601,19 +1656,117 @@ int dir;
CALC_SUMD(sum1, sum2, sumd);
if (nat->nat_dir == NAT_OUTBOUND) {
- fix_incksum(&oip->ip_sum, sumd, 0);
+ /*
+ * Fix IP checksum of the offending IP packet to adjust for
+ * the change in the IP address.
+ *
+ * Normally, you would expect that the ICMP checksum of the
+ * ICMP error message needs to be adjusted as well for the
+ * IP address change in oip.
+ * However, this is a NOP, because the ICMP checksum is
+ * calculated over the complete ICMP packet, which includes the
+ * changed oip IP addresses and oip->ip_sum. However, these
+ * two changes cancel each other out (if the delta for
+ * the IP address is x, then the delta for ip_sum is minus x),
+ * so no change in the icmp_cksum is necessary.
+ *
+ * Be careful that nat_dir refers to the direction of the
+ * offending IP packet (oip), not to its ICMP response (icmp)
+ */
+ fix_datacksum(&oip->ip_sum, sumd);
- sumd += (sumd & 0xffff);
- while (sumd > 0xffff)
- sumd = (sumd & 0xffff) + (sumd >> 16);
- fix_outcksum(&icmp->icmp_cksum, sumd, 0);
+ /*
+ * Fix UDP pseudo header checksum to compensate for the
+ * IP address change.
+ */
+ if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) {
+ /*
+ * The UDP checksum is optional, only adjust it
+ * if it has been set.
+ */
+ sum1 = ntohs(udp->uh_sum);
+ fix_datacksum(&udp->uh_sum, sumd);
+ sum2 = ntohs(udp->uh_sum);
+
+ /*
+ * Fix ICMP checksum to compensate the UDP
+ * checksum adjustment.
+ */
+ CALC_SUMD(sum1, sum2, sumd);
+ fix_outcksum(&icmp->icmp_cksum, sumd);
+ }
+
+#if 0
+ /*
+ * Fix TCP pseudo header checksum to compensate for the
+ * IP address change. Before we can do the change, we
+ * must make sure that oip is sufficient large to hold
+ * the TCP checksum (normally it does not!).
+ */
+ if (oip->ip_p == IPPROTO_TCP) {
+
+ }
+#endif
} else {
- fix_outcksum(&oip->ip_sum, sumd, 0);
+
+ /*
+ * Fix IP checksum of the offending IP packet to adjust for
+ * the change in the IP address.
+ *
+ * Normally, you would expect that the ICMP checksum of the
+ * ICMP error message needs to be adjusted as well for the
+ * IP address change in oip.
+ * However, this is a NOP, because the ICMP checksum is
+ * calculated over the complete ICMP packet, which includes the
+ * changed oip IP addresses and oip->ip_sum. However, these
+ * two changes cancel each other out (if the delta for
+ * the IP address is x, then the delta for ip_sum is minus x),
+ * so no change in the icmp_cksum is necessary.
+ *
+ * Be careful that nat_dir refers to the direction of the
+ * offending IP packet (oip), not to its ICMP response (icmp)
+ */
+ fix_datacksum(&oip->ip_sum, sumd);
+
+/* XXX FV : without having looked at Solaris source code, it seems unlikely
+ * that SOLARIS would compensate this in the kernel (a body of an IP packet
+ * in the data section of an ICMP packet). I have the feeling that this should
+ * be unconditional, but I'm not in a position to check.
+ */
#if !SOLARIS && !defined(__sgi)
- sumd += (sumd & 0xffff);
- while (sumd > 0xffff)
- sumd = (sumd & 0xffff) + (sumd >> 16);
- fix_incksum(&icmp->icmp_cksum, sumd, 0);
+ /*
+ * Fix UDP pseudo header checksum to compensate for the
+ * IP address change.
+ */
+ if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) {
+ /*
+ * The UDP checksum is optional, only adjust it
+ * if it has been set
+ */
+ sum1 = ntohs(udp->uh_sum);
+ fix_datacksum(&udp->uh_sum, sumd);
+ sum2 = ntohs(udp->uh_sum);
+
+ /*
+ * Fix ICMP checksum to compensate the UDP
+ * checksum adjustment.
+ */
+ CALC_SUMD(sum1, sum2, sumd);
+ fix_incksum(&icmp->icmp_cksum, sumd);
+ }
+
+#if 0
+ /*
+ * Fix TCP pseudo header checksum to compensate for the
+ * IP address change. Before we can do the change, we
+ * must make sure that oip is sufficient large to hold
+ * the TCP checksum (normally it does not!).
+ */
+ if (oip->ip_p == IPPROTO_TCP) {
+
+ };
+#endif
+
#endif
}
@@ -1624,23 +1777,98 @@ int dir;
* XXX - what if this is bogus hl and we go off the end ?
* In this case, nat_icmpinlookup() will have returned NULL.
*/
- tcp = (tcphdr_t *)((((char *)oip) + (oip->ip_hl << 2)));
+ tcp = (tcphdr_t *)udp;
+
+ /*
+ * Step 2 :
+ * For offending TCP/UDP IP packets, translate the ports as
+ * well, based on the NAT specification. Of course such
+ * a change must be reflected in the ICMP checksum as well.
+ *
+ * Advance notice : Now it becomes complicated :-)
+ *
+ * Since the port fields are part of the TCP/UDP checksum
+ * of the offending IP packet, you need to adjust that checksum
+ * as well... but, if you change, you must change the icmp
+ * checksum *again*, to reflect that change.
+ *
+ * To further complicate: the TCP checksum is not in the first
+ * 8 bytes of the offending ip packet, so it most likely is not
+ * available (we might have to fix that if the encounter a
+ * device that returns more than 8 data bytes on icmp error)
+ */
if (nat->nat_dir == NAT_OUTBOUND) {
if (tcp->th_sport != nat->nat_inport) {
+ /*
+ * Fix ICMP checksum to compensate port
+ * adjustment.
+ */
sum1 = ntohs(tcp->th_sport);
sum2 = ntohs(nat->nat_inport);
CALC_SUMD(sum1, sum2, sumd);
tcp->th_sport = nat->nat_inport;
- fix_outcksum(&icmp->icmp_cksum, sumd, 0);
+ fix_outcksum(&icmp->icmp_cksum, sumd);
+
+ /*
+ * Fix udp checksum to compensate port
+ * adjustment. NOTE : the offending IP packet
+ * flows the other direction compared to the
+ * ICMP message.
+ *
+ * The UDP checksum is optional, only adjust
+ * it if it has been set.
+ */
+ if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) {
+
+ sum1 = ntohs(udp->uh_sum);
+ fix_datacksum(&udp->uh_sum, sumd);
+ sum2 = ntohs(udp->uh_sum);
+
+ /*
+ * Fix ICMP checksum to
+ * compensate UDP checksum
+ * adjustment.
+ */
+ CALC_SUMD(sum1, sum2, sumd);
+ fix_outcksum(&icmp->icmp_cksum, sumd);
+ }
}
} else {
+
if (tcp->th_dport != nat->nat_outport) {
+ /*
+ * Fix ICMP checksum to compensate port
+ * adjustment.
+ */
sum1 = ntohs(tcp->th_dport);
sum2 = ntohs(nat->nat_outport);
CALC_SUMD(sum1, sum2, sumd);
tcp->th_dport = nat->nat_outport;
- fix_incksum(&icmp->icmp_cksum, sumd, 0);
+ fix_incksum(&icmp->icmp_cksum, sumd);
+
+ /*
+ * Fix udp checksum to compensate port
+ * adjustment. NOTE : the offending IP
+ * packet flows the other direction compared
+ * to the ICMP message.
+ *
+ * The UDP checksum is optional, only adjust
+ * it if it has been set.
+ */
+ if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) {
+
+ sum1 = ntohs(udp->uh_sum);
+ fix_datacksum(&udp->uh_sum, sumd);
+ sum2 = ntohs(udp->uh_sum);
+
+ /*
+ * Fix ICMP checksum to compensate
+ * UDP checksum adjustment.
+ */
+ CALC_SUMD(sum1, sum2, sumd);
+ fix_incksum(&icmp->icmp_cksum, sumd);
+ }
}
}
}
@@ -1665,30 +1893,92 @@ register u_int flags, p;
struct in_addr src , mapdst;
u_32_t ports;
{
- register u_short sport, mapdport;
+ register u_short sport, dport;
register nat_t *nat;
register int nflags;
+ register u_32_t dst;
u_int hv;
- mapdport = ports >> 16;
+ dst = mapdst.s_addr;
+ dport = ports >> 16;
sport = ports & 0xffff;
flags &= IPN_TCPUDP;
- hv = NAT_HASH_FN(mapdst.s_addr, mapdport, ipf_nattable_sz);
+ hv = NAT_HASH_FN(dst, dport, ipf_nattable_sz);
nat = nat_table[1][hv];
for (; nat; nat = nat->nat_hnext[1]) {
nflags = nat->nat_flags;
if ((!ifp || ifp == nat->nat_ifp) &&
nat->nat_oip.s_addr == src.s_addr &&
- nat->nat_outip.s_addr == mapdst.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 == mapdport) ||
- (nflags & FI_W_SPORT)))))
+ ((nat->nat_outport == dport) || (nflags & FI_W_SPORT)))))
return nat;
}
- return NULL;
+ if (!nat_wilds || !(flags & IPN_TCPUDP))
+ return NULL;
+ RWLOCK_EXIT(&ipf_nat);
+ hv = NAT_HASH_FN(dst, 0, ipf_nattable_sz);
+ WRITE_ENTER(&ipf_nat);
+ nat = nat_table[1][hv];
+ for (; nat; nat = nat->nat_hnext[1]) {
+ 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 ||
+ nat->nat_outip.s_addr != dst)
+ continue;
+ if (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) &&
+ ((nat->nat_outport == dport) || (nflags & FI_W_SPORT))) {
+ hv = NAT_HASH_FN(dst, dport, ipf_nattable_sz);
+ nat_tabmove(nat, hv);
+ break;
+ }
+ }
+ MUTEX_DOWNGRADE(&ipf_nat);
+ return nat;
+}
+
+
+static void nat_tabmove(nat, hv)
+nat_t *nat;
+u_int hv;
+{
+ nat_t **natp;
+
+ /*
+ * 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];
+
+ if (nat->nat_hnext[1])
+ nat->nat_hnext[0]->nat_phnext[1] = nat->nat_phnext[1];
+ *nat->nat_phnext[1] = nat->nat_hnext[1];
+
+ natp = &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;
+
+ /*
+ * Add into the NAT table in the new position
+ */
+ natp = &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;
}
@@ -1707,19 +1997,21 @@ u_32_t ports;
register u_short sport, dport;
register nat_t *nat;
register int nflags;
+ u_32_t srcip;
u_int hv;
sport = ports & 0xffff;
dport = ports >> 16;
flags &= IPN_TCPUDP;
+ srcip = src.s_addr;
- hv = NAT_HASH_FN(src.s_addr, sport, ipf_nattable_sz);
+ hv = NAT_HASH_FN(srcip, sport, ipf_nattable_sz);
nat = nat_table[0][hv];
for (; nat; nat = nat->nat_hnext[0]) {
nflags = nat->nat_flags;
if ((!ifp || ifp == nat->nat_ifp) &&
- nat->nat_inip.s_addr == src.s_addr &&
+ nat->nat_inip.s_addr == srcip &&
nat->nat_oip.s_addr == dst.s_addr &&
(((p == 0) && (flags == (nat->nat_flags & IPN_TCPUDP)))
|| (p == nat->nat_p)) && (!flags ||
@@ -1727,7 +2019,32 @@ u_32_t ports;
(nat->nat_oport == dport || nflags & FI_W_DPORT))))
return nat;
}
- return NULL;
+ if (!nat_wilds || !(flags & IPN_TCPUDP))
+ return NULL;
+ RWLOCK_EXIT(&ipf_nat);
+ hv = NAT_HASH_FN(srcip, 0, ipf_nattable_sz);
+ WRITE_ENTER(&ipf_nat);
+ nat = nat_table[0][hv];
+ for (; nat; nat = nat->nat_hnext[0]) {
+ 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) ||
+ (nat->nat_oip.s_addr != dst.s_addr))
+ continue;
+ if (((nat->nat_inport == sport) || (nflags & FI_W_DPORT)) &&
+ ((nat->nat_oport == dport) || (nflags & FI_W_SPORT))) {
+ hv = NAT_HASH_FN(srcip, sport, ipf_nattable_sz);
+ nat_tabmove(nat, hv);
+ break;
+ }
+ }
+ MUTEX_DOWNGRADE(&ipf_nat);
+ return nat;
}
@@ -1863,6 +2180,7 @@ fr_info_t *fin;
nat->nat_outport = sport;
nat->nat_flags &= ~(FI_W_DPORT|FI_W_SPORT);
nflags = nat->nat_flags;
+ nat_wilds--;
}
} else {
RWLOCK_EXIT(&ipf_nat);
@@ -1943,16 +2261,16 @@ maskloop:
CALC_SUMD(s1, s2, sumd);
if (nat->nat_dir == NAT_OUTBOUND)
- fix_incksum(&ip->ip_sum, sumd, 0);
+ fix_incksum(&ip->ip_sum, sumd);
else
- fix_outcksum(&ip->ip_sum, sumd, 0);
+ fix_outcksum(&ip->ip_sum, sumd);
}
#if SOLARIS || defined(__sgi)
else {
if (nat->nat_dir == NAT_OUTBOUND)
- fix_outcksum(&ip->ip_sum, nat->nat_ipsumd, 0);
+ fix_outcksum(&ip->ip_sum, nat->nat_ipsumd);
else
- fix_incksum(&ip->ip_sum, nat->nat_ipsumd, 0);
+ fix_incksum(&ip->ip_sum, nat->nat_ipsumd);
}
#endif
ip->ip_src = nat->nat_outip;
@@ -1996,11 +2314,9 @@ maskloop:
if (csump) {
if (nat->nat_dir == NAT_OUTBOUND)
- fix_outcksum(csump, nat->nat_sumd[1],
- ip->ip_len);
+ fix_outcksum(csump, nat->nat_sumd[1]);
else
- fix_incksum(csump, nat->nat_sumd[1],
- ip->ip_len);
+ fix_incksum(csump, nat->nat_sumd[1]);
}
}
@@ -2077,6 +2393,7 @@ fr_info_t *fin;
nat->nat_outport = dport;
nat->nat_flags &= ~(FI_W_SPORT|FI_W_DPORT);
nflags = nat->nat_flags;
+ nat_wilds--;
}
} else {
RWLOCK_EXIT(&ipf_nat);
@@ -2154,9 +2471,9 @@ maskloop:
*/
#if SOLARIS || defined(__sgi)
if (nat->nat_dir == NAT_OUTBOUND)
- fix_incksum(&ip->ip_sum, nat->nat_ipsumd, 0);
+ fix_incksum(&ip->ip_sum, nat->nat_ipsumd);
else
- fix_outcksum(&ip->ip_sum, nat->nat_ipsumd, 0);
+ fix_outcksum(&ip->ip_sum, nat->nat_ipsumd);
#endif
if (!(ip->ip_off & IP_OFFMASK) &&
!(fin->fin_fi.fi_fl & FI_SHORT)) {
@@ -2197,11 +2514,9 @@ maskloop:
if (csump) {
if (nat->nat_dir == NAT_OUTBOUND)
- fix_incksum(csump, nat->nat_sumd[0],
- 0);
+ fix_incksum(csump, nat->nat_sumd[0]);
else
- fix_outcksum(csump, nat->nat_sumd[0],
- 0);
+ fix_outcksum(csump, nat->nat_sumd[0]);
}
}
ATOMIC_INCL(nat_stats.ns_mapped[0]);
diff --git a/sys/netinet/ip_nat.h b/sys/netinet/ip_nat.h
index b5d53e8..4b24d81 100644
--- a/sys/netinet/ip_nat.h
+++ b/sys/netinet/ip_nat.h
@@ -82,7 +82,7 @@ typedef struct nat {
struct hostmap *nat_hm;
struct nat *nat_next;
struct nat *nat_hnext[2];
- struct nat **nat_hstart[2];
+ struct nat **nat_phnext[2];
void *nat_ifp;
int nat_dir;
char nat_ifname[IFNAMSIZ];
@@ -142,6 +142,11 @@ typedef struct ipnat {
#define NAT_REDIRECT 0x02
#define NAT_BIMAP (NAT_MAP|NAT_REDIRECT)
#define NAT_MAPBLK 0x04
+/* 0x100 reserved for FI_W_SPORT */
+/* 0x200 reserved for FI_W_DPORT */
+/* 0x400 reserved for FI_W_SADDR */
+/* 0x800 reserved for FI_W_DADDR */
+/* 0x1000 reserved for FI_W_NEWFR */
#define MAPBLK_MINPORT 1024 /* don't use reserved ports for src port */
#define USABLE_PORTS (65536 - MAPBLK_MINPORT)
@@ -294,7 +299,8 @@ extern int ip_natout __P((ip_t *, fr_info_t *));
extern int ip_natin __P((ip_t *, fr_info_t *));
extern void ip_natunload __P((void)), ip_natexpire __P((void));
extern void nat_log __P((struct nat *, u_int));
-extern void fix_incksum __P((u_short *, u_32_t, int));
-extern void fix_outcksum __P((u_short *, u_32_t, int));
+extern void fix_incksum __P((u_short *, u_32_t));
+extern void fix_outcksum __P((u_short *, u_32_t));
+extern void fix_datacksum __P((u_short *, u_32_t));
#endif /* __IP_NAT_H__ */
diff --git a/sys/netinet/ip_raudio_pxy.c b/sys/netinet/ip_raudio_pxy.c
index fd62033..ee527a3 100644
--- a/sys/netinet/ip_raudio_pxy.c
+++ b/sys/netinet/ip_raudio_pxy.c
@@ -171,8 +171,8 @@ nat_t *nat;
tcphdr_t *tcp, tcph, *tcp2 = &tcph;
raudio_t *rap = aps->aps_data;
struct in_addr swa, swb;
- u_int a1, a2, a3, a4;
int off, dlen, slen;
+ int a1, a2, a3, a4;
u_short sp, dp;
fr_info_t fi;
tcp_seq seq;
diff --git a/sys/netinet/ip_state.c b/sys/netinet/ip_state.c
index 01fc030..ec0fb7c 100644
--- a/sys/netinet/ip_state.c
+++ b/sys/netinet/ip_state.c
@@ -106,6 +106,7 @@ static const char rcsid[] = "@(#)$FreeBSD$";
static ipstate_t **ips_table = NULL;
static ipstate_t *ips_list = NULL;
static int ips_num = 0;
+static int ips_wild = 0;
static ips_stat_t ips_stats;
#if (SOLARIS || defined(__sgi)) && defined(_KERNEL)
extern KRWLOCK_T ipf_state, ipf_mutex;
@@ -123,6 +124,7 @@ static int fr_state_flush __P((int));
static ips_stat_t *fr_statetstats __P((void));
static void fr_delstate __P((ipstate_t *));
static int fr_state_remove __P((caddr_t));
+static void fr_ipsmove __P((ipstate_t **, ipstate_t *, u_int));
int fr_stputent __P((caddr_t));
int fr_stgetent __P((caddr_t));
void fr_stinsert __P((ipstate_t *));
@@ -135,7 +137,8 @@ u_long fr_tcpidletimeout = FIVE_DAYS,
fr_tcpclosewait = 2 * TCP_MSL,
fr_tcplastack = 2 * TCP_MSL,
fr_tcptimeout = 2 * TCP_MSL,
- fr_tcpclosed = 1,
+ fr_tcpclosed = 120,
+ fr_tcphalfclosed = 2 * 2 * 3600, /* 2 hours */
fr_udptimeout = 240,
fr_icmptimeout = 120;
int fr_statemax = IPSTATE_MAX,
@@ -240,9 +243,12 @@ caddr_t data;
for (sp = ips_list; sp; sp = sp->is_next)
if ((sp->is_p == st.is_p) && (sp->is_v == st.is_v) &&
- !bcmp(&sp->is_src, &st.is_src, sizeof(st.is_src)) &&
- !bcmp(&sp->is_dst, &st.is_src, sizeof(st.is_dst)) &&
- !bcmp(&sp->is_ps, &st.is_ps, sizeof(st.is_ps))) {
+ !bcmp((char *)&sp->is_src, (char *)&st.is_src,
+ sizeof(st.is_src)) &&
+ !bcmp((char *)&sp->is_dst, (char *)&st.is_src,
+ sizeof(st.is_dst)) &&
+ !bcmp((char *)&sp->is_ps, (char *)&st.is_ps,
+ sizeof(st.is_ps))) {
WRITE_ENTER(&ipf_state);
#ifdef IPFILTER_LOG
ipstate_log(sp, ISL_REMOVE);
@@ -590,8 +596,8 @@ u_int flags;
hv += tcp->th_dport;
hv += tcp->th_sport;
}
- is->is_send = ntohl(tcp->th_seq) + ip->ip_len -
- fin->fin_hlen - (tcp->th_off << 2) +
+ is->is_send = ntohl(tcp->th_seq) + fin->fin_dlen -
+ (tcp->th_off << 2) +
((tcp->th_flags & TH_SYN) ? 1 : 0) +
((tcp->th_flags & TH_FIN) ? 1 : 0);
is->is_maxsend = is->is_send;
@@ -660,6 +666,8 @@ u_int flags;
is->is_flags = fin->fin_fi.fi_fl & FI_CMP;
is->is_flags |= FI_CMP << 4;
is->is_flags |= flags & (FI_WILDP|FI_WILDA);
+ if (flags & (FI_WILDP|FI_WILDA))
+ ips_wild++;
is->is_ifp[1 - out] = NULL;
is->is_ifp[out] = fin->fin_ifp;
#ifdef _KERNEL
@@ -718,6 +726,7 @@ tcphdr_t *tcp;
((tcp->th_flags & TH_SYN) ? 1 : 0) +
((tcp->th_flags & TH_FIN) ? 1 : 0);
+ MUTEX_ENTER(&is->is_lock);
if (fdata->td_end == 0) {
/*
* Must be a (outgoing) SYN-ACK in reply to a SYN.
@@ -783,12 +792,11 @@ tcphdr_t *tcp;
/*
* Nearing end of connection, start timeout.
*/
- MUTEX_ENTER(&is->is_lock);
/* source ? 0 : 1 -> !source */
fr_tcp_age(&is->is_age, is->is_state, fin, !source);
- MUTEX_EXIT(&is->is_lock);
ret = 1;
}
+ MUTEX_EXIT(&is->is_lock);
return ret;
}
@@ -892,6 +900,7 @@ tcphdr_t *tcp;
is->is_maxdend = is->is_dend + 1;
}
is->is_flags &= ~(FI_W_SPORT|FI_W_DPORT);
+ ips_wild--;
}
ret = -1;
@@ -983,7 +992,7 @@ fr_info_t *fin;
* Only a basic IP header (no options) should be with
* an ICMP error header.
*/
- if (((ip->ip_v != 4) && (ip->ip_hl != 5)) ||
+ if (((ip->ip_v != 4) || (ip->ip_hl != 5)) ||
(fin->fin_plen < ICMPERR_MINPKTLEN))
return NULL;
ic = (struct icmp *)fin->fin_dp;
@@ -1037,8 +1046,8 @@ fr_info_t *fin;
* the IP6EQ and IP6NEQ macros produce the wrong results because
* of the 'junk' in the unused part of the union
*/
- bzero(&src, sizeof(src));
- bzero(&dst, sizeof(dst));
+ bzero((char *)&src, sizeof(src));
+ bzero((char *)&dst, sizeof(dst));
if (oip->ip_p == IPPROTO_ICMP) {
icmp = (icmphdr_t *)((char *)oip + (oip->ip_hl << 2));
@@ -1158,6 +1167,38 @@ fr_info_t *fin;
return NULL;
}
+
+static void fr_ipsmove(isp, is, hv)
+ipstate_t **isp, *is;
+u_int hv;
+{
+ u_int hvm;
+
+ hvm = is->is_hv;
+ /*
+ * Remove the hash from the old location...
+ */
+ if (is->is_hnext)
+ is->is_hnext->is_phnext = isp;
+ *isp = is->is_hnext;
+ if (ips_table[hvm] == NULL)
+ ips_stats.iss_inuse--;
+
+ /*
+ * ...and put the hash in the new one.
+ */
+ hvm = hv % fr_statesize;
+ isp = &ips_table[hvm];
+ if (*isp)
+ (*isp)->is_phnext = &is->is_hnext;
+ else
+ ips_stats.iss_inuse++;
+ is->is_phnext = isp;
+ is->is_hnext = *isp;
+ *isp = is;
+}
+
+
/*
* Check if a packet has a registered state.
*/
@@ -1240,7 +1281,7 @@ fr_info_t *fin;
break;
case IPPROTO_TCP :
{
- register u_short dport = tcp->th_dport, sport = tcp->th_sport;
+ register u_short dport, sport;
register int i;
i = tcp->th_flags;
@@ -1250,57 +1291,42 @@ fr_info_t *fin;
if ((i & TH_RST) &&
((i & (TH_FIN|TH_SYN|TH_RST)) != TH_RST))
break;
+ case IPPROTO_UDP :
+ dport = tcp->th_dport;
+ sport = tcp->th_sport;
tryagain = 0;
-retry_tcp:
- hvm = hv % fr_statesize;
- WRITE_ENTER(&ipf_state);
- for (isp = &ips_table[hvm]; (is = *isp);
- isp = &is->is_hnext)
-
-
- if ((is->is_p == pr) && (is->is_v == v) &&
- fr_matchsrcdst(is, src, dst, fin, tcp)) {
- if (fr_tcpstate(is, fin, ip, tcp))
- break;
- is = NULL;
- break;
- }
- if (is != NULL)
- break;
- RWLOCK_EXIT(&ipf_state);
hv += dport;
hv += sport;
- if (tryagain == 0) {
- tryagain = 1;
- goto retry_tcp;
- }
- break;
- }
- case IPPROTO_UDP :
- {
- register u_short dport = tcp->th_dport, sport = tcp->th_sport;
-
- tryagain = 0;
-retry_udp:
- hvm = hv % fr_statesize;
- /*
- * Nothing else to match on but ports. and IP#'s
- */
READ_ENTER(&ipf_state);
- for (is = ips_table[hvm]; is; is = is->is_hnext)
+retry_tcpudp:
+ hvm = hv % fr_statesize;
+ for (isp = &ips_table[hvm]; (is = *isp); isp = &is->is_hnext)
if ((is->is_p == pr) && (is->is_v == v) &&
fr_matchsrcdst(is, src, dst, fin, tcp)) {
- is->is_age = fr_udptimeout;
+ if ((pr == IPPROTO_TCP)) {
+ if (!fr_tcpstate(is, fin, ip, tcp)) {
+ continue;
+ }
+ }
break;
}
- if (is != NULL)
+ if (is != NULL) {
+ if (tryagain &&
+ !(is->is_flags & (FI_WILDP|FI_WILDA))) {
+ hv += dport;
+ hv += sport;
+ fr_ipsmove(isp, is, hv);
+ MUTEX_DOWNGRADE(&ipf_state);
+ }
break;
+ }
RWLOCK_EXIT(&ipf_state);
- hv += dport;
- hv += sport;
- if (tryagain == 0) {
+ if (!tryagain && ips_wild) {
+ hv -= dport;
+ hv -= sport;
tryagain = 1;
- goto retry_udp;
+ WRITE_ENTER(&ipf_state);
+ goto retry_tcpudp;
}
break;
}
@@ -1357,6 +1383,8 @@ ipstate_t *is;
{
frentry_t *fr;
+ if (is->is_flags & (FI_WILDP|FI_WILDA))
+ ips_wild--;
if (is->is_next)
is->is_next->is_pnext = is->is_pnext;
*is->is_pnext = is->is_next;
@@ -1566,7 +1594,7 @@ int dir;
* SYN_RECEIVED -> FIN_WAIT_1
*/
state[dir] = TCPS_FIN_WAIT_1;
- *age = fr_tcpidletimeout; /* or fr_tcptimeout? */
+ *age = fr_tcpidletimeout;
}
break;
@@ -1578,7 +1606,7 @@ int dir;
* ESTABLISHED -> FIN_WAIT_1
*/
state[dir] = TCPS_FIN_WAIT_1;
- *age = fr_tcpidletimeout;
+ *age = fr_tcphalfclosed;
} else if (flags & TH_ACK) {
/* an ACK, should we exclude other flags here? */
if (ostate == TCPS_FIN_WAIT_1) {
@@ -1590,7 +1618,7 @@ int dir;
* a half-closed connection
*/
state[dir] = TCPS_CLOSE_WAIT;
- *age = fr_tcpidletimeout;
+ *age = fr_tcphalfclosed;
} else if (ostate < TCPS_CLOSE_WAIT)
/*
* Still a fully established connection,
@@ -1614,7 +1642,7 @@ int dir;
* closed already and we did not close our side yet;
* reset timeout
*/
- *age = fr_tcpidletimeout;
+ *age = fr_tcphalfclosed;
}
break;
@@ -1638,7 +1666,7 @@ int dir;
* other side is still active (ESTABLISHED/CLOSE_WAIT);
* continue with this half-closed connection
*/
- *age = fr_tcpidletimeout;
+ *age = fr_tcphalfclosed;
break;
case TCPS_CLOSING: /* 7 */
diff --git a/sys/netinet/ip_state.h b/sys/netinet/ip_state.h
index 2374068..765709c 100644
--- a/sys/netinet/ip_state.h
+++ b/sys/netinet/ip_state.h
@@ -174,6 +174,7 @@ extern u_long fr_tcpclosewait;
extern u_long fr_tcplastack;
extern u_long fr_tcptimeout;
extern u_long fr_tcpclosed;
+extern u_long fr_tcphalfclosed;
extern u_long fr_udptimeout;
extern u_long fr_icmptimeout;
extern int fr_state_lock;
diff --git a/sys/netinet/ipl.h b/sys/netinet/ipl.h
index edb4dc9..67cbf31 100644
--- a/sys/netinet/ipl.h
+++ b/sys/netinet/ipl.h
@@ -12,6 +12,6 @@
#ifndef __IPL_H__
#define __IPL_H__
-#define IPL_VERSION "IP Filter: v3.4.9"
+#define IPL_VERSION "IP Filter: v3.4.12"
#endif
diff --git a/sys/netinet/mlfk_ipl.c b/sys/netinet/mlfk_ipl.c
index e92360d..1be8916 100644
--- a/sys/netinet/mlfk_ipl.c
+++ b/sys/netinet/mlfk_ipl.c
@@ -65,6 +65,8 @@ SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RW,
&fr_tcptimeout, 0, "");
SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RW,
&fr_tcpclosed, 0, "");
+SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RW,
+ &fr_tcphalfclosed, 0, "");
SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RW,
&fr_udptimeout, 0, "");
SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RW,
OpenPOWER on IntegriCloud