Import version 3.2alpha7

This commit is contained in:
Darren Reed 1997-05-25 15:50:46 +00:00
parent 1fddb84ad6
commit e10102a12a
Notes: svn2git 2020-12-20 02:59:44 +00:00
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
15 changed files with 1762 additions and 319 deletions

View file

@ -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 @@ int out;
}
}
#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 @@ int out;
#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 @@ int out;
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;
}

View file

@ -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))); \

View file

@ -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,8 +15,15 @@ static char rcsid[] = "$Id: ip_fil.c,v 1.1.1.3 1997/04/03 10:10:52 darrenr Exp $
#endif
#ifdef __FreeBSD__
# 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>
#include <string.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>
#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>
#ifndef _KERNEL
# include <syslog.h>
#include "ip_compat.h"
#include "ip_fil.h"
#include "ip_frag.h"
#include "ip_nat.h"
#include "ip_state.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()

View file

@ -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__ */

View file

@ -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,12 +254,46 @@ fr_info_t *fin;
f->ipfr_off = off;
}
ipfr_stats.ifs_hits++;
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 ret;
}
MUTEX_EXIT(&ipf_frag);
return 0;
}
/*
@ -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();

View file

@ -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

204
sys/netinet/ip_ftp_pxy.c Normal file
View file

@ -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;
}

View file

@ -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>
#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;
if (!n->in_use) {
if (n->in_apr)
ap_free(n->in_apr);
KFREE(n);
nattable_sync();
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--;
}
@ -329,44 +357,28 @@ 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;
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;
ifa = ifp->if_addrlist;
# if BSD < 199306
sin = (struct sockaddr_in *)&ifa->ifa_addr;
# if (__FreeBSD_version >= 300000)
ifa = TAILQ_FIRST(&ifp->if_addrhead);
# else
sin = (struct sockaddr_in *)ifa->ifa_addr;
# ifdef __NetBSD__
ifa = ifp->if_addrlist.tqh_first;
# else
ifa = ifp->if_addrlist;
# endif
# endif
# if BSD < 199306
sin = (SOCKADDR_IN *)&ifa->ifa_addr;
# else
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);
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_redir & NAT_MAP) ||
(np->in_pnext == sport))) {
if (*np->in_plabel && !ap_ok(ip, tcp, np))
continue;
/*
* 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 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);
#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);
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_MAP || np->in_pmin == dport)) {
if (!(nat = nat_inlookup(nflags, ip->ip_src, sport,
ip->ip_dst, dport))) {
(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);
#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_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_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_inport = nat->nat_inport;
natl.nl_outport = nat->nat_outport;
natl.nl_type = type;
natl.nl_rule = -1;
if (nat->nat_ptr) {

View file

@ -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__ */

271
sys/netinet/ip_proxy.c Normal file
View file

@ -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);
}
}

89
sys/netinet/ip_proxy.h Normal file
View file

@ -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__ */

View file

@ -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,8 +19,7 @@ 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>
#if defined(KERNEL) && (__FreeBSD_version >= 220000)
# include <sys/filio.h>
# include <sys/fcntl.h>
#else
@ -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;

View file

@ -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__ */

16
sys/netinet/ipl.h Normal file
View file

@ -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

377
sys/netinet/mln_ipl.c Normal file
View file

@ -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 */