summaryrefslogtreecommitdiff
path: root/sys/netinet/ip_nat.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/ip_nat.c')
-rw-r--r--sys/netinet/ip_nat.c55
1 files changed, 46 insertions, 9 deletions
diff --git a/sys/netinet/ip_nat.c b/sys/netinet/ip_nat.c
index 6bf634f9c9c..a6283e04d34 100644
--- a/sys/netinet/ip_nat.c
+++ b/sys/netinet/ip_nat.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_nat.c,v 1.33 2000/07/03 04:50:05 aaron Exp $ */
+/* $OpenBSD: ip_nat.c,v 1.34 2000/08/10 05:50:26 kjell Exp $ */
/*
* Copyright (C) 1995-1998 by Darren Reed.
@@ -11,7 +11,7 @@
*/
#if !defined(lint)
static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed";
-static const char rcsid[] = "@(#)$IPFilter: ip_nat.c,v 2.2.2.18 2000/05/19 15:52:29 darrenr Exp $";
+static const char rcsid[] = "@(#)$IPFilter: ip_nat.c,v 2.2.2.21 2000/08/08 16:00:33 darrenr Exp $";
#endif
#if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL)
@@ -410,7 +410,7 @@ int mode;
* mapping range. In all cases, the range is inclusive of
* the start and ending IP addresses.
* If to a CIDR address, lose 2: broadcast + network address
- * (so subtract 1)
+ * (so subtract 1)
* If to a range, add one.
* If to a single IP address, set to 1.
*/
@@ -614,9 +614,9 @@ void
nat_ifdetach(ifp)
struct ifnet *ifp;
{
- ipnat_t *n, **np = &nat_list;
+ ipnat_t *n, **np;
- while ((n = *np)) {
+ for (np = &nat_list; (n = *np) != NULL; np = &n->in_next) {
*np = n->in_next;
if (!n->in_use) {
if (n->in_apr)
@@ -627,6 +627,7 @@ nat_ifdetach(ifp)
n->in_flags |= IPN_DELETE;
n->in_next = NULL;
}
+ n = NULL;
}
}
@@ -1027,11 +1028,13 @@ nat_t *nat_icmpinlookup(ip, fin)
ip_t *ip;
fr_info_t *fin;
{
- icmphdr_t *icmp;
tcphdr_t *tcp = NULL;
+ icmphdr_t *icmp;
ip_t *oip;
- int flags = 0, type;
+ int flags = 0, type, minlen;
+ if ((fin->fin_fi.fi_fl & FI_SHORT) || (ip->ip_off & IP_OFFMASK))
+ return NULL;
icmp = (icmphdr_t *)fin->fin_dp;
/*
* Does it at least have the return (basic) IP header ?
@@ -1050,13 +1053,43 @@ fr_info_t *fin;
return NULL;
oip = (ip_t *)((char *)fin->fin_dp + 8);
- if (ip->ip_len < ICMPERR_MAXPKTLEN + ((oip->ip_hl - 5) << 2))
+ minlen = (oip->ip_hl << 2);
+ if (ip->ip_len < ICMPERR_MINPKTLEN + minlen)
+ return NULL;
+ /*
+ * Is the buffer big enough for all of it ? It's the size of the IP
+ * header claimed in the encapsulated part which is of concern. It
+ * may be too big to be in this buffer but not so big that it's
+ * outside the ICMP packet, leading to TCP deref's causing problems.
+ * This is possible because we don't know how big oip_hl is when we
+ * do the pullup early in fr_check() and thus can't gaurantee it is
+ * all here now.
+ */
+#ifdef _KERNEL
+ {
+ mb_t *m;
+
+# if SOLARIS
+ m = fin->fin_qfm;
+ if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr)
return NULL;
+# else
+ m = *(mb_t **)fin->fin_mp;
+ if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >
+ (char *)ip + m->m_len)
+ return NULL;
+# endif
+ }
+#endif
+
if (oip->ip_p == IPPROTO_TCP)
flags = IPN_TCP;
else if (oip->ip_p == IPPROTO_UDP)
flags = IPN_UDP;
if (flags & IPN_TCPUDP) {
+ minlen += 8; /* + 64bits of data to get ports */
+ if (ip->ip_len < ICMPERR_MINPKTLEN + minlen)
+ return NULL;
tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2));
return nat_inlookup(fin->fin_ifp, flags, (u_int)oip->ip_p,
oip->ip_dst, oip->ip_src,
@@ -1135,7 +1168,10 @@ u_int *nflags;
if ((flags & IPN_TCPUDP) != 0) {
tcphdr_t *tcp;
- /* XXX - what if this is bogus hl and we go off the end ? */
+ /*
+ * 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)));
if (nat->nat_dir == NAT_OUTBOUND) {
@@ -1466,6 +1502,7 @@ maskloop:
} else if (ip->ip_p == IPPROTO_ICMP) {
nat->nat_age = fr_defnaticmpage;
}
+
if (csump) {
if (nat->nat_dir == NAT_OUTBOUND)
fix_outcksum(csump, nat->nat_sumd[1],