aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarren Reed <darrenr@FreeBSD.org>1997-05-25 15:50:46 +0000
committerDarren Reed <darrenr@FreeBSD.org>1997-05-25 15:50:46 +0000
commite10102a12a980dc84a95a4a831769c1058c946c0 (patch)
tree25de559faf9011589a627f617cbd6ba5d2249232
parent1fddb84ad639d46f835aa6d5b12abdbbc6934d03 (diff)
downloadsrc-e10102a12a980dc84a95a4a831769c1058c946c0.tar.gz
src-e10102a12a980dc84a95a4a831769c1058c946c0.zip
Import version 3.2alpha7vendor/ipfilter-sys/v3-2-a7
Notes
Notes: svn path=/vendor-sys/ipfilter/dist-old/; revision=26124 svn path=/vendor-sys/ipfilter/v3-2-a7/; revision=26126; tag=vendor/ipfilter-sys/v3-2-a7
-rw-r--r--sys/netinet/fil.c205
-rw-r--r--sys/netinet/ip_compat.h32
-rw-r--r--sys/netinet/ip_fil.c110
-rw-r--r--sys/netinet/ip_fil.h91
-rw-r--r--sys/netinet/ip_frag.c223
-rw-r--r--sys/netinet/ip_frag.h11
-rw-r--r--sys/netinet/ip_ftp_pxy.c204
-rw-r--r--sys/netinet/ip_nat.c321
-rw-r--r--sys/netinet/ip_nat.h50
-rw-r--r--sys/netinet/ip_proxy.c271
-rw-r--r--sys/netinet/ip_proxy.h89
-rw-r--r--sys/netinet/ip_state.c56
-rw-r--r--sys/netinet/ip_state.h19
-rw-r--r--sys/netinet/ipl.h16
-rw-r--r--sys/netinet/mln_ipl.c377
15 files changed, 1759 insertions, 316 deletions
diff --git a/sys/netinet/fil.c b/sys/netinet/fil.c
index 118edf225ed5..b40695f829e3 100644
--- a/sys/netinet/fil.c
+++ b/sys/netinet/fil.c
@@ -7,7 +7,7 @@
*/
#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-1996 Darren Reed";
-static char rcsid[] = "$Id: fil.c,v 1.1.1.3 1997/04/03 10:10:10 darrenr Exp $";
+static char rcsid[] = "$Id: fil.c,v 2.0.2.13 1997/05/24 07:33:37 darrenr Exp $";
#endif
#include <sys/errno.h>
@@ -45,11 +45,12 @@ static char rcsid[] = "$Id: fil.c,v 1.1.1.3 1997/04/03 10:10:10 darrenr Exp $";
#include <netinet/udp.h>
#include <netinet/tcpip.h>
#include <netinet/ip_icmp.h>
-#include "ip_compat.h"
-#include "ip_fil.h"
-#include "ip_nat.h"
-#include "ip_frag.h"
-#include "ip_state.h"
+#include "netinet/ip_compat.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"
#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
@@ -70,7 +71,6 @@ extern int opts;
# define IPLLOG(a, c, d, e) ipllog()
# if SOLARIS
# define ICMP_ERROR(b, ip, t, c, if, src) icmp_error(ip)
-# define bcmp memcmp
# else
# define ICMP_ERROR(b, ip, t, c, if, src) icmp_error(b, ip, if)
# endif
@@ -100,19 +100,12 @@ extern kmutex_t ipf_mutex;
# endif
#endif
-#ifndef IPF_LOGGING
-#define IPF_LOGGING 0
-#endif
-#ifdef IPF_DEFAULT_PASS
-#define IPF_NOMATCH (IPF_DEFAULT_PASS|FR_NOMATCH)
-#else
-#define IPF_NOMATCH (FR_PASS|FR_NOMATCH)
-#endif
struct filterstats frstats[2] = {{0,0,0,0,0},{0,0,0,0,0}};
struct frentry *ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } },
*ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } };
int fr_flags = IPF_LOGGING, fr_active = 0;
+int fr_pass = (IPF_DEFAULT_PASS|FR_NOMATCH);
fr_info_t frcache[2];
@@ -417,7 +410,7 @@ void *m;
#endif
{
register u_long *ld, *lm, *lip;
- register int i;
+ register int i, j;
lip = (u_long *)fi;
lm = (u_long *)&fr->fr_mip;
@@ -425,10 +418,10 @@ void *m;
i = ((lip[0] & lm[0]) != ld[0]);
FR_IFDEBUG(i,continue,("0. %#08x & %#08x != %#08x\n",
lip[0], lm[0], ld[0]));
- i |= ((lip[1] & lm[1]) != ld[1]);
+ i |= ((lip[1] & lm[1]) != ld[1]) << 21;
FR_IFDEBUG(i,continue,("1. %#08x & %#08x != %#08x\n",
lip[1], lm[1], ld[1]));
- i |= ((lip[2] & lm[2]) != ld[2]);
+ i |= ((lip[2] & lm[2]) != ld[2]) << 22;
FR_IFDEBUG(i,continue,("2. %#08x & %#08x != %#08x\n",
lip[2], lm[2], ld[2]));
i |= ((lip[3] & lm[3]) != ld[3]);
@@ -437,6 +430,7 @@ void *m;
i |= ((lip[4] & lm[4]) != ld[4]);
FR_IFDEBUG(i,continue,("4. %#08x & %#08x != %#08x\n",
lip[4], lm[4], ld[4]));
+ i ^= (fi->fi_fl & (FR_NOTSRCIP|FR_NOTDSTIP));
if (i)
continue;
}
@@ -557,6 +551,7 @@ int out;
fr_makefrip(hlen, ip, fin);
fin->fin_ifp = ifp;
fin->fin_out = out;
+ fin->fin_mp = mp;
MUTEX_ENTER(&ipf_mutex);
if (!out) {
@@ -566,24 +561,8 @@ int out;
frstats[0].fr_acct++;
}
- if ((pass = ipfr_knownfrag(ip, fin))) {
- if ((pass & FR_KEEPSTATE)) {
- if (fr_addstate(ip, fin, pass) == -1)
- frstats[out].fr_bads++;
- else
- frstats[out].fr_ads++;
- }
- } else if ((pass = fr_checkstate(ip, fin))) {
- if ((pass & FR_KEEPFRAG)) {
- if (fin->fin_fi.fi_fl & FI_FRAG) {
- if (ipfr_newfrag(ip, fin, pass) == -1)
- frstats[out].fr_bnfr++;
- else
- frstats[out].fr_nfr++;
- } else
- frstats[out].fr_cfr++;
- }
- } else {
+ if (!(pass = ipfr_knownfrag(ip, fin)) &&
+ !(pass = fr_checkstate(ip, fin))) {
fc = frcache + out;
if (fc->fin_fr && !bcmp((char *)fin, (char *)fc, FI_CSIZE)) {
/*
@@ -594,16 +573,16 @@ int out;
frstats[out].fr_chit++;
pass = fin->fin_fr->fr_flags;
} else {
- pass = IPF_NOMATCH;
+ pass = fr_pass;
if ((fin->fin_fr = ipfilter[out][fr_active]))
- pass = FR_SCANLIST(IPF_NOMATCH, ip, fin, m);
+ pass = FR_SCANLIST(fr_pass, ip, fin, m);
bcopy((char *)fin, (char *)fc, FI_CSIZE);
if (pass & FR_NOMATCH)
frstats[out].fr_nom++;
}
fr = fin->fin_fr;
- if ((pass & FR_KEEPFRAG)) {
+ if (pass & FR_KEEPFRAG) {
if (fin->fin_fi.fi_fl & FI_FRAG) {
if (ipfr_newfrag(ip, fin, pass) == -1)
frstats[out].fr_bnfr++;
@@ -660,6 +639,19 @@ logit:
}
}
#endif /* IPFILTER_LOG */
+#ifdef _KERNEL
+ /*
+ * Only allow FR_DUP to work if a rule matched - it makes no sense to
+ * set FR_DUP as a "default" as there are no instructions about where
+ * to send the packet.
+ */
+ if (fr && (pass & FR_DUP))
+# if SOLARIS
+ mc = dupmsg(m);
+# else
+ mc = m_copy(m, 0, M_COPYALL);
+# endif
+#endif
if (pass & FR_PASS)
frstats[out].fr_pass++;
@@ -703,10 +695,16 @@ logit:
#endif
}
}
+
+ /*
+ * If we didn't drop off the bottom of the list of rules (and thus
+ * the 'current' rule fr is not NULL), then we may have some extra
+ * instructions about what to do with a packet.
+ * Once we're finished return to our caller, freeing the packet if
+ * we are dropping it (* BSD ONLY *).
+ */
#ifdef _KERNEL
# if !SOLARIS
- if (pass & FR_DUP)
- mc = m_copy(m, 0, M_COPYALL);
if (fr) {
frdest_t *fdp = &fr->fr_tif;
@@ -722,8 +720,6 @@ logit:
m_freem(m);
return (pass & FR_PASS) ? 0 : -1;
# else
- if (pass & FR_DUP)
- mc = dupmsg(m);
if (fr) {
frdest_t *fdp = &fr->fr_tif;
@@ -777,3 +773,126 @@ int len;
return len;
}
#endif
+
+
+u_short ipf_cksum(addr, len)
+register u_short *addr;
+register int len;
+{
+ register u_long sum = 0;
+
+ for (sum = 0; len > 1; len -= 2)
+ sum += *addr++;
+
+ /* mop up an odd byte, if necessary */
+ if (len == 1)
+ sum += *(u_char *)addr;
+
+ /*
+ * add back carry outs from top 16 bits to low 16 bits
+ */
+ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
+ sum += (sum >> 16); /* add carry */
+ return (u_short)(~sum);
+}
+
+
+/*
+ * NB: This function assumes we've pullup'd enough for all of the IP header
+ * and the TCP header. We also assume that data blocks aren't allocated in
+ * odd sizes.
+ */
+u_short fr_tcpsum(m, ip, tcp)
+#if SOLARIS
+mblk_t *m;
+#else
+struct mbuf *m;
+#endif
+ip_t *ip;
+tcphdr_t *tcp;
+{
+ union {
+ u_char c[2];
+ u_short s;
+ } bytes;
+ u_long sum;
+ u_short *sp;
+ int len, add, hlen, ilen;
+
+ /*
+ * Add up IP Header portion
+ */
+ ilen = len = ip->ip_len - (ip->ip_hl << 2);
+ bytes.c[0] = 0;
+ bytes.c[1] = IPPROTO_TCP;
+ sum = bytes.s;
+ sum += htons((u_short)len);
+ sp = (u_short *)&ip->ip_src;
+ sum += *sp++;
+ sum += *sp++;
+ sum += *sp++;
+ sum += *sp++;
+ if (sp != (u_short *)tcp)
+ sp = (u_short *)tcp;
+ sum += *sp++;
+ sum += *sp++;
+ sum += *sp++;
+ sum += *sp++;
+ sum += *sp++;
+ sum += *sp++;
+ sum += *sp++;
+ sum += *sp;
+ sp += 2; /* Skip over checksum */
+ sum += *sp++;
+
+#if SOLARIS
+ /*
+ * In case we had to copy the IP & TCP header out of mblks,
+ * skip over the mblk bits which are the header
+ */
+ if ((caddr_t)ip != (caddr_t)m->b_rptr) {
+ hlen = (caddr_t)sp - (caddr_t)ip;
+ while (hlen) {
+ add = MIN(hlen, m->b_wptr - m->b_rptr);
+ sp = (u_short *)((caddr_t)m->b_rptr + add);
+ if ((hlen -= add))
+ m = m->b_cont;
+ }
+ }
+#endif
+
+ if (!(len -= sizeof(*tcp)))
+ goto nodata;
+ while (len > 1) {
+ sum += *sp++;
+ len -= 2;
+#if SOLARIS
+ if ((caddr_t)sp > (caddr_t)m->b_wptr) {
+ m = m->b_cont;
+ PANIC((!m),("fr_tcpsum: not enough data"));
+ sp = (u_short *)m->b_rptr;
+ }
+#else
+# ifdef m_data
+ if ((caddr_t)sp > (m->m_data + m->m_len))
+# else
+ if ((caddr_t)sp > (caddr_t)(m->m_dat + m->m_off + m->m_len))
+# endif
+ {
+ m = m->m_next;
+ PANIC((!m),("fr_tcpsum: not enough data"));
+ sp = mtod(m, u_short *);
+ }
+#endif /* SOLARIS */
+ }
+ if (len) {
+ bytes.c[1] = 0;
+ bytes.c[0] = *(u_char *)sp;
+ sum += bytes.s;
+ }
+nodata:
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+ sum = (u_short)((~sum) & 0xffff);
+ return sum;
+}
diff --git a/sys/netinet/ip_compat.h b/sys/netinet/ip_compat.h
index 615e4d061139..cbb3239b2b8d 100644
--- a/sys/netinet/ip_compat.h
+++ b/sys/netinet/ip_compat.h
@@ -1,15 +1,15 @@
/*
- * (C)opyright 1993, 1994, 1995 by Darren Reed.
+ * (C)opyright 1993-1997 by Darren Reed.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and due credit is given
* to the original author and the contributors.
*
* @(#)ip_compat.h 1.8 1/14/96
- * $Id: ip_compat.h,v 1.1.1.2 1997/04/03 10:10:48 darrenr Exp $
+ * $Id: ip_compat.h,v 2.0.2.11 1997/05/04 05:29:02 darrenr Exp $
*/
-#ifndef __IP_COMPAT_H_
+#ifndef __IP_COMPAT_H__
#define __IP_COMPAT_H__
#ifndef __P
@@ -24,6 +24,22 @@
#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
#endif
+#if defined(_KERNEL) && !defined(KERNEL)
+#define KERNEL
+#endif
+#if defined(KERNEL) && !defined(_KERNEL)
+#define _KERNEL
+#endif
+
+#if defined(__SVR4) || defined(__svr4__)
+#define index strchr
+# ifndef _KERNEL
+# define bzero(a,b) memset(a,0,b)
+# define bcmp memcmp
+# define bcopy(a,b,c) memmove(b,a,c)
+# endif
+#endif
+
#if SOLARIS
# define MTYPE(m) ((m)->b_datap->db_type)
# include <sys/ioccom.h>
@@ -58,8 +74,10 @@
#if BSD > 199306
# define USE_QUAD_T
# define U_QUAD_T u_quad_t
+# define QUAD_T quad_t
#else
# define U_QUAD_T u_long
+# define QUAD_T long
#endif
#ifndef MAX
@@ -167,6 +185,7 @@ extern ill_t *get_unit __P((char *));
# define UIOMOVE(a,b,c,d) uiomove(a,b,c,d)
# define SLEEP(id, n) sleep((id), PZERO+1)
# define KFREE(x) kmem_free((char *)(x), sizeof(*(x)))
+# define KFREES(x,s) kmem_free((char *)(x), (s))
# if SOLARIS
typedef struct qif {
struct qif *qf_next;
@@ -219,13 +238,16 @@ extern vm_map_t kmem_map;
# define KMALLOC(a,b,c) (a) = (b)kmem_alloc(kmem_map, (c))
# define KFREE(x) kmem_free(kmem_map, (vm_offset_t)(x), \
sizeof(*(x)))
+# define KFREES(x,s) kmem_free(kmem_map, (vm_offset_t)(x), (s))
*/
# ifdef M_PFIL
# define KMALLOC(a, b, c) MALLOC((a), b, (c), M_PFIL, M_NOWAIT)
# define KFREE(x) FREE((x), M_PFIL)
+# define KFREES(x,s) FREE((x), M_PFIL)
# else
# define KMALLOC(a, b, c) MALLOC((a), b, (c), M_TEMP, M_NOWAIT)
# define KFREE(x) FREE((x), M_TEMP)
+# define KFREES(x,s) FREE((x), M_TEMP)
# endif
# define UIOMOVE(a,b,c,d) uiomove(a,b,d)
# define SLEEP(id, n) tsleep((id), PPAUSE|PCATCH, n, 0)
@@ -238,7 +260,9 @@ extern vm_map_t kmem_map;
# define SPLX(x) (void) splx(x)
# endif
# endif
+# define PANIC(x,y) if (x) panic y
#else
+# define PANIC(x,y) ;
# define MUTEX_ENTER(x) ;
# define MUTEX_EXIT(x) ;
# define SPLNET(x) ;
@@ -246,6 +270,7 @@ extern vm_map_t kmem_map;
# define SPLX(x) ;
# define KMALLOC(a,b,c) (a) = (b)malloc(c)
# define KFREE(x) free(x)
+# define KFREES(x,s) free(x)
# define GETUNIT(x) get_unit(x)
# define IRCOPY(a,b,c) bcopy((a), (b), (c))
# define IWCOPY(a,b,c) bcopy((a), (b), (c))
@@ -365,6 +390,7 @@ struct ipovly {
# define KMALLOC(a,b,c) (a) = (b)kmalloc((c), GFP_ATOMIC)
# define KFREE(x) kfree_s((x), sizeof(*(x)))
+# define KFREES(x,s) kfree_s((x), (s))
# define IRCOPY(a,b,c) { \
error = verify_area(VERIFY_READ, \
(b) ,sizeof((b))); \
diff --git a/sys/netinet/ip_fil.c b/sys/netinet/ip_fil.c
index a9c298aedc5b..b79c030bb822 100644
--- a/sys/netinet/ip_fil.c
+++ b/sys/netinet/ip_fil.c
@@ -1,5 +1,5 @@
/*
- * (C)opyright 1993,1994,1995 by Darren Reed.
+ * (C)opyright 1993-1997 by Darren Reed.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and due credit is given
@@ -7,7 +7,7 @@
*/
#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-1995 Darren Reed";
-static char rcsid[] = "$Id: ip_fil.c,v 1.1.1.3 1997/04/03 10:10:52 darrenr Exp $";
+static char rcsid[] = "$Id: ip_fil.c,v 2.0.2.12 1997/05/24 07:39:56 darrenr Exp $";
#endif
#ifndef SOLARIS
@@ -15,7 +15,14 @@ static char rcsid[] = "$Id: ip_fil.c,v 1.1.1.3 1997/04/03 10:10:52 darrenr Exp $
#endif
#ifdef __FreeBSD__
-#include <osreldate.h>
+# if defined(KERNEL) && !defined(_KERNEL)
+# define _KERNEL
+# endif
+# if defined(_KERNEL) && !defined(IPFILTER_LKM)
+# include <sys/osreldate.h>
+# else
+# include <osreldate.h>
+# endif
#endif
#ifndef _KERNEL
#include <stdio.h>
@@ -25,7 +32,12 @@ static char rcsid[] = "$Id: ip_fil.c,v 1.1.1.3 1997/04/03 10:10:52 darrenr Exp $
#include <sys/types.h>
#include <sys/param.h>
#include <sys/file.h>
-#include <sys/ioctl.h>
+#if __FreeBSD_version >= 220000 && defined(_KERNEL)
+# include <sys/fcntl.h>
+# include <sys/filio.h>
+#else
+# include <sys/ioctl.h>
+#endif
#include <sys/time.h>
#ifdef _KERNEL
#include <sys/systm.h>
@@ -35,9 +47,6 @@ static char rcsid[] = "$Id: ip_fil.c,v 1.1.1.3 1997/04/03 10:10:52 darrenr Exp $
#include <sys/dir.h>
#include <sys/mbuf.h>
#else
-#define bcmp memcmp
-#define bzero(a,b) memset(a,0,b)
-#define bcopy(a,b,c) memcpy(b,a,c)
#include <sys/filio.h>
#endif
#include <sys/protosw.h>
@@ -47,6 +56,9 @@ static char rcsid[] = "$Id: ip_fil.c,v 1.1.1.3 1997/04/03 10:10:52 darrenr Exp $
#ifdef sun
#include <net/af.h>
#endif
+#if __FreeBSD_version >= 300000
+# include <net/if_var.h>
+#endif
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
@@ -57,17 +69,23 @@ static char rcsid[] = "$Id: ip_fil.c,v 1.1.1.3 1997/04/03 10:10:52 darrenr Exp $
#include <netinet/udp.h>
#include <netinet/tcpip.h>
#include <netinet/ip_icmp.h>
-#include <syslog.h>
-#include "ip_compat.h"
-#include "ip_fil.h"
-#include "ip_frag.h"
-#include "ip_nat.h"
-#include "ip_state.h"
+#ifndef _KERNEL
+# include <syslog.h>
+#endif
+#include "netinet/ip_compat.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"
#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
+#if !SOLARIS && defined(_KERNEL)
+extern int ip_optcopy __P((struct ip *, struct ip *));
+#endif
+
-extern fr_flags, fr_active;
extern struct protosw inetsw[];
#if BSD < 199306
static int (*fr_saveslowtimo) __P((void));
@@ -139,6 +157,7 @@ char *s;
int iplattach()
{
+ char *defpass;
int s, i;
SPLNET(s);
@@ -157,11 +176,21 @@ int iplattach()
/*
* Set log buffer pointers for each of the log buffers
*/
+#ifdef IPFILTER_LOG
for (i = 0; i <= 2; i++) {
iplh[i] = iplbuf[i];
iplt[i] = iplbuf[i];
}
+#endif
SPLX(s);
+ if (fr_pass & FR_PASS)
+ defpass = "pass";
+ else if (fr_pass & FR_BLOCK)
+ defpass = "block";
+ else
+ defpass = "no-match -> block";
+
+ printf("IP Filter: initialized. Default = %s all\n", defpass);
return 0;
}
@@ -258,7 +287,8 @@ caddr_t data;
* Filter ioctl interface.
*/
int iplioctl(dev, cmd, data, mode
-#if ((_BSDI_VERSION >= 199510) || (BSD >= 199506)) && defined(_KERNEL)
+#if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \
+ (__FreeBSD_version >= 220000)) && defined(_KERNEL)
, p)
struct proc *p;
#else
@@ -278,10 +308,21 @@ int mode;
#endif
SPLNET(s);
+
+ if (unit == IPL_LOGNAT) {
+ error = nat_ioctl(data, cmd, mode);
+ SPLX(s);
+ return error;
+ }
+ if (unit == IPL_LOGSTATE) {
+ error = fr_state_ioctl(data, cmd, mode);
+ SPLX(s);
+ return error;
+ }
switch (cmd) {
case FIONREAD :
#ifdef IPFILTER_LOG
- *(int *)data = iplused[unit];
+ *(int *)data = iplused[IPL_LOGIPF];
#endif
break;
#if !defined(IPFILTER_LKM) && defined(_KERNEL)
@@ -373,24 +414,13 @@ int mode;
else {
*(int *)data = iplused[unit];
iplh[unit] = iplt[unit] = iplbuf[unit];
- iplused[unit] = 0;
+ iplused[unix] = 0;
}
break;
#endif /* IPFILTER_LOG */
- case SIOCADNAT :
- case SIOCRMNAT :
- case SIOCGNATS :
- case SIOCGNATL :
- case SIOCFLNAT :
- case SIOCCNATL :
- error = nat_ioctl(data, cmd, mode);
- break;
case SIOCGFRST :
IWCOPY((caddr_t)ipfr_fragstats(), data, sizeof(ipfrstat_t));
break;
- case SIOCGIPST :
- IWCOPY((caddr_t)fr_statetstats(), data, sizeof(ips_stat_t));
- break;
default :
error = EINVAL;
break;
@@ -508,7 +538,8 @@ caddr_t data;
* routines below for saving IP headers to buffer
*/
int iplopen(dev, flags
-#if ((_BSDI_VERSION >= 199510) || (BSD >= 199506)) && defined(_KERNEL)
+#if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \
+ (__FreeBSD_version >= 220000)) && defined(_KERNEL)
, devtype, p)
int devtype;
struct proc *p;
@@ -529,7 +560,8 @@ int flags;
int iplclose(dev, flags
-#if ((_BSDI_VERSION >= 199510) || (BSD >= 199506)) && defined(_KERNEL)
+#if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \
+ (__FreeBSD_version >= 220000)) && defined(_KERNEL)
, devtype, p)
int devtype;
struct proc *p;
@@ -699,6 +731,9 @@ struct tcpiphdr *ti;
struct tcphdr *tcp;
struct mbuf *m;
int tlen = 0;
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
+ struct route ro;
+#endif
if (ti->ti_flags & TH_RST)
return -1; /* feedback loop */
@@ -710,6 +745,8 @@ struct tcpiphdr *ti;
# endif
if (m == NULL)
return -1;
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
+#endif
if (ti->ti_flags & TH_SYN)
tlen = 1;
@@ -743,18 +780,29 @@ struct tcpiphdr *ti;
ip->ip_ttl = ip_defttl;
# endif
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
+ bzero((char *)&ro, sizeof(ro));
+ (void) ip_output(m, (struct mbuf *)0, &ro, 0, 0);
+ if (ro.ro_rt)
+ RTFREE(ro.ro_rt);
+#else
/*
* extra 0 in case of multicast
*/
(void) ip_output(m, (struct mbuf *)0, 0, 0, 0);
+#endif
return 0;
}
-# ifndef IPFILTER_LKM
+# if !defined(IPFILTER_LKM) && !(__FreeBSD_version >= 300000)
# if BSD < 199306
+int iplinit __P((void));
+
int
# else
+void iplinit __P((void));
+
void
# endif
iplinit()
diff --git a/sys/netinet/ip_fil.h b/sys/netinet/ip_fil.h
index 4f0bfa98d09d..661e109f407e 100644
--- a/sys/netinet/ip_fil.h
+++ b/sys/netinet/ip_fil.h
@@ -1,12 +1,12 @@
/*
- * (C)opyright 1993-1996 by Darren Reed.
+ * (C)opyright 1993-1997 by Darren Reed.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and due credit is given
* to the original author and the contributors.
*
* @(#)ip_fil.h 1.35 6/5/96
- * $Id: ip_fil.h,v 1.1.1.2 1997/04/03 10:10:58 darrenr Exp $
+ * $Id: ip_fil.h,v 2.0.2.13 1997/05/24 07:41:55 darrenr Exp $
*/
#ifndef __IP_FIL_H__
@@ -97,6 +97,7 @@ typedef struct fr_info {
u_short fin_dlen;
char *fin_dp; /* start of data past IP header */
struct frentry *fin_fr;
+ void *fin_mp;
} fr_info_t;
#define FI_CSIZE (sizeof(struct fr_ip) + 11)
@@ -179,16 +180,18 @@ typedef struct frentry {
#define FR_CALLNOW 0x10000 /* call another function (fr_func) if matches */
#define FR_DUP 0x20000 /* duplicate packet */
#define FR_LOGORBLOCK 0x40000 /* block the packet if it can't be logged */
+#define FR_NOTSRCIP 0x80000 /* not the src IP# */
+#define FR_NOTDSTIP 0x100000 /* not the dst IP# */
#define FR_LOGMASK (FR_LOG|FR_LOGP|FR_LOGB)
/*
* recognized flags for SIOCGETFF and SIOCSETFF
*/
-#define FF_LOGPASS 0x100000
-#define FF_LOGBLOCK 0x200000
-#define FF_LOGNOMATCH 0x400000
+#define FF_LOGPASS 0x10000000
+#define FF_LOGBLOCK 0x20000000
+#define FF_LOGNOMATCH 0x40000000
#define FF_LOGGING (FF_LOGPASS|FF_LOGBLOCK|FF_LOGNOMATCH)
-#define FF_BLOCKNONIP 0x800000 /* Solaris2 Only */
+#define FF_BLOCKNONIP 0x80000000 /* Solaris2 Only */
#define FR_NONE 0
#define FR_EQUAL 1
@@ -257,9 +260,9 @@ typedef struct ipl_ci {
u_long flags;
u_char ifname[IFNAMSIZ]; /* = 32 bytes */
#else
- u_long flags:24;
- u_long unit:8;
- u_char ifname[4]; /* = 20 bytes */
+ u_long flags;
+ u_int unit;
+ u_char ifname[4]; /* = 24 bytes */
#endif
} ipl_ci_t;
@@ -268,6 +271,13 @@ typedef struct ipl_ci {
#define ICMP_UNREACH_FILTER 13
#endif
+#ifndef IPF_LOGGING
+#define IPF_LOGGING 0
+#endif
+#ifndef IPF_DEFAULT_PASS
+#define IPF_DEFAULT_PASS 0
+#endif
+
#define IPMINLEN(i, h) ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h)))
#define IPLLOGSIZE 8192
@@ -301,7 +311,12 @@ extern int send_reset __P((struct ip *, struct ifnet *));
extern int icmp_error __P((struct ip *, struct ifnet *));
extern void ipllog __P((void));
extern void ipfr_fastroute __P((struct ip *, fr_info_t *, frdest_t *));
-#else
+extern int iplioctl __P((dev_t, int, caddr_t, int));
+extern int iplopen __P((dev_t, int));
+extern int iplclose __P((dev_t, int));
+#else /* #ifndef _KERNEL */
+extern int iplattach __P((void));
+extern int ipldetach __P((void));
# if SOLARIS
extern int fr_check __P((struct ip *, int, struct ifnet *, int, qif_t *,
queue_t *, mblk_t **));
@@ -309,33 +324,6 @@ extern int (*fr_checkp) __P((struct ip *, int, struct ifnet *,
int, qif_t *, queue_t *, mblk_t *));
extern int icmp_error __P((queue_t *, ip_t *, int, int, qif_t *,
struct in_addr));
-# else
-extern int fr_check __P((struct ip *, int, struct ifnet *, int,
- struct mbuf **));
-extern int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int,
- struct mbuf **));
-extern int send_reset __P((struct tcpiphdr *));
-extern int ipllog __P((u_int, int, struct ip *, fr_info_t *, struct mbuf *));
-extern void ipfr_fastroute __P((struct mbuf *, fr_info_t *, frdest_t *));
-# endif
-#endif
-extern int fr_copytolog __P((int, char *, int));
-extern int ipl_unreach;
-extern fr_info_t frcache[];
-extern char *iplh[3], *iplt[3];
-extern char iplbuf[3][IPLLOGSIZE];
-extern int iplused[3];
-extern struct frentry *ipfilter[2][2], *ipacct[2][2];
-extern struct filterstats frstats[];
-
-#ifndef _KERNEL
-extern int iplioctl __P((dev_t, int, caddr_t, int));
-extern int iplopen __P((dev_t, int));
-extern int iplclose __P((dev_t, int));
-#else
-extern int iplattach __P((void));
-extern int ipldetach __P((void));
-# if SOLARIS
extern int iplioctl __P((dev_t, int, int, int, cred_t *, int *));
extern int iplopen __P((dev_t *, int, int, cred_t *));
extern int iplclose __P((dev_t, int, int, cred_t *));
@@ -343,11 +331,21 @@ extern int ipfsync __P((void));
# ifdef IPFILTER_LOG
extern int iplread __P((dev_t, struct uio *, cred_t *));
# endif
-# else
+extern u_short fr_tcpsum __P((mblk_t *, ip_t *, tcphdr_t *));
+# else /* SOLARIS */
+extern int fr_check __P((struct ip *, int, struct ifnet *, int,
+ struct mbuf **));
+extern int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int,
+ struct mbuf **));
+extern int send_reset __P((struct tcpiphdr *));
+extern int ipllog __P((u_int, int, struct ip *, fr_info_t *, struct mbuf *));
+extern void ipfr_fastroute __P((struct mbuf *, fr_info_t *, frdest_t *));
# ifdef IPFILTER_LKM
extern int iplidentify __P((char *));
# endif
-# if (_BSDI_VERSION >= 199510) || (__FreeBSD_version >= 199612)
+extern u_short fr_tcpsum __P((struct mbuf *, ip_t *, tcphdr_t *));
+# if (_BSDI_VERSION >= 199510) || (__FreeBSD_version >= 220000) || \
+ (NetBSD >= 199511)
extern int iplioctl __P((dev_t, int, caddr_t, int, struct proc *));
extern int iplopen __P((dev_t, int, int, struct proc *));
extern int iplclose __P((dev_t, int, int, struct proc *));
@@ -366,5 +364,18 @@ extern int iplread __P((dev_t, struct uio *));
# define iplread noread
# endif /* IPFILTER_LOG */
# endif /* SOLARIS */
-#endif /* _KERNEL */
+#endif /* #ifndef _KERNEL */
+extern u_short ipf_cksum __P((u_short *, int));
+extern int fr_copytolog __P((int, char *, int));
+extern int ipl_unreach;
+extern int ipl_inited;
+extern int fr_pass;
+extern int fr_flags;
+extern int fr_active;
+extern fr_info_t frcache[];
+extern char *iplh[3], *iplt[3];
+extern char iplbuf[3][IPLLOGSIZE];
+extern int iplused[3];
+extern struct frentry *ipfilter[2][2], *ipacct[2][2];
+extern struct filterstats frstats[];
#endif /* __IP_FIL_H__ */
diff --git a/sys/netinet/ip_frag.c b/sys/netinet/ip_frag.c
index dbe852e9cd82..9b9bce35e7eb 100644
--- a/sys/netinet/ip_frag.c
+++ b/sys/netinet/ip_frag.c
@@ -7,7 +7,7 @@
*/
#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-1995 Darren Reed";
-static char rcsid[] = "$Id: ip_frag.c,v 1.1.1.3 1997/04/03 10:11:03 darrenr Exp $";
+static char rcsid[] = "$Id: ip_frag.c,v 2.0.2.10 1997/05/24 07:36:23 darrenr Exp $";
#endif
#if !defined(_KERNEL) && !defined(KERNEL)
@@ -19,8 +19,7 @@ static char rcsid[] = "$Id: ip_frag.c,v 1.1.1.3 1997/04/03 10:11:03 darrenr Exp
#include <sys/param.h>
#include <sys/time.h>
#include <sys/file.h>
-#if defined(__FreeBSD__) && (__FreeBSD__ >= 3)
-#include <sys/ioccom.h>
+#if defined(KERNEL) && (__FreeBSD_version >= 220000)
#include <sys/filio.h>
#include <sys/fcntl.h>
#else
@@ -54,39 +53,36 @@ static char rcsid[] = "$Id: ip_frag.c,v 1.1.1.3 1997/04/03 10:11:03 darrenr Exp
#include <netinet/udp.h>
#include <netinet/tcpip.h>
#include <netinet/ip_icmp.h>
-#include "ip_compat.h"
-#include "ip_fil.h"
-#include "ip_frag.h"
-#include "ip_nat.h"
-#include "ip_state.h"
+#include "netinet/ip_compat.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"
ipfr_t *ipfr_heads[IPFT_SIZE];
+ipfr_t *ipfr_nattab[IPFT_SIZE];
ipfrstat_t ipfr_stats;
u_long ipfr_inuse = 0,
fr_ipfrttl = 120; /* 60 seconds */
#ifdef _KERNEL
extern int ipfr_timer_id;
#endif
-#if SOLARIS
-# ifdef _KERNEL
+#if SOLARIS && defined(_KERNEL)
extern kmutex_t ipf_frag;
-# else
-#define bcmp(a,b,c) memcmp(a,b,c)
-#define bcopy(a,b,c) memmove(b,a,c)
-# endif
+extern kmutex_t ipf_natfrag;
+extern kmutex_t ipf_nat;
#endif
-#ifdef __FreeBSD__
-# if BSD < 199306
-int ipfr_slowtimer __P((void));
-# else
-void ipfr_slowtimer __P((void));
-# endif
-#endif /* __FreeBSD__ */
+
+static ipfr_t *ipfr_new __P((ip_t *, fr_info_t *, int, ipfr_t **));
+static ipfr_t *ipfr_lookup __P((ip_t *, fr_info_t *, ipfr_t **));
+
ipfrstat_t *ipfr_fragstats()
{
ipfr_stats.ifs_table = ipfr_heads;
+ ipfr_stats.ifs_nattab = ipfr_nattab;
ipfr_stats.ifs_inuse = ipfr_inuse;
return &ipfr_stats;
}
@@ -96,10 +92,11 @@ ipfrstat_t *ipfr_fragstats()
* add a new entry to the fragment cache, registering it as having come
* through this box, with the result of the filter operation.
*/
-int ipfr_newfrag(ip, fin, pass)
+static ipfr_t *ipfr_new(ip, fin, pass, table)
ip_t *ip;
fr_info_t *fin;
int pass;
+ipfr_t *table[];
{
ipfr_t **fp, *fr, frag;
u_int idx;
@@ -119,33 +116,77 @@ int pass;
/*
* first, make sure it isn't already there...
*/
- MUTEX_ENTER(&ipf_frag);
- for (fp = &ipfr_heads[idx]; (fr = *fp); fp = &fr->ipfr_next)
+ for (fp = &table[idx]; (fr = *fp); fp = &fr->ipfr_next)
if (!bcmp((char *)&frag.ipfr_src, (char *)&fr->ipfr_src,
IPFR_CMPSZ)) {
ipfr_stats.ifs_exists++;
MUTEX_EXIT(&ipf_frag);
- return -1;
+ return NULL;
}
+ /*
+ * allocate some memory, if possible, if not, just record that we
+ * failed to do so.
+ */
KMALLOC(fr, ipfr_t *, sizeof(*fr));
if (fr == NULL) {
ipfr_stats.ifs_nomem++;
MUTEX_EXIT(&ipf_frag);
- return -1;
+ return NULL;
}
- if ((fr->ipfr_next = ipfr_heads[idx]))
- ipfr_heads[idx]->ipfr_prev = fr;
+
+ /*
+ * Instert the fragment into the fragment table, copy the struct used
+ * in the search using bcopy rather than reassign each field.
+ * Set the ttl to the default and mask out logging from "pass"
+ */
+ if ((fr->ipfr_next = table[idx]))
+ table[idx]->ipfr_prev = fr;
fr->ipfr_prev = NULL;
- ipfr_heads[idx] = fr;
+ fr->ipfr_data = NULL;
+ table[idx] = fr;
bcopy((char *)&frag.ipfr_src, (char *)&fr->ipfr_src, IPFR_CMPSZ);
fr->ipfr_ttl = fr_ipfrttl;
fr->ipfr_pass = pass & ~(FR_LOGFIRST|FR_LOG);
+ /*
+ * Compute the offset of the expected start of the next packet.
+ */
fr->ipfr_off = (ip->ip_off & 0x1fff) + (fin->fin_dlen >> 3);
ipfr_stats.ifs_new++;
ipfr_inuse++;
+ return fr;
+}
+
+
+int ipfr_newfrag(ip, fin, pass)
+ip_t *ip;
+fr_info_t *fin;
+int pass;
+{
+ ipfr_t *ipf;
+
+ MUTEX_ENTER(&ipf_frag);
+ ipf = ipfr_new(ip, fin, pass, ipfr_heads);
MUTEX_EXIT(&ipf_frag);
- return 0;
+ return ipf ? 0 : -1;
+}
+
+
+int ipfr_nat_newfrag(ip, fin, pass, nat)
+ip_t *ip;
+fr_info_t *fin;
+int pass;
+nat_t *nat;
+{
+ ipfr_t *ipf;
+
+ MUTEX_ENTER(&ipf_natfrag);
+ if ((ipf = ipfr_new(ip, fin, pass, ipfr_nattab))) {
+ ipf->ipfr_data = nat;
+ nat->nat_frag = ipf;
+ }
+ MUTEX_EXIT(&ipf_natfrag);
+ return ipf ? 0 : -1;
}
@@ -153,9 +194,10 @@ int pass;
* check the fragment cache to see if there is already a record of this packet
* with its filter result known.
*/
-int ipfr_knownfrag(ip, fin)
+static ipfr_t *ipfr_lookup(ip, fin, table)
ip_t *ip;
fr_info_t *fin;
+ipfr_t *table[];
{
ipfr_t *f, frag;
u_int idx;
@@ -164,6 +206,8 @@ fr_info_t *fin;
/*
* For fragments, we record protocol, packet id, TOS and both IP#'s
* (these should all be the same for all fragments of a packet).
+ *
+ * build up a hash value to index the table with.
*/
frag.ipfr_p = ip->ip_p;
idx = ip->ip_p;
@@ -177,25 +221,26 @@ fr_info_t *fin;
idx *= 127;
idx %= IPFT_SIZE;
- MUTEX_ENTER(&ipf_frag);
- for (f = ipfr_heads[idx]; f; f = f->ipfr_next)
+ /*
+ * check the table, careful to only compare the right amount of data
+ */
+ for (f = table[idx]; f; f = f->ipfr_next)
if (!bcmp((char *)&frag.ipfr_src, (char *)&f->ipfr_src,
IPFR_CMPSZ)) {
u_short atoff, off;
- if (f != ipfr_heads[idx]) {
+ if (f != table[idx]) {
/*
* move fragment info. to the top of the list
* to speed up searches.
*/
if ((f->ipfr_prev->ipfr_next = f->ipfr_next))
f->ipfr_next->ipfr_prev = f->ipfr_prev;
- f->ipfr_next = ipfr_heads[idx];
- ipfr_heads[idx]->ipfr_prev = f;
+ f->ipfr_next = table[idx];
+ table[idx]->ipfr_prev = f;
f->ipfr_prev = NULL;
- ipfr_heads[idx] = f;
+ table[idx] = f;
}
- ret = f->ipfr_pass;
off = ip->ip_off;
atoff = (off & 0x1fff) - (fin->fin_dlen >> 3);
/*
@@ -209,11 +254,45 @@ fr_info_t *fin;
f->ipfr_off = off;
}
ipfr_stats.ifs_hits++;
- MUTEX_EXIT(&ipf_frag);
- return ret;
+ return f;
}
+ return NULL;
+}
+
+
+/*
+ * functional interface for normal lookups of the fragment cache
+ */
+nat_t *ipfr_nat_knownfrag(ip, fin)
+ip_t *ip;
+fr_info_t *fin;
+{
+ nat_t *nat;
+ ipfr_t *ipf;
+
+ MUTEX_ENTER(&ipf_natfrag);
+ ipf = ipfr_lookup(ip, fin, ipfr_heads);
+ nat = ipf ? ipf->ipfr_data : NULL;
+ MUTEX_EXIT(&ipf_natfrag);
+ return nat;
+}
+
+
+/*
+ * functional interface for NAT lookups of the NAT fragment cache
+ */
+int ipfr_knownfrag(ip, fin)
+ip_t *ip;
+fr_info_t *fin;
+{
+ int ret;
+ ipfr_t *ipf;
+
+ MUTEX_ENTER(&ipf_frag);
+ ipf = ipfr_lookup(ip, fin, ipfr_heads);
+ ret = ipf ? ipf->ipfr_pass : 0;
MUTEX_EXIT(&ipf_frag);
- return 0;
+ return ret;
}
@@ -223,20 +302,35 @@ fr_info_t *fin;
void ipfr_unload()
{
ipfr_t **fp, *fr;
+ nat_t *nat;
int idx;
#if !SOLARIS && defined(_KERNEL)
int s;
#endif
- MUTEX_ENTER(&ipf_frag);
SPLNET(s);
+ MUTEX_ENTER(&ipf_frag);
for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
for (fp = &ipfr_heads[idx]; (fr = *fp); ) {
*fp = fr->ipfr_next;
KFREE(fr);
}
- SPLX(s);
MUTEX_EXIT(&ipf_frag);
+
+ MUTEX_ENTER(&ipf_nat);
+ MUTEX_ENTER(&ipf_natfrag);
+ for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
+ for (fp = &ipfr_nattab[idx]; (fr = *fp); ) {
+ *fp = fr->ipfr_next;
+ if ((nat = (nat_t *)fr->ipfr_data)) {
+ if (nat->nat_frag == fr)
+ nat->nat_frag = NULL;
+ }
+ KFREE(fr);
+ }
+ MUTEX_EXIT(&ipf_natfrag);
+ MUTEX_EXIT(&ipf_nat);
+ SPLX(s);
}
@@ -252,11 +346,17 @@ int ipfr_slowtimer()
# endif
{
ipfr_t **fp, *fr;
+ nat_t *nat;
int s, idx;
MUTEX_ENTER(&ipf_frag);
SPLNET(s);
+ /*
+ * Go through the entire table, looking for entries to expire,
+ * decreasing the ttl by one for each entry. If it reaches 0,
+ * remove it from the chain and free it.
+ */
for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
for (fp = &ipfr_heads[idx]; (fr = *fp); ) {
--fr->ipfr_ttl;
@@ -274,12 +374,45 @@ int ipfr_slowtimer()
} else
fp = &fr->ipfr_next;
}
+ MUTEX_EXIT(&ipf_frag);
+
+ /*
+ * Same again for the NAT table, except that if the structure also
+ * still points to a NAT structure, and the NAT structure points back
+ * at the one to be free'd, NULL the reference from the NAT struct.
+ * NOTE: We need to grab both mutex's early, and in this order so as
+ * to prevent a deadlock if both try to expire at the same time.
+ */
+ MUTEX_ENTER(&ipf_nat);
+ MUTEX_ENTER(&ipf_natfrag);
+ for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
+ for (fp = &ipfr_nattab[idx]; (fr = *fp); ) {
+ --fr->ipfr_ttl;
+ if (fr->ipfr_ttl == 0) {
+ if (fr->ipfr_prev)
+ fr->ipfr_prev->ipfr_next =
+ fr->ipfr_next;
+ if (fr->ipfr_next)
+ fr->ipfr_next->ipfr_prev =
+ fr->ipfr_prev;
+ *fp = fr->ipfr_next;
+ ipfr_stats.ifs_expire++;
+ ipfr_inuse--;
+ if ((nat = (nat_t *)fr->ipfr_data)) {
+ if (nat->nat_frag == fr)
+ nat->nat_frag = NULL;
+ }
+ KFREE(fr);
+ } else
+ fp = &fr->ipfr_next;
+ }
+ MUTEX_EXIT(&ipf_natfrag);
+ MUTEX_EXIT(&ipf_nat);
SPLX(s);
# if SOLARIS
- MUTEX_EXIT(&ipf_frag);
fr_timeoutstate();
ip_natexpire();
- ipfr_timer_id = timeout(ipfr_slowtimer, NULL, HZ/2);
+ ipfr_timer_id = timeout(ipfr_slowtimer, NULL, drv_usectohz(500000));
# else
fr_timeoutstate();
ip_natexpire();
diff --git a/sys/netinet/ip_frag.h b/sys/netinet/ip_frag.h
index 0e8fe90ccc54..df275babb318 100644
--- a/sys/netinet/ip_frag.h
+++ b/sys/netinet/ip_frag.h
@@ -1,21 +1,22 @@
/*
- * (C)opyright 1993, 1994, 1995 by Darren Reed.
+ * (C)opyright 1993-1997 by Darren Reed.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and due credit is given
* to the original author and the contributors.
*
* @(#)ip_frag.h 1.5 3/24/96
- * $Id: ip_frag.h,v 1.1.1.2 1997/04/03 10:11:06 darrenr Exp $
+ * $Id: ip_frag.h,v 2.0.2.7 1997/05/08 10:10:18 darrenr Exp $
*/
-#ifndef __IP_FRAG_H_
+#ifndef __IP_FRAG_H__
#define __IP_FRAG_H__
#define IPFT_SIZE 257
typedef struct ipfr {
struct ipfr *ipfr_next, *ipfr_prev;
+ void *ipfr_data;
struct in_addr ipfr_src;
struct in_addr ipfr_dst;
u_short ipfr_id;
@@ -35,14 +36,18 @@ typedef struct ipfrstat {
u_long ifs_expire;
u_long ifs_inuse;
struct ipfr **ifs_table;
+ struct ipfr **ifs_nattab;
} ipfrstat_t;
#define IPFR_CMPSZ (4 + 4 + 2 + 1 + 1)
extern ipfrstat_t *ipfr_fragstats __P((void));
extern int ipfr_newfrag __P((ip_t *, fr_info_t *, int));
+extern int ipfr_nat_newfrag __P((ip_t *, fr_info_t *, int, struct nat *));
+extern nat_t *ipfr_nat_knownfrag __P((ip_t *, fr_info_t *));
extern int ipfr_knownfrag __P((ip_t *, fr_info_t *));
extern void ipfr_unload __P((void));
+
#if (BSD >= 199306) || SOLARIS
extern void ipfr_slowtimer __P((void));
#else
diff --git a/sys/netinet/ip_ftp_pxy.c b/sys/netinet/ip_ftp_pxy.c
new file mode 100644
index 000000000000..48196e97fd0f
--- /dev/null
+++ b/sys/netinet/ip_ftp_pxy.c
@@ -0,0 +1,204 @@
+/*
+ * Simple FTP transparent proxy for in-kernel.
+ */
+
+#define isdigit(x) ((x) >= '0' && (x) <= '9')
+
+#define IPF_FTP_PROXY
+
+#define IPF_MINPORTLEN 18
+#define IPF_MAXPORTLEN 30
+
+
+int ippr_ftp_init(fin, ip, tcp, aps, nat)
+fr_info_t *fin;
+ip_t *ip;
+tcphdr_t *tcp;
+ap_session_t *aps;
+nat_t *nat;
+{
+ aps->aps_sport = tcp->th_sport;
+ aps->aps_dport = tcp->th_dport;
+ return 0;
+}
+
+
+int ippr_ftp_in(fin, ip, tcp, aps, nat)
+fr_info_t *fin;
+ip_t *ip;
+tcphdr_t *tcp;
+ap_session_t *aps;
+nat_t *nat;
+{
+ int ch = 0;
+ u_long sum1, sum2;
+
+ if (tcp->th_dport != aps->aps_dport) {
+ sum2 = (u_long)ntohl(tcp->th_ack);
+ if (aps->aps_seqoff && (sum2 > aps->aps_after)) {
+ sum1 = (u_long)aps->aps_seqoff;
+ tcp->th_ack = htonl(sum2 - sum1);
+ return 2;
+ }
+ }
+ return 0;
+}
+
+
+u_short ipf_ftp_atoi(ptr)
+char **ptr;
+{
+ register char *s = *ptr, c;
+ register u_char i = 0, j = 0;
+
+ while ((c = *s++) && isdigit(c)) {
+ i *= 10;
+ i += c - '0';
+ }
+ if (c != ',') {
+ *ptr = NULL;
+ return 0;
+ }
+ while ((c = *s++) && isdigit(c)) {
+ j *= 10;
+ j += c - '0';
+ }
+ *ptr = s;
+ return (i << 8) | j;
+}
+
+
+int ippr_ftp_out(fin, ip, tcp, aps, nat)
+fr_info_t *fin;
+ip_t *ip;
+tcphdr_t *tcp;
+ap_session_t *aps;
+nat_t *nat;
+{
+ register u_long sum1, sum2, sumd;
+ char newbuf[IPF_MAXPORTLEN+1];
+ char portbuf[IPF_MAXPORTLEN+1], *s, c;
+ int ch = 0, off = (ip->ip_hl << 2) + (tcp->th_off << 2), len;
+ u_int a1, a2, a3, a4;
+ u_short a5, a6;
+ int olen, dlen, nlen, inc = 0, blen;
+ tcphdr_t tcph, *tcp2 = &tcph;
+ void *savep;
+ nat_t *ipn;
+ struct in_addr swip;
+#if SOLARIS
+ mblk_t *m1, *m = *(mblk_t **)fin->fin_mp;
+
+ dlen = m->b_wptr - m->b_rptr - off;
+ blen = m->b_datap->db_lim - m->b_datap->db_base;
+ bzero(portbuf, sizeof(portbuf));
+ copyout_mblk(m, off, portbuf, MIN(sizeof(portbuf), dlen));
+#else
+ struct mbuf *m1, *m = *(struct mbuf **)fin->fin_mp;
+
+ dlen = m->m_len - off;
+# if BSD >= 199306
+ blen = (MLEN - m->m_len) - (m->m_data - m->m_dat);
+# else
+ blen = (MLEN - m->m_len) - m->m_off;
+# endif
+ if (blen < 0)
+ panic("blen < 0 - size of mblk/mbuf wrong");
+ bzero(portbuf, sizeof(portbuf));
+ m_copydata(m, off, MIN(sizeof(portbuf), dlen), portbuf);
+#endif
+ portbuf[IPF_MAXPORTLEN] = '\0';
+ len = MIN(32, dlen);
+
+ if ((len < IPF_MINPORTLEN) || strncmp(portbuf, "PORT ", 5))
+ goto adjust_seqack;
+
+ /*
+ * Skip the PORT command + space
+ */
+ s = portbuf + 5;
+ /*
+ * Pick out the address components, two at a time.
+ */
+ (void) ipf_ftp_atoi(&s);
+ if (!s)
+ goto adjust_seqack;
+ (void) ipf_ftp_atoi(&s);
+ if (!s)
+ goto adjust_seqack;
+ a5 = ipf_ftp_atoi(&s);
+ if (!s)
+ goto adjust_seqack;
+ /*
+ * check for CR-LF at the end.
+ */
+ if (*s != '\n' || *(s - 1) != '\r')
+ goto adjust_seqack;
+ a6 = a5 & 0xff;
+ a5 >>= 8;
+ /*
+ * Calculate new address parts for PORT command
+ */
+ a1 = ntohl(ip->ip_src.s_addr);
+ a2 = (a1 >> 16) & 0xff;
+ a3 = (a1 >> 8) & 0xff;
+ a4 = a1 & 0xff;
+ a1 >>= 24;
+ olen = s - portbuf + 1;
+ (void) sprintf(newbuf, "PORT %d,%d,%d,%d,%d,%d\r\n",
+ a1, a2, a3, a4, a5, a6);
+ nlen = strlen(newbuf);
+ inc = nlen - olen;
+ if (tcp->th_seq > aps->aps_after) {
+ aps->aps_after = ntohl(tcp->th_seq) + dlen;
+ aps->aps_seqoff += inc;
+ }
+#if SOLARIS
+ if (inc && dlen)
+ if ((inc < 0) || (blen >= dlen)) {
+ bcopy(m->b_rptr + off,
+ m->b_rptr + off + aps->aps_seqoff, dlen);
+ }
+ for (m1 = m; m1->b_cont; m1 = m1->b_cont)
+ ;
+ m1->b_wptr += inc;
+ copyin_mblk(m, off, newbuf, strlen(newbuf));
+#else
+ if (inc && dlen)
+ if ((inc < 0) || (blen >= dlen)) {
+ bcopy((char *)ip + off,
+ (char *)ip + off + aps->aps_seqoff, dlen);
+ }
+ m->m_len += inc;
+ m_copyback(m, off, nlen, newbuf);
+#endif
+ ip->ip_len += inc;
+ ch = 1;
+
+ /*
+ * Add skeleton NAT entry for connection which will come back the
+ * other way.
+ */
+ savep = fin->fin_dp;
+ fin->fin_dp = (char *)tcp2;
+ tcp2->th_sport = htons(a5 << 8 | a6);
+ tcp2->th_dport = htons(20);
+ swip = ip->ip_src;
+ ip->ip_src = nat->nat_inip;
+ if ((ipn = nat_new(nat->nat_ptr, ip, fin, IPN_TCP, NAT_OUTBOUND)))
+ ipn->nat_age = fr_defnatage;
+ ip->ip_src = swip;
+ fin->fin_dp = (char *)savep;
+
+adjust_seqack:
+ if (tcp->th_dport == aps->aps_dport) {
+ sum2 = (u_long)ntohl(tcp->th_seq);
+ if (aps->aps_seqoff && (sum2 > aps->aps_after)) {
+ sum1 = (u_long)aps->aps_seqoff;
+ tcp->th_seq = htonl(sum2 + sum1);
+ ch = 1;
+ }
+ }
+
+ return ch ? 2 : 0;
+}
diff --git a/sys/netinet/ip_nat.c b/sys/netinet/ip_nat.c
index 146b4906c60d..3c9476fe68d2 100644
--- a/sys/netinet/ip_nat.c
+++ b/sys/netinet/ip_nat.c
@@ -9,10 +9,10 @@
*/
#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed";
-static char rcsid[] = "$Id: ip_nat.c,v 1.1.1.3 1997/04/03 10:11:11 darrenr Exp $";
+static char rcsid[] = "$Id: ip_nat.c,v 2.0.2.18 1997/05/24 07:34:44 darrenr Exp $";
#endif
-#if defined(__FreeBSD__) && defined(KERNEL)
+#if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL)
#define _KERNEL
#endif
@@ -26,7 +26,13 @@ static char rcsid[] = "$Id: ip_nat.c,v 1.1.1.3 1997/04/03 10:11:11 darrenr Exp $
#include <sys/param.h>
#include <sys/time.h>
#include <sys/file.h>
-#include <sys/ioctl.h>
+#if defined(KERNEL) && (__FreeBSD_version >= 220000)
+# include <sys/filio.h>
+# include <sys/fnctl.h>
+#else
+# include <sys/ioctl.h>
+#endif
+#include <sys/fcntl.h>
#include <sys/uio.h>
#include <sys/protosw.h>
#include <sys/socket.h>
@@ -36,13 +42,19 @@ static char rcsid[] = "$Id: ip_nat.c,v 1.1.1.3 1997/04/03 10:11:11 darrenr Exp $
#if !defined(__SVR4) && !defined(__svr4__)
# include <sys/mbuf.h>
#else
+# include <sys/filio.h>
# include <sys/byteorder.h>
# include <sys/dditypes.h>
# include <sys/stream.h>
# include <sys/kmem.h>
#endif
-
+#if __FreeBSD_version >= 300000
+# include <sys/queue.h>
+#endif
#include <net/if.h>
+#if __FreeBSD_version >= 300000
+# include <net/if_var.h>
+#endif
#ifdef sun
#include <net/af.h>
#endif
@@ -62,36 +74,30 @@ extern struct ifnet vpnif;
#include <netinet/udp.h>
#include <netinet/tcpip.h>
#include <netinet/ip_icmp.h>
-#include "ip_compat.h"
-#include "ip_fil.h"
-#include "ip_nat.h"
-#include "ip_state.h"
+#include "netinet/ip_compat.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"
#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
+#undef SOCKADDR_IN
+#define SOCKADDR_IN struct sockaddr_in
nat_t *nat_table[2][NAT_SIZE], *nat_instances = NULL;
ipnat_t *nat_list = NULL;
-u_long nat_inuse = 0,
- fr_defnatage = 1200;
+u_long fr_defnatage = 1200;
natstat_t nat_stats;
-#if SOLARIS
-# ifndef _KERNEL
-#define bzero(a,b) memset(a,0,b)
-#define bcmp(a,b,c) memcpy(a,b,c)
-#define bcopy(a,b,c) memmove(b,a,c)
-# else
+#if SOLARIS && defined(_KERNEL)
extern kmutex_t ipf_nat;
-# endif
+extern kmutex_t ipf_natfrag;
#endif
static int flush_nattable __P((void)), clear_natlist __P((void));
-static void nattable_sync __P((void)), nat_delete __P((struct nat *));
-static nat_t *nat_new __P((ipnat_t *, ip_t *, fr_info_t *, u_short, int));
-static void fix_outcksum __P((u_short *, u_long));
-static void fix_incksum __P((u_short *, u_long));
-static void fix_outcksum(sp, n)
+void fix_outcksum(sp, n)
u_short *sp;
u_long n;
{
@@ -112,7 +118,7 @@ u_long n;
}
-static void fix_incksum(sp, n)
+void fix_incksum(sp, n)
u_short *sp;
u_long n;
{
@@ -197,6 +203,7 @@ int cmd, mode;
}
IRCOPY((char *)data, (char *)n, sizeof(*n));
n->in_ifp = (void *)GETUNIT(n->in_ifname);
+ n->in_apr = ap_match(n->in_p, n->in_plabel);
n->in_next = *np;
n->in_use = 0;
n->in_space = ~(0xffffffff & ntohl(n->in_outmsk));
@@ -208,7 +215,7 @@ int cmd, mode;
n->in_nip = ntohl(n->in_outip) + 1;
else
n->in_nip = ntohl(n->in_outip);
- if (n->in_redir == NAT_MAP) {
+ if (n->in_redir & NAT_MAP) {
n->in_pnext = ntohs(n->in_pmin);
/*
* Multiply by the number of ports made available.
@@ -219,6 +226,7 @@ int cmd, mode;
}
/* Otherwise, these fields are preset */
*np = n;
+ nat_stats.ns_rules++;
break;
case SIOCRMNAT :
if (!(mode & FWRITE)) {
@@ -230,15 +238,20 @@ int cmd, mode;
break;
}
*np = n->in_next;
-
- KFREE(n);
- nattable_sync();
+ if (!n->in_use) {
+ if (n->in_apr)
+ ap_free(n->in_apr);
+ KFREE(n);
+ nat_stats.ns_rules--;
+ } else {
+ n->in_flags |= IPN_DELETE;
+ n->in_next = NULL;
+ }
break;
case SIOCGNATS :
nat_stats.ns_table[0] = nat_table[0];
nat_stats.ns_table[1] = nat_table[1];
nat_stats.ns_list = nat_list;
- nat_stats.ns_inuse = nat_inuse;
IWCOPY((char *)&nat_stats, (char *)data, sizeof(nat_stats));
break;
case SIOCGNATL :
@@ -269,6 +282,11 @@ int cmd, mode;
ret = clear_natlist();
IWCOPY((caddr_t)&ret, data, sizeof(ret));
break;
+ case FIONREAD :
+#ifdef IPFILTER_LOG
+ *(int *)data = iplused[IPL_LOGNAT];
+#endif
+ break;
}
SPLX(s);
MUTEX_EXIT(&ipf_nat);
@@ -280,6 +298,7 @@ static void nat_delete(natd)
struct nat *natd;
{
register struct nat **natp, *nat;
+ struct ipnat *ipn;
for (natp = natd->nat_hstart[0]; (nat = *natp);
natp = &nat->nat_hnext[0])
@@ -295,12 +314,21 @@ struct nat *natd;
break;
}
- if (natd->nat_ptr) {
- natd->nat_ptr->in_space++;
- natd->nat_ptr->in_use--;
+ if ((ipn = natd->nat_ptr)) {
+ ipn->in_space++;
+ ipn->in_use--;
+ if (!ipn->in_use && (ipn->in_flags & IPN_DELETE)) {
+ if (ipn->in_apr)
+ ap_free(ipn->in_apr);
+ KFREE(ipn);
+ nat_stats.ns_rules--;
+ }
}
+ MUTEX_ENTER(&ipf_natfrag);
+ if (nat->nat_frag && nat->nat_frag->ipfr_data == nat)
+ nat->nat_frag->ipfr_data = NULL;
+ MUTEX_EXIT(&ipf_natfrag);
KFREE(natd);
- nat_inuse--;
}
@@ -330,43 +358,27 @@ static int flush_nattable()
/*
- * I know this is O(N*M), but it can't be avoided.
- */
-static void nattable_sync()
-{
- register nat_t *nat;
- register ipnat_t *np;
- int i;
-
- for (i = NAT_SIZE - 1; i >= 0; i--)
- for (nat = nat_instances; nat; nat = nat->nat_next) {
- for (np = nat_list; np; np = np->in_next)
- if (nat->nat_ptr == np)
- break;
- /*
- * XXX - is it better to remove this if ? works the
- * same if it is just "nat->nat_ptr = np".
- */
- if (!np)
- nat->nat_ptr = NULL;
- }
-}
-
-
-/*
* clear_natlist - delete all entries in the active NAT mapping list.
*/
static int clear_natlist()
{
- register ipnat_t *n, **np;
+ register ipnat_t *n, **np = &nat_list;
int i = 0;
- for (np = &nat_list; (n = *np); i++) {
+ while ((n = *np)) {
*np = n->in_next;
- KFREE(n);
+ if (!n->in_use) {
+ if (n->in_apr)
+ ap_free(n->in_apr);
+ KFREE(n);
+ nat_stats.ns_rules--;
+ i++;
+ } else {
+ n->in_flags |= IPN_DELETE;
+ n->in_next = NULL;
+ }
}
-
- nattable_sync();
+ nat_stats.ns_inuse = 0;
return i;
}
@@ -374,7 +386,7 @@ static int clear_natlist()
/*
* Create a new NAT table entry.
*/
-static nat_t *nat_new(np, ip, fin, flags, direction)
+nat_t *nat_new(np, ip, fin, flags, direction)
ipnat_t *np;
ip_t *ip;
fr_info_t *fin;
@@ -426,15 +438,31 @@ int direction;
struct ifaddr *ifa;
struct sockaddr_in *sin;
+# if (__FreeBSD_version >= 300000)
+ ifa = TAILQ_FIRST(&ifp->if_addrhead);
+# else
+# ifdef __NetBSD__
+ ifa = ifp->if_addrlist.tqh_first;
+# else
ifa = ifp->if_addrlist;
+# endif
+# endif
# if BSD < 199306
- sin = (struct sockaddr_in *)&ifa->ifa_addr;
+ sin = (SOCKADDR_IN *)&ifa->ifa_addr;
# else
- sin = (struct sockaddr_in *)ifa->ifa_addr;
+ sin = (SOCKADDR_IN *)ifa->ifa_addr;
while (sin && ifa &&
sin->sin_family != AF_INET) {
+# if (__FreeBSD_version >= 300000)
+ ifa = TAILQ_NEXT(ifa, ifa_link);
+# else
+# ifdef __NetBSD__
+ ifa = ifa->ifa_list.tqe_next;
+# else
ifa = ifa->ifa_next;
- sin = (struct sockaddr_in *)ifa->ifa_addr;
+# endif
+# endif
+ sin = (SOCKADDR_IN *)ifa->ifa_addr;
}
if (!ifa)
sin = NULL;
@@ -465,7 +493,8 @@ int direction;
if ((np->in_nip & ntohl(np->in_outmsk)) >
ntohl(np->in_outip))
np->in_nip = ntohl(np->in_outip) + 1;
- } while (nat_inlookup(flags, ip->ip_dst, dport, in, port));
+ } while (nat_inlookup(fin->fin_ifp, flags, ip->ip_dst,
+ dport, in, port));
/* Setup the NAT table */
nat->nat_inip = ip->ip_src;
@@ -562,7 +591,10 @@ int direction;
nat->nat_hnext[1] = *natp;
*natp = nat;
nat->nat_ptr = np;
- np->in_use++;
+ nat->nat_bytes = 0;
+ nat->nat_pkts = 0;
+ nat->nat_ifp = fin->fin_ifp;
+ nat->nat_dir = direction;
if (direction == NAT_OUTBOUND) {
if (flags & IPN_TCPUDP)
tcp->th_sport = htons(port);
@@ -571,7 +603,8 @@ int direction;
tcp->th_dport = htons(nport);
}
nat_stats.ns_added++;
- nat_inuse++;
+ nat_stats.ns_inuse++;
+ np->in_use++;
return nat;
}
@@ -586,7 +619,8 @@ int direction;
* 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(flags, src, sport, mapdst, mapdport)
+nat_t *nat_inlookup(ifp, flags, src, sport, mapdst, mapdport)
+void *ifp;
register int flags;
struct in_addr src , mapdst;
u_short sport, mapdport;
@@ -597,7 +631,8 @@ u_short sport, mapdport;
nat = nat_table[1][mapdst.s_addr % NAT_SIZE];
for (; nat; nat = nat->nat_hnext[1])
- if (nat->nat_oip.s_addr == src.s_addr &&
+ if ((!ifp || ifp == nat->nat_ifp) &&
+ nat->nat_oip.s_addr == src.s_addr &&
nat->nat_outip.s_addr == mapdst.s_addr &&
flags == nat->nat_flags && (!flags ||
(nat->nat_oport == sport &&
@@ -613,7 +648,8 @@ u_short sport, mapdport;
* 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(flags, src, sport, dst, dport)
+nat_t *nat_outlookup(ifp, flags, src, sport, dst, dport)
+void *ifp;
register int flags;
struct in_addr src , dst;
u_short sport, dport;
@@ -624,7 +660,8 @@ u_short sport, dport;
nat = nat_table[0][src.s_addr % NAT_SIZE];
for (; nat; nat = nat->nat_hnext[0])
- if (nat->nat_inip.s_addr == src.s_addr &&
+ if ((!ifp || ifp == nat->nat_ifp) &&
+ nat->nat_inip.s_addr == src.s_addr &&
nat->nat_oip.s_addr == dst.s_addr &&
flags == nat->nat_flags && (!flags ||
(nat->nat_inport == sport && nat->nat_oport == dport)))
@@ -638,7 +675,8 @@ u_short sport, dport;
* real destination address/port. We use this lookup when sending a packet
* out, we're looking for a table entry, based on the source address.
*/
-nat_t *nat_lookupmapip(flags, mapsrc, mapsport, dst, dport)
+nat_t *nat_lookupmapip(ifp, flags, mapsrc, mapsport, dst, dport)
+void *ifp;
register int flags;
struct in_addr mapsrc , dst;
u_short mapsport, dport;
@@ -649,8 +687,9 @@ u_short mapsport, dport;
nat = nat_table[1][mapsrc.s_addr % NAT_SIZE];
for (; nat; nat = nat->nat_hnext[0])
- if (nat->nat_outip.s_addr == mapsrc.s_addr &&
+ if ((!ifp || ifp == nat->nat_ifp) &&
nat->nat_oip.s_addr == dst.s_addr &&
+ nat->nat_outip.s_addr == mapsrc.s_addr &&
flags == nat->nat_flags && (!flags ||
(nat->nat_outport == mapsport &&
nat->nat_oport == dport)))
@@ -671,7 +710,7 @@ register natlookup_t *np;
* 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(IPN_TCPUDP, np->nl_inip, np->nl_inport,
+ if ((nat = nat_outlookup(NULL, IPN_TCPUDP, np->nl_inip, np->nl_inport,
np->nl_outip, np->nl_outport))) {
np->nl_inip = nat->nat_outip;
np->nl_inport = nat->nat_outport;
@@ -718,43 +757,56 @@ fr_info_t *fin;
ipa = ip->ip_src.s_addr;
MUTEX_ENTER(&ipf_nat);
- for (np = nat_list; np; np = np->in_next)
- if ((np->in_ifp == ifp) && np->in_space &&
- (!np->in_flags || (np->in_flags & nflags)) &&
- ((ipa & np->in_inmsk) == np->in_inip) &&
- ((np->in_redir == NAT_MAP) ||
- (np->in_pnext == sport))) {
- /*
- * If there is no current entry in the nat table for
- * this IP#, create one for it.
- */
- if (!(nat = nat_outlookup(nflags, ip->ip_src, sport,
- ip->ip_dst, dport))) {
+ if ((nat = ipfr_nat_knownfrag(ip, fin)))
+ ;
+ else if ((nat = nat_outlookup(fin->fin_ifp, nflags, ip->ip_src, sport,
+ ip->ip_dst, dport)))
+ np = nat->nat_ptr;
+ else
+ /*
+ * If there is no current entry in the nat table for this IP#,
+ * create one for it (if there is a matching rule).
+ */
+ for (np = nat_list; np; np = np->in_next)
+ if ((np->in_ifp == ifp) && np->in_space &&
+ (!np->in_flags || (np->in_flags & nflags)) &&
+ ((ipa & np->in_inmsk) == np->in_inip) &&
+ ((np->in_redir & NAT_MAP) ||
+ (np->in_pnext == sport))) {
+ if (*np->in_plabel && !ap_ok(ip, tcp, np))
+ continue;
/*
- * If it's a redirection, then we don't want
- * to create new outgoing port stuff.
+ * 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_REDIRECT)
+ if (!(np->in_redir & NAT_MAP))
continue;
- if (!(nat = nat_new(np, ip, fin, nflags,
+ if ((nat = nat_new(np, ip, fin, nflags,
NAT_OUTBOUND)))
- break;
#ifdef IPFILTER_LOG
- nat_log(nat, (u_short)np->in_redir);
+ nat_log(nat, (u_short)np->in_redir);
+#else
+ ;
#endif
+ break;
}
- ip->ip_src = nat->nat_outip;
- nat->nat_age = fr_defnatage; /* 5 mins */
+ if (nat) {
+ if (!nat->nat_frag && fin->fin_fi.fi_fl & FI_FRAG)
+ ipfr_nat_newfrag(ip, fin, 0, nat);
+ nat->nat_age = fr_defnatage;
+ ip->ip_src = nat->nat_outip;
+ nat->nat_bytes += ip->ip_len;
+ nat->nat_pkts++;
/*
* Fix up checksums, not by recalculating them, but
* simply computing adjustments.
*/
#if SOLARIS
- if (np->in_redir == NAT_MAP)
+ if (nat->nat_dir == NAT_OUTBOUND)
fix_outcksum(&ip->ip_sum, nat->nat_ipsumd);
else
fix_incksum(&ip->ip_sum, nat->nat_ipsumd);
@@ -770,6 +822,14 @@ fr_info_t *fin;
csump = &tcp->th_sum;
fr_tcp_age(&nat->nat_age,
nat->nat_state, ip, fin,1);
+ /*
+ * Increase this because we may have
+ * "keep state" following this too and
+ * packet storms can occur if this is
+ * removed too quickly.
+ */
+ if (nat->nat_age == fr_tcpclosed)
+ nat->nat_age = fr_tcplastack;
} else if (ip->ip_p == IPPROTO_UDP) {
udphdr_t *udp = (udphdr_t *)tcp;
@@ -781,7 +841,7 @@ fr_info_t *fin;
csump = &ic->icmp_cksum;
}
if (csump) {
- if (np->in_redir == NAT_MAP)
+ if (nat->nat_dir == NAT_OUTBOUND)
fix_outcksum(csump,
nat->nat_sumd);
else
@@ -789,6 +849,7 @@ fr_info_t *fin;
nat->nat_sumd);
}
}
+ (void) ap_check(ip, tcp, fin, nat);
nat_stats.ns_mapped[1]++;
MUTEX_EXIT(&ipf_nat);
return 1;
@@ -829,38 +890,55 @@ fr_info_t *fin;
in = ip->ip_dst;
MUTEX_ENTER(&ipf_nat);
- for (np = nat_list; np; np = np->in_next)
- if ((np->in_ifp == ifp) &&
- (!np->in_flags || (nflags & np->in_flags)) &&
- ((in.s_addr & np->in_outmsk) == np->in_outip) &&
- (np->in_redir == NAT_MAP || np->in_pmin == dport)) {
- if (!(nat = nat_inlookup(nflags, ip->ip_src, sport,
- ip->ip_dst, dport))) {
+
+ if ((nat = ipfr_nat_knownfrag(ip, fin)))
+ ;
+ else if ((nat = nat_inlookup(fin->fin_ifp, nflags, ip->ip_src, sport,
+ ip->ip_dst, dport)))
+ np = nat->nat_ptr;
+ else
+ /*
+ * If there is no current entry in the nat table for this IP#,
+ * create one for it (if there is a matching rule).
+ */
+ for (np = nat_list; np; np = np->in_next)
+ if ((np->in_ifp == ifp) &&
+ (!np->in_flags || (nflags & np->in_flags)) &&
+ ((in.s_addr & np->in_outmsk) == np->in_outip) &&
+ (np->in_redir & NAT_REDIRECT ||
+ np->in_pmin == dport)) {
/*
* If this rule (np) is a redirection, rather
* than a mapping, then do a nat_new.
* Otherwise, if it's just a mapping, do a
* continue;
*/
- if (np->in_redir == NAT_MAP)
+ if (!(np->in_redir & NAT_REDIRECT))
continue;
- if (!(nat = nat_new(np, ip, fin, nflags,
+ if ((nat = nat_new(np, ip, fin, nflags,
NAT_INBOUND)))
- break;
#ifdef IPFILTER_LOG
- nat_log(nat, (u_short)np->in_redir);
+ nat_log(nat, (u_short)np->in_redir);
+#else
+ ;
#endif
+ break;
}
- ip->ip_dst = nat->nat_inip;
-
+ if (nat) {
+ if (!nat->nat_frag && fin->fin_fi.fi_fl & FI_FRAG)
+ ipfr_nat_newfrag(ip, fin, 0, nat);
+ (void) ap_check(ip, tcp, fin, nat);
nat->nat_age = fr_defnatage;
+ ip->ip_dst = nat->nat_inip;
+ nat->nat_bytes += ip->ip_len;
+ nat->nat_pkts++;
/*
* Fix up checksums, not by recalculating them, but
* simply computing adjustments.
*/
#if SOLARIS
- if (np->in_redir == NAT_MAP)
+ if (nat->nat_dir == NAT_OUTBOUND)
fix_incksum(&ip->ip_sum, nat->nat_ipsumd);
else
fix_outcksum(&ip->ip_sum, nat->nat_ipsumd);
@@ -875,6 +953,14 @@ fr_info_t *fin;
csump = &tcp->th_sum;
fr_tcp_age(&nat->nat_age,
nat->nat_state, ip, fin,0);
+ /*
+ * Increase this because we may have
+ * "keep state" following this too and
+ * packet storms can occur if this is
+ * removed too quickly.
+ */
+ if (nat->nat_age == fr_tcpclosed)
+ nat->nat_age = fr_tcplastack;
} else if (ip->ip_p == IPPROTO_UDP) {
udphdr_t *udp = (udphdr_t *)tcp;
@@ -886,7 +972,7 @@ fr_info_t *fin;
csump = &ic->icmp_cksum;
}
if (csump) {
- if (np->in_redir == NAT_MAP)
+ if (nat->nat_dir == NAT_OUTBOUND)
fix_incksum(csump,
nat->nat_sumd);
else
@@ -914,6 +1000,7 @@ void ip_natunload()
SPLNET(s);
(void) clear_natlist();
(void) flush_nattable();
+ (void) ap_unload();
SPLX(s)
MUTEX_EXIT(&ipf_nat);
}
@@ -970,12 +1057,14 @@ u_short type;
# if BSD >= 199306 || defined(__FreeBSD__)
microtime((struct timeval *)&natl);
# endif
+ natl.nl_inip = nat->nat_inip;
+ natl.nl_outip = nat->nat_outip;
+ natl.nl_origip = nat->nat_oip;
+ natl.nl_bytes = nat->nat_bytes;
+ natl.nl_pkts = nat->nat_pkts;
natl.nl_origport = nat->nat_oport;
- natl.nl_outport = nat->nat_outport;
natl.nl_inport = nat->nat_inport;
- natl.nl_origip = nat->nat_oip;
- natl.nl_outip = nat->nat_outip;
- natl.nl_inip = nat->nat_inip;
+ natl.nl_outport = nat->nat_outport;
natl.nl_type = type;
natl.nl_rule = -1;
if (nat->nat_ptr) {
diff --git a/sys/netinet/ip_nat.h b/sys/netinet/ip_nat.h
index 6dcd28be4185..add4a9a237e6 100644
--- a/sys/netinet/ip_nat.h
+++ b/sys/netinet/ip_nat.h
@@ -1,17 +1,21 @@
/*
- * (C)opyright 1995 by Darren Reed.
+ * (C)opyright 1995-1997 by Darren Reed.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and due credit is given
* to the original author and the contributors.
*
* @(#)ip_nat.h 1.5 2/4/96
- * $Id: ip_nat.h,v 1.1.1.2 1997/04/03 10:11:19 darrenr Exp $
+ * $Id: ip_nat.h,v 2.0.2.12 1997/05/24 07:35:20 darrenr Exp $
*/
-#ifndef __IP_NAT_H_
+#ifndef __IP_NAT_H__
#define __IP_NAT_H__
+#ifndef __IP_PROXY_H__
+#include "netinet/ip_proxy.h"
+#endif
+
#ifndef SOLARIS
#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
#endif
@@ -44,9 +48,12 @@ typedef struct nat {
int nat_flags;
u_long nat_sumd;
u_long nat_ipsumd;
+ struct ipfr *nat_frag;
struct in_addr nat_inip;
struct in_addr nat_outip;
struct in_addr nat_oip; /* other ip */
+ U_QUAD_T nat_pkts;
+ U_QUAD_T nat_bytes;
u_short nat_oport; /* other port */
u_short nat_inport;
u_short nat_outport;
@@ -56,6 +63,8 @@ typedef struct nat {
struct nat *nat_next;
struct nat *nat_hnext[2];
struct nat **nat_hstart[2];
+ void *nat_ifp;
+ int nat_dir;
} nat_t;
typedef struct ipnat {
@@ -69,8 +78,12 @@ typedef struct ipnat {
u_short in_port[2];
struct in_addr in_in[2];
struct in_addr in_out[2];
+ struct aproxy *in_apr;
int in_redir; /* 0 if it's a mapping, 1 if it's a hard redir */
char in_ifname[IFNAMSIZ];
+ char in_plabel[APR_LABELLEN]; /* proxy label */
+ char in_p; /* protocol */
+ u_short in_dport;
} ipnat_t;
#define in_pmin in_port[0] /* Also holds static redir port */
@@ -81,11 +94,12 @@ typedef struct ipnat {
#define in_outip in_out[0].s_addr
#define in_outmsk in_out[1].s_addr
-#define NAT_INBOUND 0
-#define NAT_OUTBOUND 1
+#define NAT_OUTBOUND 0
+#define NAT_INBOUND 1
-#define NAT_MAP 0
-#define NAT_REDIRECT 1
+#define NAT_MAP 0x01
+#define NAT_REDIRECT 0x02
+#define NAT_BIMAP (NAT_MAP|NAT_REDIRECT)
#define IPN_CMPSIZ (sizeof(struct in_addr) * 4 + sizeof(u_short) * 3 + \
sizeof(int))
@@ -99,6 +113,7 @@ typedef struct natlookup {
typedef struct natstat {
u_long ns_mapped[2];
+ u_long ns_rules;
u_long ns_added;
u_long ns_expire;
u_long ns_inuse;
@@ -108,10 +123,11 @@ typedef struct natstat {
ipnat_t *ns_list;
} natstat_t;
-#define IPN_ANY 0
-#define IPN_TCP 1
-#define IPN_UDP 2
-#define IPN_TCPUDP 3
+#define IPN_ANY 0x00
+#define IPN_TCP 0x01
+#define IPN_UDP 0x02
+#define IPN_TCPUDP 0x03
+#define IPN_DELETE 0x04
typedef struct natlog {
@@ -124,6 +140,8 @@ typedef struct natlog {
u_short nl_inport;
u_short nl_type;
int nl_rule;
+ U_QUAD_T nl_pkts;
+ U_QUAD_T nl_bytes;
} natlog_t;
@@ -132,18 +150,22 @@ typedef struct natlog {
#define NL_EXPIRE 0xffff
+extern u_long fr_defnatage;
extern nat_t *nat_table[2][NAT_SIZE];
extern int nat_ioctl __P((caddr_t, int, int));
-extern nat_t *nat_outlookup __P((int, struct in_addr, u_short,
+extern nat_t *nat_new __P((ipnat_t *, ip_t *, fr_info_t *, u_short, int));
+extern nat_t *nat_outlookup __P((void *, int, struct in_addr, u_short,
struct in_addr, u_short));
-extern nat_t *nat_inlookup __P((int, struct in_addr, u_short,
+extern nat_t *nat_inlookup __P((void *, int, struct in_addr, u_short,
struct in_addr, u_short));
extern nat_t *nat_lookupredir __P((natlookup_t *));
-extern nat_t *nat_lookupmapip __P((int, struct in_addr, u_short,
+extern nat_t *nat_lookupmapip __P((void *, int, struct in_addr, u_short,
struct in_addr, u_short));
extern int ip_natout __P((ip_t *, int, fr_info_t *));
extern int ip_natin __P((ip_t *, int, fr_info_t *));
extern void ip_natunload __P((void)), ip_natexpire __P((void));
extern void nat_log __P((struct nat *, u_short));
+extern void fix_incksum __P((u_short *, u_long));
+extern void fix_outcksum __P((u_short *, u_long));
#endif /* __IP_NAT_H__ */
diff --git a/sys/netinet/ip_proxy.c b/sys/netinet/ip_proxy.c
new file mode 100644
index 000000000000..16e5fbe2cf44
--- /dev/null
+++ b/sys/netinet/ip_proxy.c
@@ -0,0 +1,271 @@
+/*
+ * (C)opyright 1997 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+#if !defined(lint) && defined(LIBC_SCCS)
+static char rcsid[] = "$Id: ip_proxy.c,v 2.0.2.3 1997/05/24 07:36:22 darrenr Exp $";
+#endif
+
+#if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL)
+# define _KERNEL
+#endif
+
+#if !defined(_KERNEL) && !defined(KERNEL)
+# include <stdio.h>
+# include <string.h>
+# include <stdlib.h>
+#endif
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/fcntl.h>
+#include <sys/uio.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#ifdef _KERNEL
+# include <sys/systm.h>
+#endif
+#if !defined(__SVR4) && !defined(__svr4__)
+# include <sys/mbuf.h>
+#else
+# include <sys/byteorder.h>
+# include <sys/dditypes.h>
+# include <sys/stream.h>
+# include <sys/kmem.h>
+#endif
+#if __FreeBSD__ > 2
+# include <sys/queue.h>
+#endif
+#include <net/if.h>
+#ifdef sun
+# include <net/af.h>
+#endif
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/tcpip.h>
+#include <netinet/ip_icmp.h>
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_proxy.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_state.h"
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+static ap_session_t *ap_find __P((ip_t *, tcphdr_t *));
+static ap_session_t *ap_new_session __P((aproxy_t *, ip_t *, tcphdr_t *,
+ fr_info_t *, nat_t *));
+
+#define AP_SESS_SIZE 53
+
+#ifdef _KERNEL
+#include "netinet/ip_ftp_pxy.c"
+#endif
+
+ap_session_t *ap_sess_tab[AP_SESS_SIZE];
+aproxy_t ap_proxies[] = {
+#ifdef IPF_FTP_PROXY
+ { "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, ippr_ftp_in, ippr_ftp_out },
+#endif
+ { "", '\0', 0, 0, NULL, NULL }
+};
+
+
+int ap_ok(ip, tcp, nat)
+ip_t *ip;
+tcphdr_t *tcp;
+ipnat_t *nat;
+{
+ aproxy_t *apr = nat->in_apr;
+ u_short dport = nat->in_dport;
+
+ if (!apr || (apr && (apr->apr_flags & APR_DELETE)) ||
+ (ip->ip_p != apr->apr_p))
+ return 0;
+ if ((tcp && (tcp->th_dport != dport)) || (!tcp && dport))
+ return 0;
+ return 1;
+}
+
+
+static ap_session_t *ap_find(ip, tcp)
+ip_t *ip;
+tcphdr_t *tcp;
+{
+ struct in_addr src = ip->ip_src, dst = ip->ip_dst;
+ register u_long hv;
+ register u_short sp, dp;
+ register ap_session_t *aps;
+ register u_char p = ip->ip_p;
+
+ hv = ip->ip_src.s_addr ^ ip->ip_dst.s_addr;
+ hv *= 651733;
+ if (tcp) {
+ sp = tcp->th_sport;
+ dp = tcp->th_dport;
+ hv ^= (sp + dp);
+ hv *= 5;
+ }
+ hv %= AP_SESS_SIZE;
+
+ for (aps = ap_sess_tab[hv]; aps; aps = aps->aps_next)
+ if ((aps->aps_p == p) &&
+ IPPAIR(aps->aps_src, aps->aps_dst, src, dst)) {
+ if (tcp) {
+ if (PAIRS(aps->aps_sport, aps->aps_dport,
+ sp, dp))
+ break;
+ } else
+ break;
+ }
+ return aps;
+}
+
+static ap_session_t *ap_new_session(apr, ip, tcp, fin, nat)
+aproxy_t *apr;
+ip_t *ip;
+tcphdr_t *tcp;
+fr_info_t *fin;
+nat_t *nat;
+{
+ register ap_session_t *aps;
+ u_short dport;
+ u_long hv;
+
+ if (!apr || (apr && (apr->apr_flags & APR_DELETE)) ||
+ (ip->ip_p != apr->apr_p))
+ return NULL;
+ dport = nat->nat_ptr->in_dport;
+ if ((tcp && (tcp->th_dport != dport)) || (!tcp && dport))
+ return NULL;
+
+ hv = ip->ip_src.s_addr ^ ip->ip_dst.s_addr;
+ hv *= 651733;
+ if (tcp) {
+ hv ^= (tcp->th_sport + tcp->th_dport);
+ hv *= 5;
+ }
+ hv %= AP_SESS_SIZE;
+
+ KMALLOC(aps, ap_session_t *, sizeof(*aps));
+ if (!aps)
+ return NULL;
+ bzero((char *)aps, sizeof(aps));
+ apr->apr_ref++;
+ aps->aps_apr = apr;
+ aps->aps_src = ip->ip_src;
+ aps->aps_dst = ip->ip_dst;
+ aps->aps_p = ip->ip_p;
+ aps->aps_tout = 1200; /* XXX */
+ if (tcp) {
+ if (ip->ip_p == IPPROTO_TCP) {
+ aps->aps_seqoff = 0;
+ aps->aps_ackoff = 0;
+ aps->aps_state[0] = 0;
+ aps->aps_state[1] = 0;
+ }
+ aps->aps_sport = tcp->th_sport;
+ aps->aps_dport = tcp->th_dport;
+ }
+ aps->aps_data = NULL;
+ aps->aps_psiz = 0;
+ aps->aps_next = ap_sess_tab[hv];
+ ap_sess_tab[hv] = aps;
+ (void) (*apr->apr_init)(fin, ip, tcp, aps, nat);
+ return aps;
+}
+
+
+int ap_check(ip, tcp, fin, nat)
+ip_t *ip;
+tcphdr_t *tcp;
+fr_info_t *fin;
+nat_t *nat;
+{
+ ap_session_t *aps;
+ aproxy_t *apr;
+ int err;
+
+ if (!(fin->fin_fi.fi_fl & FI_TCPUDP))
+ tcp = NULL;
+
+ if ((aps = ap_find(ip, tcp)) ||
+ (aps = ap_new_session(nat->nat_ptr->in_apr, ip, tcp, fin, nat))) {
+ if (ip->ip_p == IPPROTO_TCP)
+ fr_tcp_age(&aps->aps_tout, aps->aps_state, ip, fin,
+ tcp->th_sport == aps->aps_sport);
+ apr = aps->aps_apr;
+ err = 0;
+ if (fin->fin_out) {
+ if (apr->apr_outpkt)
+ err = (*apr->apr_outpkt)(fin, ip, tcp,
+ aps, nat);
+ } else {
+ if (apr->apr_inpkt)
+ err = (*apr->apr_inpkt)(fin, ip, tcp,
+ aps, nat);
+ }
+ if (err == 2) {
+ tcp->th_sum = fr_tcpsum(fin->fin_mp, ip, tcp);
+ err = 0;
+ }
+ return err;
+ }
+ return -1;
+}
+
+
+aproxy_t *ap_match(pr, name)
+char pr;
+char *name;
+{
+ aproxy_t *ap;
+
+ for (ap = ap_proxies; ap->apr_p; ap++)
+ if ((ap->apr_p == pr) &&
+ !strncmp(name, ap->apr_label, sizeof(ap->apr_label)))
+ return ap;
+ return NULL;
+}
+
+
+void ap_free(ap)
+aproxy_t *ap;
+{
+ KFREE(ap);
+}
+
+
+void aps_free(aps)
+ap_session_t *aps;
+{
+ if (aps->aps_data && aps->aps_psiz)
+ KFREES(aps->aps_data, aps->aps_psiz);
+ KFREE(aps);
+}
+
+
+void ap_unload()
+{
+ ap_session_t *aps;
+ int i;
+
+ for (i = 0; i < AP_SESS_SIZE; i++)
+ while (aps = ap_sess_tab[i]) {
+ ap_sess_tab[i] = aps->aps_next;
+ aps_free(aps);
+ }
+}
diff --git a/sys/netinet/ip_proxy.h b/sys/netinet/ip_proxy.h
new file mode 100644
index 000000000000..2d7175491b39
--- /dev/null
+++ b/sys/netinet/ip_proxy.h
@@ -0,0 +1,89 @@
+/*
+ * (C)opyright 1997 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ *
+ * $Id: ip_proxy.h,v 2.0.2.2 1997/05/24 07:36:44 darrenr Exp $
+ */
+
+#ifndef __IP_PROXY_H__
+#define __IP_PROXY_H__
+
+#ifndef SOLARIS
+#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
+#endif
+
+#define APR_LABELLEN 16
+#define AP_SESS_SIZE 53
+
+struct nat;
+
+typedef struct ap_tcp {
+ u_short apt_sport; /* source port */
+ u_short apt_dport; /* destination port */
+ short apt_seqoff; /* sequence # difference */
+ short apt_ackoff; /* ack # difference */
+ tcp_seq apt_after; /* don't change seq-off until after this */
+ char apt_state[2]; /* connection state */
+} ap_tcp_t;
+
+typedef struct ap_udp {
+ u_short apu_sport; /* source port */
+ u_short apu_dport; /* destination port */
+} ap_udp_t;
+
+typedef struct ap_session {
+ struct aproxy *aps_apr;
+ struct in_addr aps_src; /* source IP# */
+ struct in_addr aps_dst; /* destination IP# */
+ u_char aps_p; /* protocol */
+ union {
+ struct ap_tcp apu_tcp;
+ struct ap_udp apu_udp;
+ } aps_un;
+ u_int aps_flags;
+ QUAD_T aps_bytes; /* bytes sent */
+ QUAD_T aps_pkts; /* packets sent */
+ time_t aps_tout; /* time left before expiring */
+ void *aps_data; /* private data */
+ int aps_psiz; /* size of private data */
+ struct ap_session *aps_next;
+} ap_session_t ;
+
+#define aps_sport aps_un.apu_tcp.apt_sport
+#define aps_dport aps_un.apu_tcp.apt_dport
+#define aps_seqoff aps_un.apu_tcp.apt_seqoff
+#define aps_ackoff aps_un.apu_tcp.apt_ackoff
+#define aps_sumoff aps_un.apu_tcp.apt_sumoff
+#define aps_state aps_un.apu_tcp.apt_state
+#define aps_after aps_un.apu_tcp.apt_after
+
+
+typedef struct aproxy {
+ char apr_label[APR_LABELLEN]; /* Proxy label # */
+ char apr_p; /* protocol */
+ int apr_ref; /* +1 per rule referencing it */
+ int apr_flags;
+ int (* apr_init) __P((fr_info_t *, ip_t *, tcphdr_t *,
+ ap_session_t *, struct nat *));
+ int (* apr_inpkt) __P((fr_info_t *, ip_t *, tcphdr_t *,
+ ap_session_t *, struct nat *));
+ int (* apr_outpkt) __P((fr_info_t *, ip_t *, tcphdr_t *,
+ ap_session_t *, struct nat *));
+} aproxy_t;
+
+#define APR_DELETE 1
+
+
+extern ap_session_t *ap_sess_tab[AP_SESS_SIZE];
+extern aproxy_t ap_proxies[];
+
+extern void ap_unload __P((void));
+extern void ap_free __P((aproxy_t *));
+extern void aps_free __P((ap_session_t *));
+extern int ap_check __P((ip_t *, tcphdr_t *, fr_info_t *, struct nat *));
+extern aproxy_t *ap_match __P((char, char *));
+
+#endif /* __IP_PROXY_H__ */
diff --git a/sys/netinet/ip_state.c b/sys/netinet/ip_state.c
index e26b4f3c400b..a6bda8a170ed 100644
--- a/sys/netinet/ip_state.c
+++ b/sys/netinet/ip_state.c
@@ -7,7 +7,7 @@
*/
#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-1995 Darren Reed";
-static char rcsid[] = "$Id: ip_state.c,v 1.1.1.3 1997/04/03 10:11:29 darrenr Exp $";
+static char rcsid[] = "$Id: ip_state.c,v 2.0.2.12 1997/05/24 07:34:10 darrenr Exp $";
#endif
#if !defined(_KERNEL) && !defined(KERNEL)
@@ -19,12 +19,11 @@ static char rcsid[] = "$Id: ip_state.c,v 1.1.1.3 1997/04/03 10:11:29 darrenr Exp
#include <sys/param.h>
#include <sys/time.h>
#include <sys/file.h>
-#if defined(__FreeBSD__) && (__FreeBSD__ >= 3)
-#include <sys/ioccom.h>
-#include <sys/filio.h>
-#include <sys/fcntl.h>
+#if defined(KERNEL) && (__FreeBSD_version >= 220000)
+# include <sys/filio.h>
+# include <sys/fcntl.h>
#else
-#include <sys/ioctl.h>
+# include <sys/ioctl.h>
#endif
#include <sys/uio.h>
#include <sys/protosw.h>
@@ -35,6 +34,7 @@ static char rcsid[] = "$Id: ip_state.c,v 1.1.1.3 1997/04/03 10:11:29 darrenr Exp
#if !defined(__SVR4) && !defined(__svr4__)
# include <sys/mbuf.h>
#else
+# include <sys/filio.h>
# include <sys/byteorder.h>
# include <sys/dditypes.h>
# include <sys/stream.h>
@@ -55,9 +55,10 @@ static char rcsid[] = "$Id: ip_state.c,v 1.1.1.3 1997/04/03 10:11:29 darrenr Exp
#include <netinet/udp.h>
#include <netinet/tcpip.h>
#include <netinet/ip_icmp.h>
-#include "ip_compat.h"
-#include "ip_fil.h"
-#include "ip_state.h"
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_state.h"
#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
@@ -67,11 +68,8 @@ static char rcsid[] = "$Id: ip_state.c,v 1.1.1.3 1997/04/03 10:11:29 darrenr Exp
ipstate_t *ips_table[IPSTATE_SIZE];
int ips_num = 0;
ips_stat_t ips_stats;
-#if SOLARIS
+#if SOLARIS && defined(_KERNEL)
extern kmutex_t ipf_state;
-# if !defined(_KERNEL)
-#define bcopy(a,b,c) memmove(b,a,c)
-# endif
#endif
@@ -94,10 +92,27 @@ ips_stat_t *fr_statetstats()
}
-#define PAIRS(s1,d1,s2,d2) ((((s1) == (s2)) && ((d1) == (d2))) ||\
- (((s1) == (d2)) && ((d1) == (s2))))
-#define IPPAIR(s1,d1,s2,d2) PAIRS((s1).s_addr, (d1).s_addr, \
- (s2).s_addr, (d2).s_addr)
+int fr_state_ioctl(data, cmd, mode)
+caddr_t data;
+int cmd;
+int mode;
+{
+ switch (cmd)
+ {
+ case SIOCGIPST :
+ IWCOPY((caddr_t)fr_statetstats(), data, sizeof(ips_stat_t));
+ break;
+ case FIONREAD :
+#ifdef IPFILTER_LOG
+ *(int *)data = iplused[IPL_LOGSTATE];
+#endif
+ break;
+ default :
+ return -1;
+ }
+ return 0;
+}
+
/*
* Create a new ipstate structure and hang it off the hash table.
@@ -212,6 +227,8 @@ u_int pass;
ipstate_log(is, ISL_NEW);
#endif
MUTEX_EXIT(&ipf_state);
+ if (fin->fin_fi.fi_fl & FI_FRAG)
+ ipfr_newfrag(ip, fin, pass ^ FR_KEEPSTATE);
return 0;
}
@@ -346,8 +363,9 @@ fr_info_t *fin;
is->is_pkts++;
is->is_bytes += ip->ip_len;
ips_stats.iss_hits++;
+ pass = is->is_pass;
MUTEX_EXIT(&ipf_state);
- return is->is_pass;
+ return pass;
}
MUTEX_EXIT(&ipf_state);
break;
@@ -364,10 +382,10 @@ fr_info_t *fin;
PAIRS(sport, dport, is->is_sport, is->is_dport) &&
IPPAIR(src, dst, is->is_src, is->is_dst))
if (fr_tcpstate(is, fin, ip, tcp, sport)) {
+ pass = is->is_pass;
#ifdef _KERNEL
MUTEX_EXIT(&ipf_state);
#else
- int pass = is->is_pass;
if (tcp->th_flags & TCP_CLOSE) {
*isp = is->is_next;
diff --git a/sys/netinet/ip_state.h b/sys/netinet/ip_state.h
index b92f8c23e434..930110157488 100644
--- a/sys/netinet/ip_state.h
+++ b/sys/netinet/ip_state.h
@@ -1,12 +1,12 @@
/*
- * (C)opyright 1995 by Darren Reed.
+ * (C)opyright 1995-1997 by Darren Reed.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and due credit is given
* to the original author and the contributors.
*
* @(#)ip_state.h 1.3 1/12/96 (C) 1995 Darren Reed
- * $Id: ip_state.h,v 1.1.1.2 1997/04/03 10:11:33 darrenr Exp $
+ * $Id: ip_state.h,v 2.0.2.9 1997/05/24 07:35:11 darrenr Exp $
*/
#ifndef __IP_STATE_H__
#define __IP_STATE_H__
@@ -14,6 +14,12 @@
#define IPSTATE_SIZE 257
#define IPSTATE_MAX 2048 /* Maximum number of states held */
+#define PAIRS(s1,d1,s2,d2) ((((s1) == (s2)) && ((d1) == (d2))) ||\
+ (((s1) == (d2)) && ((d1) == (s2))))
+#define IPPAIR(s1,d1,s2,d2) PAIRS((s1).s_addr, (d1).s_addr, \
+ (s2).s_addr, (d2).s_addr)
+
+
typedef struct udpstate {
u_short us_sport;
u_short us_dport;
@@ -106,6 +112,14 @@ typedef struct ips_stat {
ipstate_t **iss_table;
} ips_stat_t;
+
+extern u_long fr_tcpidletimeout;
+extern u_long fr_tcpclosewait;
+extern u_long fr_tcplastack;
+extern u_long fr_tcptimeout;
+extern u_long fr_tcpclosed;
+extern u_long fr_udptimeout;
+extern u_long fr_icmptimeout;
extern int fr_tcpstate __P((ipstate_t *, fr_info_t *, ip_t *,
tcphdr_t *, u_short));
extern ips_stat_t *fr_statetstats __P((void));
@@ -115,4 +129,5 @@ extern void fr_timeoutstate __P((void));
extern void fr_tcp_age __P((u_long *, u_char *, ip_t *, fr_info_t *, int));
extern void fr_stateunload __P((void));
extern void ipstate_log __P((struct ipstate *, u_short));
+extern int fr_state_ioctl __P((caddr_t, int, int));
#endif /* __IP_STATE_H__ */
diff --git a/sys/netinet/ipl.h b/sys/netinet/ipl.h
new file mode 100644
index 000000000000..a7a582800b0c
--- /dev/null
+++ b/sys/netinet/ipl.h
@@ -0,0 +1,16 @@
+/*
+ * (C)opyright 1993-1997 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ *
+ * @(#)ipl.h 1.21 6/5/96
+ */
+
+#ifndef __IPL_H__
+#define __IPL_H__
+
+#define IPL_VERSION "IP Filter v3.2alpha7"
+
+#endif
diff --git a/sys/netinet/mln_ipl.c b/sys/netinet/mln_ipl.c
new file mode 100644
index 000000000000..fe035da0cbb7
--- /dev/null
+++ b/sys/netinet/mln_ipl.c
@@ -0,0 +1,377 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+/*
+ * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate
+ * its own major char number! Way cool patch!
+ */
+
+
+#include <sys/param.h>
+
+#if defined(__FreeBSD__) && (__FreeBSD__ > 1)
+# ifdef IPFILTER_LKM
+# include <osreldate.h>
+# define ACTUALLY_LKM_NOT_KERNEL
+# else
+# include <sys/osreldate.h>
+# endif
+#endif
+#include <sys/systm.h>
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
+# include <sys/conf.h>
+# include <sys/kernel.h>
+# ifdef DEVFS
+# include <sys/devfsext.h>
+# endif /*DEVFS*/
+#endif
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/proc.h>
+#include <sys/uio.h>
+#include <sys/kernel.h>
+#include <sys/vnode.h>
+#include <sys/namei.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/exec.h>
+#include <sys/mbuf.h>
+#if BSD >= 199506
+# include <sys/sysctl.h>
+#endif
+#if (__FreeBSD_version >= 199511)
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <net/route.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#endif
+#if (__FreeBSD__ > 1)
+# include <sys/sysent.h>
+#endif
+#include <sys/lkm.h>
+#include "netinet/ipl.h"
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+
+#ifndef IPL_NAME
+#define IPL_NAME "/dev/ipl"
+#endif
+#define IPL_NAT "/dev/ipnat"
+#define IPL_STATE "/dev/ipstate"
+
+#if !defined(VOP_LEASE) && defined(LEASE_CHECK)
+#define VOP_LEASE LEASE_CHECK
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+extern int lkmenodev __P((void));
+
+
+static int ipl_unload __P((void));
+static int ipl_load __P((void));
+static int ipl_remove __P((void));
+int xxxinit __P((struct lkm_table *, int, int));
+
+
+struct cdevsw ipldevsw =
+{
+ iplopen, /* open */
+ iplclose, /* close */
+ iplread, /* read */
+ (void *)nullop, /* write */
+ iplioctl, /* ioctl */
+ (void *)nullop, /* stop */
+ (void *)nullop, /* reset */
+ (void *)NULL, /* tty */
+ (void *)nullop, /* select */
+ (void *)nullop, /* mmap */
+ NULL /* strategy */
+};
+
+#ifdef SYSCTL_INT
+SYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW, 0, "IPF");
+SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &fr_flags, 0, "");
+SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_pass, CTLFLAG_RW, &fr_pass, 0, "");
+SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &fr_active, 0, "");
+SYSCTL_INT(_net_inet_ipf, OID_AUTO, ipl_unreach, CTLFLAG_RW,
+ &ipl_unreach, 0, "");
+SYSCTL_INT(_net_inet_ipf, OID_AUTO, ipl_inited, CTLFLAG_RD,
+ &ipl_inited, 0, "");
+#endif
+
+#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000)
+int ipl_major = 0;
+
+MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipldevsw);
+
+extern struct cdevsw cdevsw[];
+extern int vd_unuseddev __P((void));
+extern int nchrdev;
+#else
+int ipl_major = CDEV_MAJOR;
+
+static struct cdevsw ipl_cdevsw = {
+ iplopen, iplclose, iplread, nowrite, /* 79 */
+ iplioctl, nostop, noreset, nodevtotty,
+ noselect, nommap, nostrategy, "ipl",
+ NULL, -1
+};
+#endif
+
+
+static int iplaction __P((struct lkm_table *, int));
+
+
+static int iplaction(lkmtp, cmd)
+struct lkm_table *lkmtp;
+int cmd;
+{
+ int i = ipl_major;
+ struct lkm_dev *args = lkmtp->private.lkm_dev;
+ int err = 0;
+
+ switch (cmd)
+ {
+ case LKM_E_LOAD :
+ if (lkmexists(lkmtp))
+ return EEXIST;
+
+#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000)
+ for (i = 0; i < nchrdev; i++)
+ if (cdevsw[i].d_open == lkmenodev ||
+ cdevsw[i].d_open == iplopen)
+ break;
+ if (i == nchrdev) {
+ printf("IP Filter: No free cdevsw slots\n");
+ return ENODEV;
+ }
+
+ ipl_major = i;
+ args->lkm_offset = i; /* slot in cdevsw[] */
+#endif
+ printf("IP Filter: loaded into slot %d\n", ipl_major);
+ return ipl_load();
+ break;
+ case LKM_E_UNLOAD :
+ printf("IP Filter: unloaded from slot %d\n", ipl_major);
+ return ipl_unload();
+ case LKM_E_STAT :
+ break;
+ default:
+ err = EIO;
+ break;
+ }
+ return 0;
+}
+
+
+static int ipl_remove __P((void))
+{
+ struct nameidata nd;
+ int error;
+
+ NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, IPL_NAME, curproc);
+ if ((error = namei(&nd)))
+ return (error);
+ VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE);
+ VOP_LOCK(nd.ni_vp);
+ VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
+ (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
+
+ NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, IPL_NAT, curproc);
+ if ((error = namei(&nd)))
+ return (error);
+ VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE);
+ VOP_LOCK(nd.ni_vp);
+ VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
+ (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
+
+ NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, IPL_STATE, curproc);
+ if ((error = namei(&nd)))
+ return (error);
+ VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE);
+ VOP_LOCK(nd.ni_vp);
+ VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
+ (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
+ return 0;
+}
+
+
+static int ipl_unload()
+{
+ int error = 0;
+
+ error = ipldetach();
+ if (!error)
+ error = ipl_remove();
+ return error;
+}
+
+
+static int ipl_load()
+{
+ struct nameidata nd;
+ struct vattr vattr;
+ int error = 0, fmode = S_IFCHR|0600;
+
+ error = iplattach();
+ if (error)
+ return error;
+ (void) ipl_remove();
+
+ NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, IPL_NAME, curproc);
+ if (error = namei(&nd))
+ return error;
+ if (nd.ni_vp != NULL) {
+ VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+ if (nd.ni_dvp == nd.ni_vp)
+ vrele(nd.ni_dvp);
+ else
+ vput(nd.ni_dvp);
+ vrele(nd.ni_vp);
+ return (EEXIST);
+ }
+ VATTR_NULL(&vattr);
+ vattr.va_type = VCHR;
+ vattr.va_mode = (fmode & 07777);
+ vattr.va_rdev = ipl_major<<8;
+ VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
+ error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
+ if (error)
+ return error;
+
+ NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, IPL_NAT, curproc);
+ if (error = namei(&nd))
+ return error;
+ if (nd.ni_vp != NULL) {
+ VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+ if (nd.ni_dvp == nd.ni_vp)
+ vrele(nd.ni_dvp);
+ else
+ vput(nd.ni_dvp);
+ vrele(nd.ni_vp);
+ return (EEXIST);
+ }
+ VATTR_NULL(&vattr);
+ vattr.va_type = VCHR;
+ vattr.va_mode = (fmode & 07777);
+ vattr.va_rdev = (ipl_major<<8)|1;
+ VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
+ error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
+ if (error)
+ return error;
+
+ NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, IPL_STATE, curproc);
+ if (error = namei(&nd))
+ return error;
+ if (nd.ni_vp != NULL) {
+ VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+ if (nd.ni_dvp == nd.ni_vp)
+ vrele(nd.ni_dvp);
+ else
+ vput(nd.ni_dvp);
+ vrele(nd.ni_vp);
+ return (EEXIST);
+ }
+ VATTR_NULL(&vattr);
+ vattr.va_type = VCHR;
+ vattr.va_mode = (fmode & 07777);
+ vattr.va_rdev = (ipl_major<<8)|2;
+ VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
+ error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
+ if (error)
+ return error;
+ return 0;
+}
+
+
+#if defined(__FreeBSD_version) && (__FreeBSD_version < 220000)
+/*
+ * strlen isn't present in 2.1.* kernels.
+ */
+size_t strlen(string)
+char *string;
+{
+ register char *s;
+
+ for (s = string; *s; s++)
+ ;
+ return (size_t)(s - string);
+}
+
+
+int xxxinit(lkmtp, cmd, ver)
+struct lkm_table *lkmtp;
+int cmd, ver;
+{
+ DISPATCH(lkmtp, cmd, ver, iplaction, iplaction, iplaction);
+}
+#else
+# ifdef IPFILTER_LKM
+# include <sys/exec.h>
+
+MOD_DECL(if_ipl);
+
+static struct lkm_dev _module = {
+ LM_DEV,
+ LKM_VERSION,
+ IPL_VERSION,
+ CDEV_MAJOR,
+ LM_DT_CHAR,
+ (void *)&ipl_cdevsw
+};
+
+int if_ipl(lkmtp, cmd, ver)
+struct lkm_table *lkmtp;
+int cmd, ver;
+{
+ DISPATCH(lkmtp, cmd, ver, iplaction, iplaction, iplaction);
+}
+# else
+
+#ifdef DEVFS
+static void *ipf_devfs_token[3];
+#endif
+static ipl_devsw_installed = 0;
+
+static void ipl_drvinit __P((void *unused))
+{
+ dev_t dev;
+#ifdef DEVFS
+ void **tp = ipf_devfs_token;
+#endif
+
+ if (!ipl_devsw_installed ) {
+ dev = makedev(CDEV_MAJOR, 0);
+ cdevsw_add(&dev, &ipl_cdevsw, NULL);
+ ipl_devsw_installed = 1;
+
+#ifdef DEVFS
+ tp[IPL_LOGIPF] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGIPF,
+ DV_CHR, 0, 0, 0600,
+ "ipf", IPL_LOGIPF);
+ tp[IPL_LOGNAT] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGNAT,
+ DV_CHR, 0, 0, 0600,
+ "ipnat", IPL_LOGNAT);
+ tp[IPL_LOGSTATE] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGSTATE,
+ DV_CHR, 0, 0, 0600,
+ "ipstate", IPL_LOGSTATE);
+#endif
+ }
+}
+
+SYSINIT(ipldev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ipl_drvinit,NULL)
+# endif /* IPFILTER_LKM */
+#endif /* _FreeBSD_version */