From e10102a12a980dc84a95a4a831769c1058c946c0 Mon Sep 17 00:00:00 2001 From: Darren Reed Date: Sun, 25 May 1997 15:50:46 +0000 Subject: [PATCH] Import version 3.2alpha7 --- sys/netinet/fil.c | 205 ++++++++++++++++----- sys/netinet/ip_compat.h | 32 +++- sys/netinet/ip_fil.c | 110 ++++++++---- sys/netinet/ip_fil.h | 91 +++++----- sys/netinet/ip_frag.c | 223 ++++++++++++++++++----- sys/netinet/ip_frag.h | 11 +- sys/netinet/ip_ftp_pxy.c | 204 +++++++++++++++++++++ sys/netinet/ip_nat.c | 327 +++++++++++++++++++++------------ sys/netinet/ip_nat.h | 50 ++++-- sys/netinet/ip_proxy.c | 271 ++++++++++++++++++++++++++++ sys/netinet/ip_proxy.h | 89 +++++++++ sys/netinet/ip_state.c | 56 ++++-- sys/netinet/ip_state.h | 19 +- sys/netinet/ipl.h | 16 ++ sys/netinet/mln_ipl.c | 377 +++++++++++++++++++++++++++++++++++++++ 15 files changed, 1762 insertions(+), 319 deletions(-) create mode 100644 sys/netinet/ip_ftp_pxy.c create mode 100644 sys/netinet/ip_proxy.c create mode 100644 sys/netinet/ip_proxy.h create mode 100644 sys/netinet/ipl.h create mode 100644 sys/netinet/mln_ipl.c 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 @@ -45,11 +45,12 @@ static char rcsid[] = "$Id: fil.c,v 1.1.1.3 1997/04/03 10:10:10 darrenr Exp $"; #include #include #include -#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; +} 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 @@ -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 +# if defined(KERNEL) && !defined(_KERNEL) +# define _KERNEL +# endif +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# include +# else +# include +# endif #endif #ifndef _KERNEL #include @@ -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 #include #include -#include +#if __FreeBSD_version >= 220000 && defined(_KERNEL) +# include +# include +#else +# include +#endif #include #ifdef _KERNEL #include @@ -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 #include #else -#define bcmp memcmp -#define bzero(a,b) memset(a,0,b) -#define bcopy(a,b,c) memcpy(b,a,c) #include #endif #include @@ -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 #endif +#if __FreeBSD_version >= 300000 +# include +#endif #include #include #include @@ -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 #include #include -#include -#include "ip_compat.h" -#include "ip_fil.h" -#include "ip_frag.h" -#include "ip_nat.h" -#include "ip_state.h" +#ifndef _KERNEL +# include +#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 #include #include -#if defined(__FreeBSD__) && (__FreeBSD__ >= 3) -#include +#if defined(KERNEL) && (__FreeBSD_version >= 220000) #include #include #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 #include #include -#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 #include #include -#include +#if defined(KERNEL) && (__FreeBSD_version >= 220000) +# include +# include +#else +# include +#endif +#include #include #include #include @@ -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 #else +# include # include # include # include # include #endif - +#if __FreeBSD_version >= 300000 +# include +#endif #include +#if __FreeBSD_version >= 300000 +# include +#endif #ifdef sun #include #endif @@ -62,36 +74,30 @@ extern struct ifnet vpnif; #include #include #include -#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--; } @@ -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; - 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; - 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); - 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_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) { 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 +# include +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef _KERNEL +# include +#endif +#if !defined(__SVR4) && !defined(__svr4__) +# include +#else +# include +# include +# include +# include +#endif +#if __FreeBSD__ > 2 +# include +#endif +#include +#ifdef sun +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 #include #include -#if defined(__FreeBSD__) && (__FreeBSD__ >= 3) -#include -#include -#include +#if defined(KERNEL) && (__FreeBSD_version >= 220000) +# include +# include #else -#include +# include #endif #include #include @@ -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 #else +# include # include # include # include @@ -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 #include #include -#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 to allow it to allocate + * its own major char number! Way cool patch! + */ + + +#include + +#if defined(__FreeBSD__) && (__FreeBSD__ > 1) +# ifdef IPFILTER_LKM +# include +# define ACTUALLY_LKM_NOT_KERNEL +# else +# include +# endif +#endif +#include +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) +# include +# include +# ifdef DEVFS +# include +# endif /*DEVFS*/ +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if BSD >= 199506 +# include +#endif +#if (__FreeBSD_version >= 199511) +#include +#include +#include +#include +#include +#include +#include +#include +#endif +#if (__FreeBSD__ > 1) +# include +#endif +#include +#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 + +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 */