This commit was generated by cvs2svn to compensate for changes in r145516,

which included commits to RCS files with non-trunk default branches.
This commit is contained in:
Darren Reed 2005-04-25 18:15:41 +00:00
commit d607092b37
18 changed files with 8348 additions and 111 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,455 @@
/* $FreeBSD$ */
/*
* Copyright (C) 1993-2001, 2003 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*/
#if defined(KERNEL) || defined(_KERNEL)
# undef KERNEL
# undef _KERNEL
# define KERNEL 1
# define _KERNEL 1
#endif
#include <sys/param.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <sys/file.h>
#if !defined(_KERNEL)
# include <stdlib.h>
# include <string.h>
# define _KERNEL
# ifdef __OpenBSD__
struct file;
# endif
# include <sys/uio.h>
# undef _KERNEL
#endif
#include <sys/socket.h>
#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
# include <sys/malloc.h>
#endif
#if defined(__FreeBSD__)
# include <sys/cdefs.h>
# include <sys/proc.h>
#endif
#if !defined(__svr4__) && !defined(__SVR4) && !defined(__hpux) && \
!defined(linux)
# include <sys/mbuf.h>
#endif
#if defined(_KERNEL)
# include <sys/systm.h>
#else
# include <stdio.h>
#endif
#include <netinet/in.h>
#include <net/if.h>
#include "netinet/ip_compat.h"
#include "netinet/ip_fil.h"
#include "netinet/ip_lookup.h"
#include "netinet/ip_htable.h"
/* END OF INCLUDES */
#if !defined(lint)
static const char rcsid[] = "@(#)Id: ip_htable.c,v 2.34.2.2 2004/10/17 15:49:15 darrenr Exp";
#endif
#ifdef IPFILTER_LOOKUP
static iphtent_t *fr_iphmfind __P((iphtable_t *, struct in_addr *));
static u_long ipht_nomem[IPL_LOGSIZE] = { 0, 0, 0, 0, 0, 0, 0, 0 };
static u_long ipf_nhtables[IPL_LOGSIZE] = { 0, 0, 0, 0, 0, 0, 0, 0 };
static u_long ipf_nhtnodes[IPL_LOGSIZE] = { 0, 0, 0, 0, 0, 0, 0, 0 };
iphtable_t *ipf_htables[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL };
void fr_htable_unload()
{
iplookupflush_t fop;
fop.iplf_unit = IPL_LOGALL;
(void)fr_flushhtable(&fop);
}
int fr_gethtablestat(op)
iplookupop_t *op;
{
iphtstat_t stats;
if (op->iplo_size != sizeof(stats))
return EINVAL;
stats.iphs_tables = ipf_htables[op->iplo_unit];
stats.iphs_numtables = ipf_nhtables[op->iplo_unit];
stats.iphs_numnodes = ipf_nhtnodes[op->iplo_unit];
stats.iphs_nomem = ipht_nomem[op->iplo_unit];
return COPYOUT(&stats, op->iplo_struct, sizeof(stats));
}
/*
* Create a new hash table using the template passed.
*/
int fr_newhtable(op)
iplookupop_t *op;
{
iphtable_t *iph, *oiph;
char name[FR_GROUPLEN];
int err, i, unit;
KMALLOC(iph, iphtable_t *);
if (iph == NULL)
return ENOMEM;
err = COPYIN(op->iplo_struct, iph, sizeof(*iph));
if (err != 0) {
KFREE(iph);
return EFAULT;
}
unit = op->iplo_unit;
if (iph->iph_unit != unit) {
KFREE(iph);
return EINVAL;
}
if ((op->iplo_arg & IPHASH_ANON) == 0) {
if (fr_findhtable(op->iplo_unit, op->iplo_name) != NULL) {
KFREE(iph);
return EEXIST;
}
} else {
i = IPHASH_ANON;
do {
i++;
#if defined(SNPRINTF) && defined(_KERNEL)
SNPRINTF(name, sizeof(name), "%u", i);
#else
(void)sprintf(name, "%u", i);
#endif
for (oiph = ipf_htables[unit]; oiph != NULL;
oiph = oiph->iph_next)
if (strncmp(oiph->iph_name, name,
sizeof(oiph->iph_name)) == 0)
break;
} while (oiph != NULL);
(void)strncpy(iph->iph_name, name, sizeof(iph->iph_name));
err = COPYOUT(iph, op->iplo_struct, sizeof(*iph));
if (err != 0) {
KFREE(iph);
return EFAULT;
}
iph->iph_type |= IPHASH_ANON;
}
KMALLOCS(iph->iph_table, iphtent_t **,
iph->iph_size * sizeof(*iph->iph_table));
if (iph->iph_table == NULL) {
KFREE(iph);
ipht_nomem[unit]++;
return ENOMEM;
}
bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
iph->iph_masks = 0;
iph->iph_next = ipf_htables[unit];
iph->iph_pnext = &ipf_htables[unit];
if (ipf_htables[unit] != NULL)
ipf_htables[unit]->iph_pnext = &iph->iph_next;
ipf_htables[unit] = iph;
ipf_nhtables[unit]++;
return 0;
}
/*
*/
int fr_removehtable(op)
iplookupop_t *op;
{
iphtable_t *iph;
iph = fr_findhtable(op->iplo_unit, op->iplo_name);
if (iph == NULL)
return ESRCH;
if (iph->iph_unit != op->iplo_unit) {
return EINVAL;
}
if (iph->iph_ref != 0) {
return EBUSY;
}
fr_delhtable(iph);
return 0;
}
void fr_delhtable(iph)
iphtable_t *iph;
{
iphtent_t *ipe;
int i;
for (i = 0; i < iph->iph_size; i++)
while ((ipe = iph->iph_table[i]) != NULL)
if (fr_delhtent(iph, ipe) != 0)
return;
*iph->iph_pnext = iph->iph_next;
if (iph->iph_next != NULL)
iph->iph_next->iph_pnext = iph->iph_pnext;
ipf_nhtables[iph->iph_unit]--;
if (iph->iph_ref == 0) {
KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
KFREE(iph);
}
}
void fr_derefhtable(iph)
iphtable_t *iph;
{
iph->iph_ref--;
if (iph->iph_ref == 0)
fr_delhtable(iph);
}
iphtable_t *fr_findhtable(unit, name)
int unit;
char *name;
{
iphtable_t *iph;
for (iph = ipf_htables[unit]; iph != NULL; iph = iph->iph_next)
if (strncmp(iph->iph_name, name, sizeof(iph->iph_name)) == 0)
break;
return iph;
}
size_t fr_flushhtable(op)
iplookupflush_t *op;
{
iphtable_t *iph;
size_t freed;
int i;
freed = 0;
for (i = 0; i <= IPL_LOGMAX; i++) {
if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) {
while ((iph = ipf_htables[i]) != NULL) {
fr_delhtable(iph);
freed++;
}
}
}
return freed;
}
/*
* Add an entry to a hash table.
*/
int fr_addhtent(iph, ipeo)
iphtable_t *iph;
iphtent_t *ipeo;
{
iphtent_t *ipe;
u_int hv;
int bits;
KMALLOC(ipe, iphtent_t *);
if (ipe == NULL)
return -1;
bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe));
ipe->ipe_addr.in4_addr &= ipe->ipe_mask.in4_addr;
ipe->ipe_addr.in4_addr = ntohl(ipe->ipe_addr.in4_addr);
bits = count4bits(ipe->ipe_mask.in4_addr);
ipe->ipe_mask.in4_addr = ntohl(ipe->ipe_mask.in4_addr);
hv = IPE_HASH_FN(ipe->ipe_addr.in4_addr, ipe->ipe_mask.in4_addr,
iph->iph_size);
ipe->ipe_ref = 0;
ipe->ipe_next = iph->iph_table[hv];
ipe->ipe_pnext = iph->iph_table + hv;
if (iph->iph_table[hv] != NULL)
iph->iph_table[hv]->ipe_pnext = &ipe->ipe_next;
iph->iph_table[hv] = ipe;
if ((bits >= 0) && (bits != 32))
iph->iph_masks |= 1 << bits;
switch (iph->iph_type & ~IPHASH_ANON)
{
case IPHASH_GROUPMAP :
ipe->ipe_ptr = fr_addgroup(ipe->ipe_group, NULL,
iph->iph_flags, IPL_LOGIPF,
fr_active);
break;
default :
ipe->ipe_ptr = NULL;
ipe->ipe_value = 0;
break;
}
ipf_nhtnodes[iph->iph_unit]++;
return 0;
}
/*
* Delete an entry from a hash table.
*/
int fr_delhtent(iph, ipe)
iphtable_t *iph;
iphtent_t *ipe;
{
if (ipe->ipe_ref != 0)
return EBUSY;
*ipe->ipe_pnext = ipe->ipe_next;
if (ipe->ipe_next != NULL)
ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
switch (iph->iph_type & ~IPHASH_ANON)
{
case IPHASH_GROUPMAP :
if (ipe->ipe_group != NULL)
fr_delgroup(ipe->ipe_group, IPL_LOGIPF, fr_active);
break;
default :
ipe->ipe_ptr = NULL;
ipe->ipe_value = 0;
break;
}
KFREE(ipe);
ipf_nhtnodes[iph->iph_unit]--;
return 0;
}
void *fr_iphmfindgroup(tptr, aptr)
void *tptr, *aptr;
{
struct in_addr *addr;
iphtable_t *iph;
iphtent_t *ipe;
void *rval;
READ_ENTER(&ip_poolrw);
iph = tptr;
addr = aptr;
ipe = fr_iphmfind(iph, addr);
if (ipe != NULL)
rval = ipe->ipe_ptr;
else
rval = NULL;
RWLOCK_EXIT(&ip_poolrw);
return rval;
}
/* ------------------------------------------------------------------------ */
/* Function: fr_iphmfindip */
/* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */
/* Parameters: tptr(I) - pointer to the pool to search */
/* version(I) - IP protocol version (4 or 6) */
/* aptr(I) - pointer to address information */
/* */
/* Search the hash table for a given address and return a search result. */
/* ------------------------------------------------------------------------ */
int fr_iphmfindip(tptr, version, aptr)
void *tptr, *aptr;
int version;
{
struct in_addr *addr;
iphtable_t *iph;
iphtent_t *ipe;
int rval;
if (version != 4)
return -1;
if (tptr == NULL || aptr == NULL)
return -1;
iph = tptr;
addr = aptr;
READ_ENTER(&ip_poolrw);
ipe = fr_iphmfind(iph, addr);
if (ipe != NULL)
rval = 0;
else
rval = 1;
RWLOCK_EXIT(&ip_poolrw);
return rval;
}
/* Locks: ip_poolrw */
static iphtent_t *fr_iphmfind(iph, addr)
iphtable_t *iph;
struct in_addr *addr;
{
u_32_t hmsk, msk, ips;
iphtent_t *ipe;
u_int hv;
hmsk = iph->iph_masks;
msk = 0xffffffff;
maskloop:
ips = ntohl(addr->s_addr) & msk;
hv = IPE_HASH_FN(ips, msk, iph->iph_size);
for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
if (ipe->ipe_mask.in4_addr != msk ||
ipe->ipe_addr.in4_addr != ips) {
continue;
}
break;
}
if ((ipe == NULL) && (hmsk != 0)) {
while (hmsk != 0) {
msk <<= 1;
if (hmsk & 0x80000000)
break;
hmsk <<= 1;
}
if (hmsk != 0) {
hmsk <<= 1;
goto maskloop;
}
}
return ipe;
}
#endif /* IPFILTER_LOOKUP */

View File

@ -0,0 +1,71 @@
/* $FreeBSD$ */
#ifndef __IP_HTABLE_H__
#define __IP_HTABLE_H__
#include "netinet/ip_lookup.h"
typedef struct iphtent_s {
struct iphtent_s *ipe_next, **ipe_pnext;
void *ipe_ptr;
i6addr_t ipe_addr;
i6addr_t ipe_mask;
int ipe_ref;
union {
char ipeu_char[16];
u_long ipeu_long;
u_int ipeu_int;
}ipe_un;
} iphtent_t;
#define ipe_value ipe_un.ipeu_int
#define ipe_group ipe_un.ipeu_char
#define IPE_HASH_FN(a, m, s) (((a) * (m)) % (s))
typedef struct iphtable_s {
ipfrwlock_t iph_rwlock;
struct iphtable_s *iph_next, **iph_pnext;
struct iphtent_s **iph_table;
size_t iph_size; /* size of hash table */
u_long iph_seed; /* hashing seed */
u_32_t iph_flags;
u_int iph_unit; /* IPL_LOG* */
u_int iph_ref;
u_int iph_type; /* lookup or group map - IPHASH_* */
u_int iph_masks; /* IPv4 netmasks in use */
char iph_name[FR_GROUPLEN]; /* hash table number */
} iphtable_t;
/* iph_type */
#define IPHASH_LOOKUP 0
#define IPHASH_GROUPMAP 1
#define IPHASH_ANON 0x80000000
typedef struct iphtstat_s {
iphtable_t *iphs_tables;
u_long iphs_numtables;
u_long iphs_numnodes;
u_long iphs_nomem;
u_long iphs_pad[16];
} iphtstat_t;
extern iphtable_t *ipf_htables[IPL_LOGSIZE];
extern void fr_htable_unload __P((void));
extern int fr_newhtable __P((iplookupop_t *));
extern iphtable_t *fr_findhtable __P((int, char *));
extern int fr_removehtable __P((iplookupop_t *));
extern size_t fr_flushhtable __P((iplookupflush_t *));
extern int fr_addhtent __P((iphtable_t *, iphtent_t *));
extern int fr_delhtent __P((iphtable_t *, iphtent_t *));
extern void fr_derefhtable __P((iphtable_t *));
extern void fr_delhtable __P((iphtable_t *));
extern void *fr_iphmfindgroup __P((void *, void *));
extern int fr_iphmfindip __P((void *, int, void *));
extern int fr_gethtablestat __P((iplookupop_t *));
#endif /* __IP_HTABLE_H__ */

View File

@ -1,42 +1,90 @@
/* $FreeBSD$ */
/*
* Copyright (C) 2001-2003 by Darren Reed
*
* See the IPFILTER.LICENCE file for details on licencing.
*
* Simple ISAKMP transparent proxy for in-kernel use. For use with the NAT
* code.
*
* $Id: ip_ipsec_pxy.c,v 1.1.2.10 2002/01/13 04:58:29 darrenr Exp $
* Id: ip_ipsec_pxy.c,v 2.20.2.6 2005/03/28 10:47:53 darrenr Exp
*
*/
#define IPF_IPSEC_PROXY
int ippr_ipsec_init __P((void));
int ippr_ipsec_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *));
void ippr_ipsec_fini __P((void));
int ippr_ipsec_new __P((fr_info_t *, ap_session_t *, nat_t *));
void ippr_ipsec_del __P((ap_session_t *));
int ippr_ipsec_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *));
int ippr_ipsec_inout __P((fr_info_t *, ap_session_t *, nat_t *));
int ippr_ipsec_match __P((fr_info_t *, ap_session_t *, nat_t *));
static frentry_t ipsecfr;
static ipftq_t *ipsecnattqe;
static ipftq_t *ipsecstatetqe;
static char ipsec_buffer[1500];
int ipsec_proxy_init = 0;
int ipsec_proxy_ttl = 60;
/*
* RCMD application proxy initialization.
* IPSec application proxy initialization.
*/
int ippr_ipsec_init()
{
bzero((char *)&ipsecfr, sizeof(ipsecfr));
ipsecfr.fr_ref = 1;
ipsecfr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
MUTEX_INIT(&ipsecfr.fr_lock, "IPsec proxy rule lock");
ipsec_proxy_init = 1;
ipsecnattqe = fr_addtimeoutqueue(&nat_utqe, ipsec_proxy_ttl);
if (ipsecnattqe == NULL)
return -1;
ipsecstatetqe = fr_addtimeoutqueue(&ips_utqe, ipsec_proxy_ttl);
if (ipsecstatetqe == NULL) {
if (fr_deletetimeoutqueue(ipsecnattqe) == 0)
fr_freetimeoutqueue(ipsecnattqe);
ipsecnattqe = NULL;
return -1;
}
ipsecnattqe->ifq_flags |= IFQF_PROXY;
ipsecstatetqe->ifq_flags |= IFQF_PROXY;
ipsecfr.fr_age[0] = ipsec_proxy_ttl;
ipsecfr.fr_age[1] = ipsec_proxy_ttl;
return 0;
}
void ippr_ipsec_fini()
{
if (ipsecnattqe != NULL) {
if (fr_deletetimeoutqueue(ipsecnattqe) == 0)
fr_freetimeoutqueue(ipsecnattqe);
}
ipsecnattqe = NULL;
if (ipsecstatetqe != NULL) {
if (fr_deletetimeoutqueue(ipsecstatetqe) == 0)
fr_freetimeoutqueue(ipsecstatetqe);
}
ipsecstatetqe = NULL;
if (ipsec_proxy_init == 1) {
MUTEX_DESTROY(&ipsecfr.fr_lock);
ipsec_proxy_init = 0;
}
}
/*
* Setup for a new IPSEC proxy.
*/
int ippr_ipsec_new(fin, ip, aps, nat)
int ippr_ipsec_new(fin, aps, nat)
fr_info_t *fin;
ip_t *ip;
ap_session_t *aps;
nat_t *nat;
{
@ -44,40 +92,22 @@ nat_t *nat;
fr_info_t fi;
ipnat_t *ipn;
char *ptr;
int p, off, dlen;
int p, off, dlen, ttl;
mb_t *m;
ip_t *ip;
bzero(ipsec_buffer, sizeof(ipsec_buffer));
off = fin->fin_hlen + sizeof(udphdr_t);
#ifdef _KERNEL
# if SOLARIS
m = fin->fin_qfm;
ip = fin->fin_ip;
m = fin->fin_m;
dlen = msgdsize(m) - off;
dlen = M_LEN(m) - off;
if (dlen < 16)
return -1;
copyout_mblk(m, off, MIN(sizeof(ipsec_buffer), dlen), ipsec_buffer);
# else
m = *(mb_t **)fin->fin_mp;
dlen = mbufchainlen(m) - off;
if (dlen < 16)
return -1;
m_copydata(m, off, MIN(sizeof(ipsec_buffer), dlen), ipsec_buffer);
# endif
#else
m = *(mb_t **)fin->fin_mp;
dlen = ip->ip_len - off;
ptr = (char *)m;
ptr += off;
bcopy(ptr, ipsec_buffer, MIN(sizeof(ipsec_buffer), dlen));
#endif
COPYDATA(m, off, MIN(sizeof(ipsec_buffer), dlen), ipsec_buffer);
/*
* Because _new() gets called from nat_new(), ipf_nat is held with a
* write lock so pass rw=1 to nat_outlookup().
*/
if (nat_outlookup(fin, 0, IPPROTO_ESP, nat->nat_inip,
ip->ip_dst, 1) != NULL)
ip->ip_dst) != NULL)
return -1;
aps->aps_psiz = sizeof(*ipsec);
@ -94,7 +124,10 @@ nat_t *nat;
* describe ESP but UDP instead.
*/
ipn = &ipsec->ipsc_rule;
ipn->in_ifp = fin->fin_ifp;
ttl = IPF_TTLVAL(ipsecnattqe->ifq_ttl);
ipn->in_tqehead[0] = fr_addtimeoutqueue(&nat_utqe, ttl);
ipn->in_tqehead[1] = fr_addtimeoutqueue(&nat_utqe, ttl);
ipn->in_ifps[0] = fin->fin_ifp;
ipn->in_apr = NULL;
ipn->in_use = 1;
ipn->in_hits = 1;
@ -102,27 +135,31 @@ nat_t *nat;
ipn->in_ippip = 1;
ipn->in_inip = nat->nat_inip.s_addr;
ipn->in_inmsk = 0xffffffff;
ipn->in_outip = nat->nat_outip.s_addr;
ipn->in_outmsk = 0xffffffff;
ipn->in_outip = fin->fin_saddr;
ipn->in_outmsk = nat->nat_outip.s_addr;
ipn->in_srcip = fin->fin_saddr;
ipn->in_srcmsk = 0xffffffff;
ipn->in_redir = NAT_MAP;
bcopy(nat->nat_ptr->in_ifname, ipn->in_ifname, sizeof(ipn->in_ifname));
bcopy(nat->nat_ptr->in_ifnames[0], ipn->in_ifnames[0],
sizeof(ipn->in_ifnames[0]));
ipn->in_p = IPPROTO_ESP;
bcopy((char *)fin, (char *)&fi, sizeof(fi));
fi.fin_state = NULL;
fi.fin_nat = NULL;
fi.fin_fi.fi_p = IPPROTO_ESP;
fi.fin_fr = &ipsecfr;
fi.fin_data[0] = 0;
fi.fin_data[1] = 0;
p = ip->ip_p;
ip->ip_p = IPPROTO_ESP;
fi.fin_fl &= ~FI_TCPUDP;
fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG);
fi.fin_flx |= FI_IGNORE;
ptr = ipsec_buffer;
bcopy(ptr, ipsec->ipsc_icookie, sizeof(ipsec_cookie_t));
bcopy(ptr, (char *)ipsec->ipsc_icookie, sizeof(ipsec_cookie_t));
ptr += sizeof(ipsec_cookie_t);
bcopy(ptr, ipsec->ipsc_rcookie, sizeof(ipsec_cookie_t));
bcopy(ptr, (char *)ipsec->ipsc_rcookie, sizeof(ipsec_cookie_t));
/*
* The responder cookie should only be non-zero if the initiator
* cookie is non-zero. Therefore, it is safe to assume(!) that the
@ -130,76 +167,101 @@ nat_t *nat;
*/
if ((ipsec->ipsc_rcookie[0]|ipsec->ipsc_rcookie[1]) != 0)
ipsec->ipsc_rckset = 1;
else
nat->nat_age = 60; /* 30 seconds */
ipsec->ipsc_nat = nat_new(&fi, ip, ipn, &ipsec->ipsc_nat, FI_IGNOREPKT,
NAT_OUTBOUND);
ipsec->ipsc_nat = nat_new(&fi, ipn, &ipsec->ipsc_nat,
NAT_SLAVE|SI_WILDP, NAT_OUTBOUND);
if (ipsec->ipsc_nat != NULL) {
(void) nat_proto(&fi, ipsec->ipsc_nat, 0);
nat_update(&fi, ipsec->ipsc_nat, ipn);
fi.fin_data[0] = 0;
fi.fin_data[1] = 0;
ipsec->ipsc_state = fr_addstate(ip, &fi, &ipsec->ipsc_state,
FI_IGNOREPKT|FI_NORULE);
ipsec->ipsc_state = fr_addstate(&fi, &ipsec->ipsc_state,
SI_WILDP);
if (fi.fin_state != NULL)
fr_statederef(&fi, (ipstate_t **)&fi.fin_state);
}
ip->ip_p = p;
ip->ip_p = p & 0xff;
return 0;
}
/*
* For outgoing IKE packets. refresh timeouts for NAT & stat entries, if
* For outgoing IKE packets. refresh timeouts for NAT & state entries, if
* we can. If they have disappeared, recreate them.
*/
int ippr_ipsec_out(fin, ip, aps, nat)
int ippr_ipsec_inout(fin, aps, nat)
fr_info_t *fin;
ip_t *ip;
ap_session_t *aps;
nat_t *nat;
{
ipsec_pxy_t *ipsec;
fr_info_t fi;
ip_t *ip;
int p;
bcopy((char *)fin, (char *)&fi, sizeof(fi));
fi.fin_fi.fi_p = IPPROTO_ESP;
fi.fin_fr = &ipsecfr;
fi.fin_data[0] = 0;
fi.fin_data[1] = 0;
p = ip->ip_p;
ip->ip_p = IPPROTO_ESP;
fi.fin_fl &= ~FI_TCPUDP;
if ((fin->fin_out == 1) && (nat->nat_dir == NAT_INBOUND))
return 0;
if ((fin->fin_out == 0) && (nat->nat_dir == NAT_OUTBOUND))
return 0;
ipsec = aps->aps_data;
if (ipsec != NULL) {
ip = fin->fin_ip;
p = ip->ip_p;
if ((ipsec->ipsc_nat == NULL) || (ipsec->ipsc_state == NULL)) {
bcopy((char *)fin, (char *)&fi, sizeof(fi));
fi.fin_state = NULL;
fi.fin_nat = NULL;
fi.fin_fi.fi_p = IPPROTO_ESP;
fi.fin_fr = &ipsecfr;
fi.fin_data[0] = 0;
fi.fin_data[1] = 0;
ip->ip_p = IPPROTO_ESP;
fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG);
fi.fin_flx |= FI_IGNORE;
}
/*
* Update NAT timeout/create NAT if missing.
*/
if (ipsec->ipsc_rckset == 0)
nat->nat_age = 60; /* 30 seconds */
if (ipsec->ipsc_nat != NULL)
ipsec->ipsc_nat->nat_age = nat->nat_age;
else
ipsec->ipsc_nat = nat_new(&fi, ip, &ipsec->ipsc_rule,
fr_queueback(&ipsec->ipsc_nat->nat_tqe);
else {
ipsec->ipsc_nat = nat_new(&fi, &ipsec->ipsc_rule,
&ipsec->ipsc_nat,
FI_IGNOREPKT, NAT_OUTBOUND);
NAT_SLAVE|SI_WILDP,
nat->nat_dir);
if (ipsec->ipsc_nat != NULL) {
(void) nat_proto(&fi, ipsec->ipsc_nat, 0);
nat_update(&fi, ipsec->ipsc_nat,
&ipsec->ipsc_rule);
}
}
/*
* Update state timeout/create state if missing.
*/
READ_ENTER(&ipf_state);
if (ipsec->ipsc_state != NULL) {
ipsec->ipsc_state->is_age = nat->nat_age;
fr_queueback(&ipsec->ipsc_state->is_sti);
ipsec->ipsc_state->is_die = nat->nat_age;
RWLOCK_EXIT(&ipf_state);
} else {
RWLOCK_EXIT(&ipf_state);
fi.fin_data[0] = 0;
fi.fin_data[1] = 0;
ipsec->ipsc_state = fr_addstate(ip, &fi,
ipsec->ipsc_state = fr_addstate(&fi,
&ipsec->ipsc_state,
FI_IGNOREPKT|FI_NORULE);
SI_WILDP);
if (fi.fin_state != NULL)
fr_statederef(&fi, (ipstate_t **)&fi.fin_state);
}
ip->ip_p = p;
}
ip->ip_p = p;
return 0;
}
@ -220,24 +282,15 @@ nat_t *nat;
mb_t *m;
int off;
if ((fin->fin_dlen < sizeof(cookies)) || (fin->fin_fl & FI_FRAG))
nat = nat; /* LINT */
if ((fin->fin_dlen < sizeof(cookies)) || (fin->fin_flx & FI_FRAG))
return -1;
ipsec = aps->aps_data;
off = fin->fin_hlen + sizeof(udphdr_t);
#ifdef _KERNEL
# if SOLARIS
m = fin->fin_qfm;
copyout_mblk(m, off, sizeof(cookies), (char *)cookies);
# else
m = *(mb_t **)fin->fin_mp;
m_copydata(m, off, sizeof(cookies), (char *)cookies);
# endif
#else
m = *(mb_t **)fin->fin_mp;
bcopy((char *)m + off, cookies, sizeof(cookies));
#endif
m = fin->fin_m;
COPYDATA(m, off, sizeof(cookies), (char *)cookies);
if ((cookies[0] != ipsec->ipsc_icookie[0]) ||
(cookies[1] != ipsec->ipsc_icookie[1]))
@ -245,7 +298,6 @@ nat_t *nat;
if (ipsec->ipsc_rckset == 0) {
if ((cookies[2]|cookies[3]) == 0) {
nat->nat_age = 60; /* 30 seconds */
return 0;
}
ipsec->ipsc_rckset = 1;
@ -273,17 +325,16 @@ ap_session_t *aps;
if (ipsec != NULL) {
/*
* Don't delete it from here, just schedule it to be
* deleted ASAP.
* Don't bother changing any of the NAT structure details,
* *_del() is on a callback from aps_free(), from nat_delete()
*/
if (ipsec->ipsc_nat != NULL) {
ipsec->ipsc_nat->nat_age = 1;
ipsec->ipsc_nat->nat_ptr = NULL;
}
READ_ENTER(&ipf_state);
if (ipsec->ipsc_state != NULL)
ipsec->ipsc_state->is_age = 1;
if (ipsec->ipsc_state != NULL) {
ipsec->ipsc_state->is_die = fr_ticks + 1;
ipsec->ipsc_state->is_me = NULL;
fr_queuefront(&ipsec->ipsc_state->is_sti);
}
RWLOCK_EXIT(&ipf_state);
ipsec->ipsc_state = NULL;

View File

@ -0,0 +1,435 @@
/* $FreeBSD$ */
/*
* Copyright (C) 2000-2003 Darren Reed
*
* See the IPFILTER.LICENCE file for details on licencing.
*
* Id: ip_irc_pxy.c,v 2.39.2.4 2005/02/04 10:22:55 darrenr Exp
*/
#define IPF_IRC_PROXY
#define IPF_IRCBUFSZ 96 /* This *MUST* be >= 64! */
int ippr_irc_init __P((void));
void ippr_irc_fini __P((void));
int ippr_irc_new __P((fr_info_t *, ap_session_t *, nat_t *));
int ippr_irc_out __P((fr_info_t *, ap_session_t *, nat_t *));
int ippr_irc_send __P((fr_info_t *, nat_t *));
int ippr_irc_complete __P((ircinfo_t *, char *, size_t));
u_short ipf_irc_atoi __P((char **));
static frentry_t ircnatfr;
int irc_proxy_init = 0;
/*
* Initialize local structures.
*/
int ippr_irc_init()
{
bzero((char *)&ircnatfr, sizeof(ircnatfr));
ircnatfr.fr_ref = 1;
ircnatfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
MUTEX_INIT(&ircnatfr.fr_lock, "IRC proxy rule lock");
irc_proxy_init = 1;
return 0;
}
void ippr_irc_fini()
{
if (irc_proxy_init == 1) {
MUTEX_DESTROY(&ircnatfr.fr_lock);
irc_proxy_init = 0;
}
}
char *ippr_irc_dcctypes[] = {
"CHAT ", /* CHAT chat ipnumber portnumber */
"SEND ", /* SEND filename ipnumber portnumber */
"MOVE ",
"TSEND ",
"SCHAT ",
NULL,
};
/*
* :A PRIVMSG B :^ADCC CHAT chat 0 0^A\r\n
* PRIVMSG B ^ADCC CHAT chat 0 0^A\r\n
*/
int ippr_irc_complete(ircp, buf, len)
ircinfo_t *ircp;
char *buf;
size_t len;
{
register char *s, c;
register size_t i;
u_32_t l;
int j, k;
ircp->irc_ipnum = 0;
ircp->irc_port = 0;
if (len < 31)
return 0;
s = buf;
c = *s++;
i = len - 1;
if ((c != ':') && (c != 'P'))
return 0;
if (c == ':') {
/*
* Loosely check that the source is a nickname of some sort
*/
s++;
c = *s;
ircp->irc_snick = s;
if (!ISALPHA(c))
return 0;
i--;
for (c = *s; !ISSPACE(c) && (i > 0); i--)
c = *s++;
if (i < 31)
return 0;
if (c != 'P')
return 0;
} else
ircp->irc_snick = NULL;
/*
* Check command string
*/
if (strncmp(s, "PRIVMSG ", 8))
return 0;
i -= 8;
s += 8;
c = *s;
ircp->irc_dnick = s;
/*
* Loosely check that the destination is a nickname of some sort
*/
if (!ISALPHA(c))
return 0;
for (; !ISSPACE(c) && (i > 0); i--)
c = *s++;
if (i < 20)
return 0;
s++,
i--;
/*
* Look for a ^A to start the DCC
*/
c = *s;
if (c == ':') {
s++;
c = *s;
}
if (strncmp(s, "\001DCC ", 4))
return 0;
i -= 4;
s += 4;
/*
* Check for a recognised DCC command
*/
for (j = 0, k = 0; ippr_irc_dcctypes[j]; j++) {
k = MIN(strlen(ippr_irc_dcctypes[j]), i);
if (!strncmp(ippr_irc_dcctypes[j], s, k))
break;
}
if (!ippr_irc_dcctypes[j])
return 0;
ircp->irc_type = s;
i -= k;
s += k;
if (i < 11)
return 0;
/*
* Check for the arg
*/
c = *s;
if (ISSPACE(c))
return 0;
ircp->irc_arg = s;
for (; (c != ' ') && (c != '\001') && (i > 0); i--)
c = *s++;
if (c == '\001') /* In reality a ^A can quote another ^A...*/
return 0;
if (i < 5)
return 0;
s++;
i--;
c = *s;
if (!ISDIGIT(c))
return 0;
ircp->irc_addr = s;
/*
* Get the IP#
*/
for (l = 0; ISDIGIT(c) && (i > 0); i--) {
l *= 10;
l += c - '0';
c = *s++;
}
if (i < 4)
return 0;
if (c != ' ')
return 0;
ircp->irc_ipnum = l;
s++;
i--;
c = *s;
if (!ISDIGIT(c))
return 0;
/*
* Get the port#
*/
for (l = 0; ISDIGIT(c) && (i > 0); i--) {
l *= 10;
l += c - '0';
c = *s++;
}
if (i < 3)
return 0;
if (strncmp(s, "\001\r\n", 3))
return 0;
s += 3;
ircp->irc_len = s - buf;
ircp->irc_port = l;
return 1;
}
int ippr_irc_new(fin, aps, nat)
fr_info_t *fin;
ap_session_t *aps;
nat_t *nat;
{
ircinfo_t *irc;
KMALLOC(irc, ircinfo_t *);
if (irc == NULL)
return -1;
fin = fin; /* LINT */
nat = nat; /* LINT */
aps->aps_data = irc;
aps->aps_psiz = sizeof(ircinfo_t);
bzero((char *)irc, sizeof(*irc));
return 0;
}
int ippr_irc_send(fin, nat)
fr_info_t *fin;
nat_t *nat;
{
char ctcpbuf[IPF_IRCBUFSZ], newbuf[IPF_IRCBUFSZ];
tcphdr_t *tcp, tcph, *tcp2 = &tcph;
int off, inc = 0, i, dlen;
size_t nlen = 0, olen;
struct in_addr swip;
u_short a5, sp;
ircinfo_t *irc;
fr_info_t fi;
nat_t *nat2;
u_int a1;
ip_t *ip;
mb_t *m;
#ifdef MENTAT
mb_t *m1;
#endif
m = fin->fin_m;
ip = fin->fin_ip;
tcp = (tcphdr_t *)fin->fin_dp;
bzero(ctcpbuf, sizeof(ctcpbuf));
off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
#ifdef __sgi
dlen = fin->fin_plen - off;
#else
dlen = MSGDSIZE(m) - off;
#endif
if (dlen <= 0)
return 0;
COPYDATA(m, off, MIN(sizeof(ctcpbuf), dlen), ctcpbuf);
if (dlen <= 0)
return 0;
ctcpbuf[sizeof(ctcpbuf) - 1] = '\0';
*newbuf = '\0';
irc = nat->nat_aps->aps_data;
if (ippr_irc_complete(irc, ctcpbuf, dlen) == 0)
return 0;
/*
* check that IP address in the PORT/PASV reply is the same as the
* sender of the command - prevents using PORT for port scanning.
*/
if (irc->irc_ipnum != ntohl(nat->nat_inip.s_addr))
return 0;
a5 = irc->irc_port;
/*
* Calculate new address parts for the DCC command
*/
a1 = ntohl(ip->ip_src.s_addr);
olen = irc->irc_len;
i = irc->irc_addr - ctcpbuf;
i++;
(void) strncpy(newbuf, ctcpbuf, i);
/* DO NOT change these! */
#if defined(SNPRINTF) && defined(KERNEL)
SNPRINTF(newbuf, sizeof(newbuf) - i, "%u %u\001\r\n", a1, a5);
#else
(void) sprintf(newbuf, "%u %u\001\r\n", a1, a5);
#endif
nlen = strlen(newbuf);
inc = nlen - olen;
if ((inc + ip->ip_len) > 65535)
return 0;
#ifdef MENTAT
for (m1 = m; m1->b_cont; m1 = m1->b_cont)
;
if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) {
mblk_t *nm;
/* alloc enough to keep same trailer space for lower driver */
nm = allocb(nlen, BPRI_MED);
PANIC((!nm),("ippr_irc_out: allocb failed"));
nm->b_band = m1->b_band;
nm->b_wptr += nlen;
m1->b_wptr -= olen;
PANIC((m1->b_wptr < m1->b_rptr),
("ippr_irc_out: cannot handle fragmented data block"));
linkb(m1, nm);
} else {
# if SOLARIS && defined(ICK_VALID)
if (m1->b_datap->db_struiolim == m1->b_wptr)
m1->b_datap->db_struiolim += inc;
m1->b_datap->db_struioflag &= ~STRUIO_IP;
# endif
m1->b_wptr += inc;
}
#else
if (inc < 0)
m_adj(m, inc);
/* the mbuf chain will be extended if necessary by m_copyback() */
#endif
COPYBACK(m, off, nlen, newbuf);
if (inc != 0) {
#if defined(MENTAT) || defined(__sgi)
register u_32_t sum1, sum2;
sum1 = ip->ip_len;
sum2 = ip->ip_len + inc;
/* Because ~1 == -2, We really need ~1 == -1 */
if (sum1 > sum2)
sum2--;
sum2 -= sum1;
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
fix_outcksum(fin, &ip->ip_sum, sum2);
#endif
ip->ip_len += inc;
}
/*
* Add skeleton NAT entry for connection which will come back the
* other way.
*/
sp = htons(a5);
/*
* Don't allow the PORT command to specify a port < 1024 due to
* security crap.
*/
if (ntohs(sp) < 1024)
return 0;
/*
* The server may not make the connection back from port 20, but
* it is the most likely so use it here to check for a conflicting
* mapping.
*/
bcopy((caddr_t)fin, (caddr_t)&fi, sizeof(fi));
fi.fin_data[0] = sp;
fi.fin_data[1] = fin->fin_data[1];
nat2 = nat_outlookup(fin, IPN_TCP, nat->nat_p, nat->nat_inip,
ip->ip_dst);
if (nat2 == NULL) {
bcopy((caddr_t)fin, (caddr_t)&fi, sizeof(fi));
bzero((char *)tcp2, sizeof(*tcp2));
tcp2->th_win = htons(8192);
tcp2->th_sport = sp;
tcp2->th_dport = 0; /* XXX - don't specify remote port */
fi.fin_state = NULL;
fi.fin_nat = NULL;
fi.fin_data[0] = ntohs(sp);
fi.fin_data[1] = 0;
fi.fin_dp = (char *)tcp2;
fi.fin_fr = &ircnatfr;
fi.fin_dlen = sizeof(*tcp2);
fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
swip = ip->ip_src;
ip->ip_src = nat->nat_inip;
nat2 = nat_new(&fi, nat->nat_ptr, NULL,
NAT_SLAVE|IPN_TCP|SI_W_DPORT, NAT_OUTBOUND);
if (nat2 != NULL) {
(void) nat_proto(&fi, nat2, 0);
nat_update(&fi, nat2, nat2->nat_ptr);
(void) fr_addstate(&fi, NULL, SI_W_DPORT);
if (fi.fin_state != NULL)
fr_statederef(&fi, (ipstate_t **)&fi.fin_state);
}
ip->ip_src = swip;
}
return inc;
}
int ippr_irc_out(fin, aps, nat)
fr_info_t *fin;
ap_session_t *aps;
nat_t *nat;
{
aps = aps; /* LINT */
return ippr_irc_send(fin, nat);
}

View File

@ -0,0 +1,530 @@
/* $FreeBSD$ */
/*
* Copyright (C) 2002-2003 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*/
#if defined(KERNEL) || defined(_KERNEL)
# undef KERNEL
# undef _KERNEL
# define KERNEL 1
# define _KERNEL 1
#endif
#if defined(__osf__)
# define _PROTO_NET_H_
#endif
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/types.h>
#include <sys/time.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
#if !defined(_KERNEL)
# include <string.h>
# define _KERNEL
# ifdef __OpenBSD__
struct file;
# endif
# include <sys/uio.h>
# undef _KERNEL
#endif
#include <sys/socket.h>
#if (defined(__osf__) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL)
# ifdef __osf__
# include <net/radix.h>
# endif
# include "radix_ipf_local.h"
# define _RADIX_H_
#endif
#include <net/if.h>
#if defined(__FreeBSD__)
# include <sys/cdefs.h>
# include <sys/proc.h>
#endif
#if defined(_KERNEL)
# include <sys/systm.h>
# if !defined(__SVR4) && !defined(__svr4__)
# include <sys/mbuf.h>
# endif
#endif
#include <netinet/in.h>
#include "netinet/ip_compat.h"
#include "netinet/ip_fil.h"
#include "netinet/ip_pool.h"
#include "netinet/ip_htable.h"
#include "netinet/ip_lookup.h"
/* END OF INCLUDES */
#if !defined(lint)
static const char rcsid[] = "@(#)Id: ip_lookup.c,v 2.35.2.5 2004/07/06 11:16:25 darrenr Exp";
#endif
#ifdef IPFILTER_LOOKUP
int ip_lookup_inited = 0;
static int iplookup_addnode __P((caddr_t));
static int iplookup_delnode __P((caddr_t data));
static int iplookup_addtable __P((caddr_t));
static int iplookup_deltable __P((caddr_t));
static int iplookup_stats __P((caddr_t));
static int iplookup_flush __P((caddr_t));
/* ------------------------------------------------------------------------ */
/* Function: iplookup_init */
/* Returns: int - 0 = success, else error */
/* Parameters: Nil */
/* */
/* Initialise all of the subcomponents of the lookup infrstructure. */
/* ------------------------------------------------------------------------ */
int ip_lookup_init()
{
if (ip_pool_init() == -1)
return -1;
RWLOCK_INIT(&ip_poolrw, "ip pool rwlock");
ip_lookup_inited = 1;
return 0;
}
/* ------------------------------------------------------------------------ */
/* Function: iplookup_unload */
/* Returns: int - 0 = success, else error */
/* Parameters: Nil */
/* */
/* Free up all pool related memory that has been allocated whilst IPFilter */
/* has been running. Also, do any other deinitialisation required such */
/* ip_lookup_init() can be called again, safely. */
/* ------------------------------------------------------------------------ */
void ip_lookup_unload()
{
ip_pool_fini();
fr_htable_unload();
if (ip_lookup_inited == 1) {
RW_DESTROY(&ip_poolrw);
ip_lookup_inited = 0;
}
}
/* ------------------------------------------------------------------------ */
/* Function: iplookup_ioctl */
/* Returns: int - 0 = success, else error */
/* Parameters: data(IO) - pointer to ioctl data to be copied to/from user */
/* space. */
/* cmd(I) - ioctl command number */
/* mode(I) - file mode bits used with open */
/* */
/* Handle ioctl commands sent to the ioctl device. For the most part, this */
/* involves just calling another function to handle the specifics of each */
/* command. */
/* ------------------------------------------------------------------------ */
int ip_lookup_ioctl(data, cmd, mode)
caddr_t data;
ioctlcmd_t cmd;
int mode;
{
int err;
# if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL)
int s;
# endif
mode = mode; /* LINT */
SPL_NET(s);
switch (cmd)
{
case SIOCLOOKUPADDNODE :
case SIOCLOOKUPADDNODEW :
WRITE_ENTER(&ip_poolrw);
err = iplookup_addnode(data);
RWLOCK_EXIT(&ip_poolrw);
break;
case SIOCLOOKUPDELNODE :
case SIOCLOOKUPDELNODEW :
WRITE_ENTER(&ip_poolrw);
err = iplookup_delnode(data);
RWLOCK_EXIT(&ip_poolrw);
break;
case SIOCLOOKUPADDTABLE :
WRITE_ENTER(&ip_poolrw);
err = iplookup_addtable(data);
RWLOCK_EXIT(&ip_poolrw);
break;
case SIOCLOOKUPDELTABLE :
WRITE_ENTER(&ip_poolrw);
err = iplookup_deltable(data);
RWLOCK_EXIT(&ip_poolrw);
break;
case SIOCLOOKUPSTAT :
case SIOCLOOKUPSTATW :
WRITE_ENTER(&ip_poolrw);
err = iplookup_stats(data);
RWLOCK_EXIT(&ip_poolrw);
break;
case SIOCLOOKUPFLUSH :
WRITE_ENTER(&ip_poolrw);
err = iplookup_flush(data);
RWLOCK_EXIT(&ip_poolrw);
break;
default :
err = EINVAL;
break;
}
SPL_X(s);
return err;
}
/* ------------------------------------------------------------------------ */
/* Function: iplookup_addnode */
/* Returns: int - 0 = success, else error */
/* Parameters: data(I) - pointer to data from ioctl call */
/* */
/* Add a new data node to a lookup structure. First, check to see if the */
/* parent structure refered to by name exists and if it does, then go on to */
/* add a node to it. */
/* ------------------------------------------------------------------------ */
static int iplookup_addnode(data)
caddr_t data;
{
ip_pool_node_t node, *m;
iplookupop_t op;
iphtable_t *iph;
iphtent_t hte;
ip_pool_t *p;
int err;
err = 0;
BCOPYIN(data, &op, sizeof(op));
op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
switch (op.iplo_type)
{
case IPLT_POOL :
if (op.iplo_size != sizeof(node))
return EINVAL;
err = COPYIN(op.iplo_struct, &node, sizeof(node));
if (err != 0)
return EFAULT;
p = ip_pool_find(op.iplo_unit, op.iplo_name);
if (p == NULL)
return ESRCH;
/*
* add an entry to a pool - return an error if it already
* exists remove an entry from a pool - if it exists
* - in both cases, the pool *must* exist!
*/
m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask);
if (m)
return EEXIST;
err = ip_pool_insert(p, &node.ipn_addr.adf_addr,
&node.ipn_mask.adf_addr, node.ipn_info);
break;
case IPLT_HASH :
if (op.iplo_size != sizeof(hte))
return EINVAL;
err = COPYIN(op.iplo_struct, &hte, sizeof(hte));
if (err != 0)
return EFAULT;
iph = fr_findhtable(op.iplo_unit, op.iplo_name);
if (iph == NULL)
return ESRCH;
err = fr_addhtent(iph, &hte);
break;
default :
err = EINVAL;
break;
}
return err;
}
/* ------------------------------------------------------------------------ */
/* Function: iplookup_delnode */
/* Returns: int - 0 = success, else error */
/* Parameters: data(I) - pointer to data from ioctl call */
/* */
/* Delete a node from a lookup table by first looking for the table it is */
/* in and then deleting the entry that gets found. */
/* ------------------------------------------------------------------------ */
static int iplookup_delnode(data)
caddr_t data;
{
ip_pool_node_t node, *m;
iplookupop_t op;
iphtable_t *iph;
iphtent_t hte;
ip_pool_t *p;
int err;
err = 0;
BCOPYIN(data, &op, sizeof(op));
op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
switch (op.iplo_type)
{
case IPLT_POOL :
if (op.iplo_size != sizeof(node))
return EINVAL;
err = COPYIN(op.iplo_struct, &node, sizeof(node));
if (err != 0)
return EFAULT;
p = ip_pool_find(op.iplo_unit, op.iplo_name);
if (!p)
return ESRCH;
m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask);
if (m == NULL)
return ENOENT;
err = ip_pool_remove(p, m);
break;
case IPLT_HASH :
if (op.iplo_size != sizeof(hte))
return EINVAL;
err = COPYIN(op.iplo_struct, &hte, sizeof(hte));
if (err != 0)
return EFAULT;
iph = fr_findhtable(op.iplo_unit, op.iplo_name);
if (iph == NULL)
return ESRCH;
err = fr_delhtent(iph, &hte);
break;
default :
err = EINVAL;
break;
}
return err;
}
/* ------------------------------------------------------------------------ */
/* Function: iplookup_addtable */
/* Returns: int - 0 = success, else error */
/* Parameters: data(I) - pointer to data from ioctl call */
/* */
/* Create a new lookup table, if one doesn't already exist using the name */
/* for this one. */
/* ------------------------------------------------------------------------ */
static int iplookup_addtable(data)
caddr_t data;
{
iplookupop_t op;
int err;
err = 0;
BCOPYIN(data, &op, sizeof(op));
op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
switch (op.iplo_type)
{
case IPLT_POOL :
if (ip_pool_find(op.iplo_unit, op.iplo_name) != NULL)
err = EEXIST;
else
err = ip_pool_create(&op);
break;
case IPLT_HASH :
if (fr_findhtable(op.iplo_unit, op.iplo_name) != NULL)
err = EEXIST;
else
err = fr_newhtable(&op);
break;
default :
err = EINVAL;
break;
}
return err;
}
/* ------------------------------------------------------------------------ */
/* Function: iplookup_deltable */
/* Returns: int - 0 = success, else error */
/* Parameters: data(I) - pointer to data from ioctl call */
/* */
/* Decodes ioctl request to remove a particular hash table or pool and */
/* calls the relevant function to do the cleanup. */
/* ------------------------------------------------------------------------ */
static int iplookup_deltable(data)
caddr_t data;
{
iplookupop_t op;
int err;
BCOPYIN(data, &op, sizeof(op));
op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
if (op.iplo_arg & IPLT_ANON)
op.iplo_arg &= IPLT_ANON;
/*
* create a new pool - fail if one already exists with
* the same #
*/
switch (op.iplo_type)
{
case IPLT_POOL :
err = ip_pool_destroy(&op);
break;
case IPLT_HASH :
err = fr_removehtable(&op);
break;
default :
err = EINVAL;
break;
}
return err;
}
/* ------------------------------------------------------------------------ */
/* Function: iplookup_stats */
/* Returns: int - 0 = success, else error */
/* Parameters: data(I) - pointer to data from ioctl call */
/* */
/* Copy statistical information from inside the kernel back to user space. */
/* ------------------------------------------------------------------------ */
static int iplookup_stats(data)
caddr_t data;
{
iplookupop_t op;
int err;
err = 0;
BCOPYIN(data, &op, sizeof(op));
switch (op.iplo_type)
{
case IPLT_POOL :
err = ip_pool_statistics(&op);
break;
case IPLT_HASH :
err = fr_gethtablestat(&op);
break;
default :
err = EINVAL;
break;
}
return err;
}
/* ------------------------------------------------------------------------ */
/* Function: iplookup_flush */
/* Returns: int - 0 = success, else error */
/* Parameters: data(I) - pointer to data from ioctl call */
/* */
/* A flush is called when we want to flush all the nodes from a particular */
/* entry in the hash table/pool or want to remove all groups from those. */
/* ------------------------------------------------------------------------ */
static int iplookup_flush(data)
caddr_t data;
{
int err, unit, num, type;
iplookupflush_t flush;
err = 0;
BCOPYIN(data, &flush, sizeof(flush));
flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0';
unit = flush.iplf_unit;
if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL))
return EINVAL;
type = flush.iplf_type;
err = EINVAL;
num = 0;
if (type == IPLT_POOL || type == IPLT_ALL) {
err = 0;
num = ip_pool_flush(&flush);
}
if (type == IPLT_HASH || type == IPLT_ALL) {
err = 0;
num += fr_flushhtable(&flush);
}
if (err == 0) {
flush.iplf_count = num;
err = COPYOUT(&flush, data, sizeof(flush));
}
return err;
}
void ip_lookup_deref(type, ptr)
int type;
void *ptr;
{
if (ptr == NULL)
return;
WRITE_ENTER(&ip_poolrw);
switch (type)
{
case IPLT_POOL :
ip_pool_deref(ptr);
break;
case IPLT_HASH :
fr_derefhtable(ptr);
break;
}
RWLOCK_EXIT(&ip_poolrw);
}
#else /* IPFILTER_LOOKUP */
/*ARGSUSED*/
int ip_lookup_ioctl(data, cmd, mode)
caddr_t data;
ioctlcmd_t cmd;
int mode;
{
return EIO;
}
#endif /* IPFILTER_LOOKUP */

View File

@ -0,0 +1,65 @@
/* $FreeBSD$ */
#ifndef __IP_LOOKUP_H__
#define __IP_LOOKUP_H__
#if defined(__STDC__) || defined(__GNUC__)
# define SIOCLOOKUPADDTABLE _IOWR('r', 60, struct iplookupop)
# define SIOCLOOKUPDELTABLE _IOWR('r', 61, struct iplookupop)
# define SIOCLOOKUPSTAT _IOWR('r', 64, struct iplookupop)
# define SIOCLOOKUPSTATW _IOW('r', 64, struct iplookupop)
# define SIOCLOOKUPFLUSH _IOWR('r', 65, struct iplookupflush)
# define SIOCLOOKUPADDNODE _IOWR('r', 67, struct iplookupop)
# define SIOCLOOKUPADDNODEW _IOW('r', 67, struct iplookupop)
# define SIOCLOOKUPDELNODE _IOWR('r', 68, struct iplookupop)
# define SIOCLOOKUPDELNODEW _IOW('r', 68, struct iplookupop)
#else
# define SIOCLOOKUPADDTABLE _IOWR(r, 60, struct iplookupop)
# define SIOCLOOKUPDELTABLE _IOWR(r, 61, struct iplookupop)
# define SIOCLOOKUPSTAT _IOWR(r, 64, struct iplookupop)
# define SIOCLOOKUPSTATW _IOW(r, 64, struct iplookupop)
# define SIOCLOOKUPFLUSH _IOWR(r, 65, struct iplookupflush)
# define SIOCLOOKUPADDNODE _IOWR(r, 67, struct iplookupop)
# define SIOCLOOKUPADDNODEW _IOW(r, 67, struct iplookupop)
# define SIOCLOOKUPDELNODE _IOWR(r, 68, struct iplookupop)
# define SIOCLOOKUPDELNODEW _IOW(r, 68, struct iplookupop)
#endif
typedef struct iplookupop {
int iplo_type; /* IPLT_* */
int iplo_unit; /* IPL_LOG* */
u_int iplo_arg;
char iplo_name[FR_GROUPLEN];
size_t iplo_size; /* sizeof struct at iplo_struct */
void *iplo_struct;
} iplookupop_t;
typedef struct iplookupflush {
int iplf_type; /* IPLT_* */
int iplf_unit; /* IPL_LOG* */
u_int iplf_arg;
size_t iplf_count;
char iplf_name[FR_GROUPLEN];
} iplookupflush_t;
typedef struct iplookuplink {
int ipll_type; /* IPLT_* */
int ipll_unit; /* IPL_LOG* */
u_int ipll_num;
char ipll_group[FR_GROUPLEN];
} iplookuplink_t;
#define IPLT_ALL -1
#define IPLT_NONE 0
#define IPLT_POOL 1
#define IPLT_HASH 2
#define IPLT_ANON 0x80000000
extern int ip_lookup_init __P((void));
extern int ip_lookup_ioctl __P((caddr_t, ioctlcmd_t, int));
extern void ip_lookup_unload __P((void));
extern void ip_lookup_deref __P((int, void *));
#endif /* __IP_LOOKUP_H__ */

View File

@ -1,11 +1,13 @@
/* $FreeBSD$ */
/*
* Simple netbios-dgm transparent proxy for in-kernel use.
* For use with the NAT code.
* $Id: ip_netbios_pxy.c,v 1.1.2.3 2002/01/09 09:28:37 darrenr Exp $
* Id: ip_netbios_pxy.c,v 2.8 2003/12/01 02:52:16 darrenr Exp
*/
/*-
* Copyright (c) 2002 Paul J. Ledbetter III
* Copyright (c) 2002-2003 Paul J. Ledbetter III
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -29,16 +31,19 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ip_netbios_pxy.c,v 1.1.2.3 2002/01/09 09:28:37 darrenr Exp $
* Id: ip_netbios_pxy.c,v 2.8 2003/12/01 02:52:16 darrenr Exp
*/
#define IPF_NETBIOS_PROXY
int ippr_netbios_init __P((void));
int ippr_netbios_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *));
void ippr_netbios_fini __P((void));
int ippr_netbios_out __P((fr_info_t *, ap_session_t *, nat_t *));
static frentry_t netbiosfr;
int netbios_proxy_init = 0;
/*
* Initialize local structures.
*/
@ -47,43 +52,55 @@ int ippr_netbios_init()
bzero((char *)&netbiosfr, sizeof(netbiosfr));
netbiosfr.fr_ref = 1;
netbiosfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
MUTEX_INIT(&netbiosfr.fr_lock, "NETBIOS proxy rule lock");
netbios_proxy_init = 1;
return 0;
}
int ippr_netbios_out(fin, ip, aps, nat)
void ippr_netbios_fini()
{
if (netbios_proxy_init == 1) {
MUTEX_DESTROY(&netbiosfr.fr_lock);
netbios_proxy_init = 0;
}
}
int ippr_netbios_out(fin, aps, nat)
fr_info_t *fin;
ip_t *ip;
ap_session_t *aps;
nat_t *nat;
{
char dgmbuf[6];
int off, dlen;
udphdr_t *udp;
ip_t *ip;
mb_t *m;
aps = aps; /* LINT */
nat = nat; /* LINT */
ip = fin->fin_ip;
m = *(mb_t **)fin->fin_mp;
off = fin->fin_hlen + sizeof(udphdr_t);
#if SOLARIS
dlen = msgdsize(m);
#else
dlen = mbufchainlen(m);
#endif
dlen = M_LEN(m);
dlen -= off;
/*
* no net bios datagram could possibly be shorter than this
*/
if (dlen < 11)
if (dlen < 11)
return 0;
udp = (udphdr_t *)fin->fin_dp;
/*
/*
* move past the
* ip header;
* udp header;
* 4 bytes into the net bios dgm header.
* 4 bytes into the net bios dgm header.
* According to rfc1002, this should be the exact location of
* the source address/port
*/
@ -99,11 +116,7 @@ nat_t *nat;
dgmbuf[5] = (char)((udp->uh_sport >> 8)&0xFF);
/* replace data in packet */
#if SOLARIS
copyin_mblk(m, off, sizeof(dgmbuf), dgmbuf);
#else
m_copyback(m, off, sizeof(dgmbuf), dgmbuf);
#endif
COPYBACK(m, off, sizeof(dgmbuf), dgmbuf);
return 0;
}

View File

@ -0,0 +1,786 @@
/* $FreeBSD$ */
/*
* Copyright (C) 1993-2001, 2003 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*/
#if defined(KERNEL) || defined(_KERNEL)
# undef KERNEL
# undef _KERNEL
# define KERNEL 1
# define _KERNEL 1
#endif
#if defined(__osf__)
# define _PROTO_NET_H_
#endif
#include <sys/errno.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/file.h>
#if !defined(_KERNEL) && !defined(__KERNEL__)
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# define _KERNEL
# ifdef __OpenBSD__
struct file;
# endif
# include <sys/uio.h>
# undef _KERNEL
#else
# include <sys/systm.h>
# if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
# include <sys/proc.h>
# endif
#endif
#include <sys/time.h>
#if !defined(linux)
# include <sys/protosw.h>
#endif
#include <sys/socket.h>
#if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__))
# include <sys/mbuf.h>
#endif
#if defined(__SVR4) || defined(__svr4__)
# include <sys/filio.h>
# include <sys/byteorder.h>
# ifdef _KERNEL
# include <sys/dditypes.h>
# endif
# include <sys/stream.h>
# include <sys/kmem.h>
#endif
#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
# include <sys/malloc.h>
#endif
#if (defined(__osf__) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL)
# ifdef __osf__
# include <net/radix.h>
# endif
# include "radix_ipf_local.h"
# define _RADIX_H_
#endif
#include <net/if.h>
#include <netinet/in.h>
#include "netinet/ip_compat.h"
#include "netinet/ip_fil.h"
#include "netinet/ip_pool.h"
#if defined(IPFILTER_LOOKUP) && defined(_KERNEL) && \
((BSD >= 198911) && !defined(__osf__) && \
!defined(__hpux) && !defined(__sgi))
static int rn_freenode __P((struct radix_node *, void *));
#endif
/* END OF INCLUDES */
#if !defined(lint)
static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
static const char rcsid[] = "@(#)Id: ip_pool.c,v 2.55.2.12 2005/02/01 04:04:46 darrenr Exp";
#endif
#ifdef IPFILTER_LOOKUP
# ifndef RADIX_NODE_HEAD_LOCK
# define RADIX_NODE_HEAD_LOCK(x) ;
# endif
# ifndef RADIX_NODE_HEAD_UNLOCK
# define RADIX_NODE_HEAD_UNLOCK(x) ;
# endif
ip_pool_stat_t ipoolstat;
ipfrwlock_t ip_poolrw;
/*
* Binary tree routines from Sedgewick and enhanced to do ranges of addresses.
* NOTE: Insertion *MUST* be from greatest range to least for it to work!
* These should be replaced, eventually, by something else - most notably a
* interval searching method. The important feature is to be able to find
* the best match.
*
* So why not use a radix tree for this? As the first line implies, it
* has been written to work with a _range_ of addresses. A range is not
* necessarily a match with any given netmask so what we end up dealing
* with is an interval tree. Implementations of these are hard to find
* and the one herein is far from bug free.
*
* Sigh, in the end I became convinced that the bugs the code contained did
* not make it worthwhile not using radix trees. For now the radix tree from
* 4.4 BSD is used, but this is not viewed as a long term solution.
*/
ip_pool_t *ip_pool_list[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL };
#ifdef TEST_POOL
void treeprint __P((ip_pool_t *));
int
main(argc, argv)
int argc;
char *argv[];
{
addrfamily_t a, b;
iplookupop_t op;
ip_pool_t *ipo;
i6addr_t ip;
RWLOCK_INIT(&ip_poolrw, "poolrw");
ip_pool_init();
bzero((char *)&a, sizeof(a));
bzero((char *)&b, sizeof(b));
bzero((char *)&ip, sizeof(ip));
bzero((char *)&op, sizeof(op));
strcpy(op.iplo_name, "0");
if (ip_pool_create(&op) == 0)
ipo = ip_pool_find(0, "0");
a.adf_addr.in4.s_addr = 0x0a010203;
b.adf_addr.in4.s_addr = 0xffffffff;
ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
a.adf_addr.in4.s_addr = 0x0a000000;
b.adf_addr.in4.s_addr = 0xff000000;
ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
a.adf_addr.in4.s_addr = 0x0a010100;
b.adf_addr.in4.s_addr = 0xffffff00;
ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
a.adf_addr.in4.s_addr = 0x0a010200;
b.adf_addr.in4.s_addr = 0xffffff00;
ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
a.adf_addr.in4.s_addr = 0x0a010000;
b.adf_addr.in4.s_addr = 0xffff0000;
ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
a.adf_addr.in4.s_addr = 0x0a01020f;
b.adf_addr.in4.s_addr = 0xffffffff;
ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
#ifdef DEBUG_POOL
treeprint(ipo);
#endif
ip.in4.s_addr = 0x0a00aabb;
printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
ip_pool_search(ipo, 4, &ip));
ip.in4.s_addr = 0x0a000001;
printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
ip_pool_search(ipo, 4, &ip));
ip.in4.s_addr = 0x0a000101;
printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
ip_pool_search(ipo, 4, &ip));
ip.in4.s_addr = 0x0a010001;
printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
ip_pool_search(ipo, 4, &ip));
ip.in4.s_addr = 0x0a010101;
printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
ip_pool_search(ipo, 4, &ip));
ip.in4.s_addr = 0x0a010201;
printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
ip_pool_search(ipo, 4, &ip));
ip.in4.s_addr = 0x0a010203;
printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
ip_pool_search(ipo, 4, &ip));
ip.in4.s_addr = 0x0a01020f;
printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
ip_pool_search(ipo, 4, &ip));
ip.in4.s_addr = 0x0b00aabb;
printf("search(%#x) = %d (-1)\n", ip.in4.s_addr,
ip_pool_search(ipo, 4, &ip));
#ifdef DEBUG_POOL
treeprint(ipo);
#endif
ip_pool_fini();
return 0;
}
void
treeprint(ipo)
ip_pool_t *ipo;
{
ip_pool_node_t *c;
for (c = ipo->ipo_list; c != NULL; c = c->ipn_next)
printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n",
c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr,
c->ipn_mask.adf_addr.in4.s_addr,
c->ipn_info, c->ipn_hits);
}
#endif /* TEST_POOL */
/* ------------------------------------------------------------------------ */
/* Function: ip_pool_init */
/* Returns: int - 0 = success, else error */
/* */
/* Initialise the routing table data structures where required. */
/* ------------------------------------------------------------------------ */
int ip_pool_init()
{
bzero((char *)&ipoolstat, sizeof(ipoolstat));
#if (!defined(_KERNEL) || (BSD < 199306))
rn_init();
#endif
return 0;
}
/* ------------------------------------------------------------------------ */
/* Function: ip_pool_fini */
/* Returns: int - 0 = success, else error */
/* Locks: WRITE(ipf_global) */
/* */
/* Clean up all the pool data structures allocated and call the cleanup */
/* function for the radix tree that supports the pools. ip_pool_destroy() is*/
/* used to delete the pools one by one to ensure they're properly freed up. */
/* ------------------------------------------------------------------------ */
void ip_pool_fini()
{
ip_pool_t *p, *q;
iplookupop_t op;
int i;
ASSERT(rw_read_locked(&ipf_global.ipf_lk) == 0);
for (i = 0; i <= IPL_LOGMAX; i++) {
for (q = ip_pool_list[i]; (p = q) != NULL; ) {
op.iplo_unit = i;
(void)strncpy(op.iplo_name, p->ipo_name,
sizeof(op.iplo_name));
q = p->ipo_next;
(void) ip_pool_destroy(&op);
}
}
#if (!defined(_KERNEL) || (BSD < 199306))
rn_fini();
#endif
}
/* ------------------------------------------------------------------------ */
/* Function: ip_pool_statistics */
/* Returns: int - 0 = success, else error */
/* Parameters: op(I) - pointer to lookup operation arguments */
/* */
/* Copy the current statistics out into user space, collecting pool list */
/* pointers as appropriate for later use. */
/* ------------------------------------------------------------------------ */
int ip_pool_statistics(op)
iplookupop_t *op;
{
ip_pool_stat_t stats;
int unit, i, err = 0;
if (op->iplo_size != sizeof(ipoolstat))
return EINVAL;
bcopy((char *)&ipoolstat, (char *)&stats, sizeof(stats));
unit = op->iplo_unit;
if (unit == IPL_LOGALL) {
for (i = 0; i < IPL_LOGSIZE; i++)
stats.ipls_list[i] = ip_pool_list[i];
} else if (unit >= 0 && unit < IPL_LOGSIZE) {
if (op->iplo_name[0] != '\0')
stats.ipls_list[unit] = ip_pool_find(unit,
op->iplo_name);
else
stats.ipls_list[unit] = ip_pool_list[unit];
} else
err = EINVAL;
if (err == 0)
err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
return err;
}
/* ------------------------------------------------------------------------ */
/* Function: ip_pool_find */
/* Returns: int - 0 = success, else error */
/* Parameters: ipo(I) - pointer to the pool getting the new node. */
/* */
/* Find a matching pool inside the collection of pools for a particular */
/* device, indicated by the unit number. */
/* ------------------------------------------------------------------------ */
void *ip_pool_find(unit, name)
int unit;
char *name;
{
ip_pool_t *p;
for (p = ip_pool_list[unit]; p != NULL; p = p->ipo_next)
if (strncmp(p->ipo_name, name, sizeof(p->ipo_name)) == 0)
break;
return p;
}
/* ------------------------------------------------------------------------ */
/* Function: ip_pool_findeq */
/* Returns: int - 0 = success, else error */
/* Parameters: ipo(I) - pointer to the pool getting the new node. */
/* addr(I) - pointer to address information to delete */
/* mask(I) - */
/* */
/* Searches for an exact match of an entry in the pool. */
/* ------------------------------------------------------------------------ */
ip_pool_node_t *ip_pool_findeq(ipo, addr, mask)
ip_pool_t *ipo;
addrfamily_t *addr, *mask;
{
struct radix_node *n;
#ifdef USE_SPL
int s;
SPL_NET(s);
#endif
RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
n = ipo->ipo_head->rnh_lookup(addr, mask, ipo->ipo_head);
RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
SPL_X(s);
return (ip_pool_node_t *)n;
}
/* ------------------------------------------------------------------------ */
/* Function: ip_pool_search */
/* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */
/* Parameters: tptr(I) - pointer to the pool to search */
/* version(I) - IP protocol version (4 or 6) */
/* dptr(I) - pointer to address information */
/* */
/* Search the pool for a given address and return a search result. */
/* ------------------------------------------------------------------------ */
int ip_pool_search(tptr, version, dptr)
void *tptr;
int version;
void *dptr;
{
struct radix_node *rn;
ip_pool_node_t *m;
i6addr_t *addr;
addrfamily_t v;
ip_pool_t *ipo;
int rv;
ipo = tptr;
if (ipo == NULL)
return -1;
rv = 1;
m = NULL;
addr = (i6addr_t *)dptr;
bzero(&v, sizeof(v));
v.adf_len = offsetof(addrfamily_t, adf_addr);
if (version == 4) {
v.adf_len += sizeof(addr->in4);
v.adf_addr.in4 = addr->in4;
#ifdef USE_INET6
} else if (version == 6) {
v.adf_len += sizeof(addr->in6);
v.adf_addr.in6 = addr->in6;
#endif
} else
return -1;
READ_ENTER(&ip_poolrw);
RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
rn = ipo->ipo_head->rnh_matchaddr(&v, ipo->ipo_head);
RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
if ((rn != NULL) && ((rn->rn_flags & RNF_ROOT) == 0)) {
m = (ip_pool_node_t *)rn;
ipo->ipo_hits++;
m->ipn_hits++;
rv = m->ipn_info;
}
RWLOCK_EXIT(&ip_poolrw);
return rv;
}
/* ------------------------------------------------------------------------ */
/* Function: ip_pool_insert */
/* Returns: int - 0 = success, else error */
/* Parameters: ipo(I) - pointer to the pool getting the new node. */
/* addr(I) - address being added as a node */
/* mask(I) - netmask to with the node being added */
/* info(I) - extra information to store in this node. */
/* Locks: WRITE(ip_poolrw) */
/* */
/* Add another node to the pool given by ipo. The three parameters passed */
/* in (addr, mask, info) shold all be stored in the node. */
/* ------------------------------------------------------------------------ */
int ip_pool_insert(ipo, addr, mask, info)
ip_pool_t *ipo;
i6addr_t *addr, *mask;
int info;
{
struct radix_node *rn;
ip_pool_node_t *x;
ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
KMALLOC(x, ip_pool_node_t *);
if (x == NULL) {
return ENOMEM;
}
bzero(x, sizeof(*x));
x->ipn_info = info;
(void)strncpy(x->ipn_name, ipo->ipo_name, sizeof(x->ipn_name));
bcopy(addr, &x->ipn_addr.adf_addr, sizeof(*addr));
x->ipn_addr.adf_len = sizeof(x->ipn_addr);
bcopy(mask, &x->ipn_mask.adf_addr, sizeof(*mask));
x->ipn_mask.adf_len = sizeof(x->ipn_mask);
RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
rn = ipo->ipo_head->rnh_addaddr(&x->ipn_addr, &x->ipn_mask,
ipo->ipo_head, x->ipn_nodes);
RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
#ifdef DEBUG_POOL
printf("Added %p at %p\n", x, rn);
#endif
if (rn == NULL) {
KFREE(x);
return ENOMEM;
}
x->ipn_next = ipo->ipo_list;
x->ipn_pnext = &ipo->ipo_list;
if (ipo->ipo_list != NULL)
ipo->ipo_list->ipn_pnext = &x->ipn_next;
ipo->ipo_list = x;
ipoolstat.ipls_nodes++;
return 0;
}
/* ------------------------------------------------------------------------ */
/* Function: ip_pool_create */
/* Returns: int - 0 = success, else error */
/* Parameters: op(I) - pointer to iplookup struct with call details */
/* Locks: WRITE(ip_poolrw) */
/* */
/* Creates a new group according to the paramters passed in via the */
/* iplookupop structure. Does not check to see if the group already exists */
/* when being inserted - assume this has already been done. If the pool is */
/* marked as being anonymous, give it a new, unique, identifier. Call any */
/* other functions required to initialise the structure. */
/* ------------------------------------------------------------------------ */
int ip_pool_create(op)
iplookupop_t *op;
{
char name[FR_GROUPLEN];
int poolnum, unit;
ip_pool_t *h;
ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
KMALLOC(h, ip_pool_t *);
if (h == NULL)
return ENOMEM;
bzero(h, sizeof(*h));
if (rn_inithead((void **)&h->ipo_head,
offsetof(addrfamily_t, adf_addr) << 3) == 0) {
KFREE(h);
return ENOMEM;
}
unit = op->iplo_unit;
if ((op->iplo_arg & IPOOL_ANON) != 0) {
ip_pool_t *p;
poolnum = IPOOL_ANON;
#if defined(SNPRINTF) && defined(_KERNEL)
SNPRINTF(name, sizeof(name), "%x", poolnum);
#else
(void)sprintf(name, "%x", poolnum);
#endif
for (p = ip_pool_list[unit]; p != NULL; ) {
if (strncmp(name, p->ipo_name,
sizeof(p->ipo_name)) == 0) {
poolnum++;
#if defined(SNPRINTF) && defined(_KERNEL)
SNPRINTF(name, sizeof(name), "%x", poolnum);
#else
(void)sprintf(name, "%x", poolnum);
#endif
p = ip_pool_list[unit];
} else
p = p->ipo_next;
}
(void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
} else {
(void) strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
}
h->ipo_ref = 1;
h->ipo_list = NULL;
h->ipo_unit = unit;
h->ipo_next = ip_pool_list[unit];
if (ip_pool_list[unit] != NULL)
ip_pool_list[unit]->ipo_pnext = &h->ipo_next;
h->ipo_pnext = &ip_pool_list[unit];
ip_pool_list[unit] = h;
ipoolstat.ipls_pools++;
return 0;
}
/* ------------------------------------------------------------------------ */
/* Function: ip_pool_remove */
/* Returns: int - 0 = success, else error */
/* Parameters: ipo(I) - pointer to the pool to remove the node from. */
/* ipe(I) - address being deleted as a node */
/* Locks: WRITE(ip_poolrw) */
/* */
/* Add another node to the pool given by ipo. The three parameters passed */
/* in (addr, mask, info) shold all be stored in the node. */
/* ------------------------------------------------------------------------ */
int ip_pool_remove(ipo, ipe)
ip_pool_t *ipo;
ip_pool_node_t *ipe;
{
ip_pool_node_t **ipp, *n;
ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
for (ipp = &ipo->ipo_list; (n = *ipp) != NULL; ipp = &n->ipn_next) {
if (ipe == n) {
*n->ipn_pnext = n->ipn_next;
if (n->ipn_next)
n->ipn_next->ipn_pnext = n->ipn_pnext;
break;
}
}
if (n == NULL)
return ENOENT;
RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
ipo->ipo_head);
RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
KFREE(n);
ipoolstat.ipls_nodes--;
return 0;
}
/* ------------------------------------------------------------------------ */
/* Function: ip_pool_destroy */
/* Returns: int - 0 = success, else error */
/* Parameters: op(I) - information about the pool to remove */
/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
/* */
/* Search for a pool using paramters passed in and if it's not otherwise */
/* busy, free it. */
/* */
/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */
/* may not be initialised, we can't use an ASSERT to enforce the locking */
/* assertion that one of the two (ip_poolrw,ipf_global) is held. */
/* ------------------------------------------------------------------------ */
int ip_pool_destroy(op)
iplookupop_t *op;
{
ip_pool_t *ipo;
ipo = ip_pool_find(op->iplo_unit, op->iplo_name);
if (ipo == NULL)
return ESRCH;
if (ipo->ipo_ref != 1)
return EBUSY;
ip_pool_free(ipo);
return 0;
}
/* ------------------------------------------------------------------------ */
/* Function: ip_pool_flush */
/* Returns: int - number of pools deleted */
/* Parameters: fp(I) - which pool(s) to flush */
/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
/* */
/* Free all pools associated with the device that matches the unit number */
/* passed in with operation. */
/* */
/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */
/* may not be initialised, we can't use an ASSERT to enforce the locking */
/* assertion that one of the two (ip_poolrw,ipf_global) is held. */
/* ------------------------------------------------------------------------ */
int ip_pool_flush(fp)
iplookupflush_t *fp;
{
int i, num = 0, unit, err;
ip_pool_t *p, *q;
iplookupop_t op;
unit = fp->iplf_unit;
for (i = 0; i <= IPL_LOGMAX; i++) {
if (unit != IPLT_ALL && i != unit)
continue;
for (q = ip_pool_list[i]; (p = q) != NULL; ) {
op.iplo_unit = i;
(void)strncpy(op.iplo_name, p->ipo_name,
sizeof(op.iplo_name));
q = p->ipo_next;
err = ip_pool_destroy(&op);
if (err == 0)
num++;
else
break;
}
}
return num;
}
/* ------------------------------------------------------------------------ */
/* Function: ip_pool_free */
/* Returns: void */
/* Parameters: ipo(I) - pointer to pool structure */
/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
/* */
/* Deletes the pool strucutre passed in from the list of pools and deletes */
/* all of the address information stored in it, including any tree data */
/* structures also allocated. */
/* */
/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */
/* may not be initialised, we can't use an ASSERT to enforce the locking */
/* assertion that one of the two (ip_poolrw,ipf_global) is held. */
/* ------------------------------------------------------------------------ */
void ip_pool_free(ipo)
ip_pool_t *ipo;
{
ip_pool_node_t *n;
RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
while ((n = ipo->ipo_list) != NULL) {
ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
ipo->ipo_head);
*n->ipn_pnext = n->ipn_next;
if (n->ipn_next)
n->ipn_next->ipn_pnext = n->ipn_pnext;
KFREE(n);
ipoolstat.ipls_nodes--;
}
RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
ipo->ipo_list = NULL;
if (ipo->ipo_next != NULL)
ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
*ipo->ipo_pnext = ipo->ipo_next;
rn_freehead(ipo->ipo_head);
KFREE(ipo);
ipoolstat.ipls_pools--;
}
/* ------------------------------------------------------------------------ */
/* Function: ip_pool_deref */
/* Returns: void */
/* Parameters: ipo(I) - pointer to pool structure */
/* Locks: WRITE(ip_poolrw) */
/* */
/* Drop the number of known references to this pool structure by one and if */
/* we arrive at zero known references, free it. */
/* ------------------------------------------------------------------------ */
void ip_pool_deref(ipo)
ip_pool_t *ipo;
{
ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
ipo->ipo_ref--;
if (ipo->ipo_ref == 0)
ip_pool_free(ipo);
}
# if defined(_KERNEL) && ((BSD >= 198911) && !defined(__osf__) && \
!defined(__hpux) && !defined(__sgi))
static int
rn_freenode(struct radix_node *n, void *p)
{
struct radix_node_head *rnh = p;
struct radix_node *d;
d = rnh->rnh_deladdr(n->rn_key, NULL, rnh);
if (d != NULL) {
FreeS(d, max_keylen + 2 * sizeof (*d));
}
return 0;
}
void
rn_freehead(rnh)
struct radix_node_head *rnh;
{
RADIX_NODE_HEAD_LOCK(rnh);
(*rnh->rnh_walktree)(rnh, rn_freenode, rnh);
rnh->rnh_addaddr = NULL;
rnh->rnh_deladdr = NULL;
rnh->rnh_matchaddr = NULL;
rnh->rnh_lookup = NULL;
rnh->rnh_walktree = NULL;
RADIX_NODE_HEAD_UNLOCK(rnh);
Free(rnh);
}
# endif
#endif /* IPFILTER_LOOKUP */

View File

@ -0,0 +1,87 @@
/* $FreeBSD$ */
/*
* Copyright (C) 1993-2001, 2003 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
* Id: ip_pool.h,v 2.26.2.2 2004/03/23 12:44:34 darrenr Exp
*/
#ifndef __IP_POOL_H__
#define __IP_POOL_H__
#if defined(_KERNEL) && !defined(__osf__) && !defined(__hpux) && \
!defined(linux) && !defined(sun)
# include <net/radix.h>
extern void rn_freehead __P((struct radix_node_head *));
# define FreeS(p, z) KFREES(p, z)
extern int max_keylen;
#else
# if defined(__osf__) || defined(__hpux)
# include "radix_ipf_local.h"
# define radix_mask ipf_radix_mask
# define radix_node ipf_radix_node
# define radix_node_head ipf_radix_node_head
# else
# include "radix_ipf.h"
# endif
#endif
#include "netinet/ip_lookup.h"
#define IP_POOL_NOMATCH 0
#define IP_POOL_POSITIVE 1
typedef struct ip_pool_node {
struct radix_node ipn_nodes[2];
addrfamily_t ipn_addr;
addrfamily_t ipn_mask;
int ipn_info;
char ipn_name[FR_GROUPLEN];
u_long ipn_hits;
struct ip_pool_node *ipn_next, **ipn_pnext;
} ip_pool_node_t;
typedef struct ip_pool_s {
struct ip_pool_s *ipo_next;
struct ip_pool_s **ipo_pnext;
struct radix_node_head *ipo_head;
ip_pool_node_t *ipo_list;
u_long ipo_hits;
int ipo_unit;
int ipo_flags;
int ipo_ref;
char ipo_name[FR_GROUPLEN];
} ip_pool_t;
#define IPOOL_ANON 0x80000000
typedef struct ip_pool_stat {
u_long ipls_pools;
u_long ipls_tables;
u_long ipls_nodes;
ip_pool_t *ipls_list[IPL_LOGSIZE];
} ip_pool_stat_t;
extern ip_pool_stat_t ipoolstat;
extern ip_pool_t *ip_pool_list[IPL_LOGSIZE];
extern int ip_pool_search __P((void *, int, void *));
extern int ip_pool_init __P((void));
extern void ip_pool_fini __P((void));
extern int ip_pool_create __P((iplookupop_t *));
extern int ip_pool_insert __P((ip_pool_t *, i6addr_t *, i6addr_t *, int));
extern int ip_pool_remove __P((ip_pool_t *, ip_pool_node_t *));
extern int ip_pool_destroy __P((iplookupop_t *));
extern void ip_pool_free __P((ip_pool_t *));
extern void ip_pool_deref __P((ip_pool_t *));
extern void *ip_pool_find __P((int, char *));
extern ip_pool_node_t *ip_pool_findeq __P((ip_pool_t *,
addrfamily_t *, addrfamily_t *));
extern int ip_pool_flush __P((iplookupflush_t *));
extern int ip_pool_statistics __P((iplookupop_t *));
#endif /* __IP_POOL_H__ */

View File

@ -0,0 +1,527 @@
/* $FreeBSD$ */
/*
* Copyright (C) 2002-2003 by Darren Reed
*
* Simple PPTP transparent proxy for in-kernel use. For use with the NAT
* code.
*
* Id: ip_pptp_pxy.c,v 2.10.2.9 2005/03/16 18:17:34 darrenr Exp
*
*/
#define IPF_PPTP_PROXY
typedef struct pptp_hdr {
u_short pptph_len;
u_short pptph_type;
u_32_t pptph_cookie;
} pptp_hdr_t;
#define PPTP_MSGTYPE_CTL 1
#define PPTP_MTCTL_STARTREQ 1
#define PPTP_MTCTL_STARTREP 2
#define PPTP_MTCTL_STOPREQ 3
#define PPTP_MTCTL_STOPREP 4
#define PPTP_MTCTL_ECHOREQ 5
#define PPTP_MTCTL_ECHOREP 6
#define PPTP_MTCTL_OUTREQ 7
#define PPTP_MTCTL_OUTREP 8
#define PPTP_MTCTL_INREQ 9
#define PPTP_MTCTL_INREP 10
#define PPTP_MTCTL_INCONNECT 11
#define PPTP_MTCTL_CLEAR 12
#define PPTP_MTCTL_DISCONNECT 13
#define PPTP_MTCTL_WANERROR 14
#define PPTP_MTCTL_LINKINFO 15
int ippr_pptp_init __P((void));
void ippr_pptp_fini __P((void));
int ippr_pptp_new __P((fr_info_t *, ap_session_t *, nat_t *));
void ippr_pptp_del __P((ap_session_t *));
int ippr_pptp_inout __P((fr_info_t *, ap_session_t *, nat_t *));
void ippr_pptp_donatstate __P((fr_info_t *, nat_t *, pptp_pxy_t *));
int ippr_pptp_message __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *));
int ippr_pptp_nextmessage __P((fr_info_t *, nat_t *, pptp_pxy_t *, int));
int ippr_pptp_mctl __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *));
static frentry_t pptpfr;
int pptp_proxy_init = 0;
int ippr_pptp_debug = 0;
int ippr_pptp_gretimeout = IPF_TTLVAL(120); /* 2 minutes */
/*
* PPTP application proxy initialization.
*/
int ippr_pptp_init()
{
bzero((char *)&pptpfr, sizeof(pptpfr));
pptpfr.fr_ref = 1;
pptpfr.fr_age[0] = ippr_pptp_gretimeout;
pptpfr.fr_age[1] = ippr_pptp_gretimeout;
pptpfr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
MUTEX_INIT(&pptpfr.fr_lock, "PPTP proxy rule lock");
pptp_proxy_init = 1;
return 0;
}
void ippr_pptp_fini()
{
if (pptp_proxy_init == 1) {
MUTEX_DESTROY(&pptpfr.fr_lock);
pptp_proxy_init = 0;
}
}
/*
* Setup for a new PPTP proxy.
*/
int ippr_pptp_new(fin, aps, nat)
fr_info_t *fin;
ap_session_t *aps;
nat_t *nat;
{
pptp_pxy_t *pptp;
ipnat_t *ipn;
ip_t *ip;
int off;
ip = fin->fin_ip;
off = fin->fin_hlen + sizeof(udphdr_t);
if (nat_outlookup(fin, 0, IPPROTO_GRE, nat->nat_inip,
ip->ip_dst) != NULL) {
if (ippr_pptp_debug > 0)
printf("ippr_pptp_new: GRE session already exists\n");
return -1;
}
aps->aps_psiz = sizeof(*pptp);
KMALLOCS(aps->aps_data, pptp_pxy_t *, sizeof(*pptp));
if (aps->aps_data == NULL) {
if (ippr_pptp_debug > 0)
printf("ippr_pptp_new: malloc for aps_data failed\n");
return -1;
}
/*
* Create NAT rule against which the tunnel/transport mapping is
* created. This is required because the current NAT rule does not
* describe GRE but TCP instead.
*/
pptp = aps->aps_data;
bzero((char *)pptp, sizeof(*pptp));
ipn = &pptp->pptp_rule;
ipn->in_ifps[0] = fin->fin_ifp;
ipn->in_apr = NULL;
ipn->in_use = 1;
ipn->in_hits = 1;
ipn->in_ippip = 1;
if (nat->nat_dir == NAT_OUTBOUND) {
ipn->in_nip = ntohl(nat->nat_outip.s_addr);
ipn->in_outip = fin->fin_saddr;
ipn->in_redir = NAT_MAP;
} else if (nat->nat_dir == NAT_INBOUND) {
ipn->in_nip = 0;
ipn->in_outip = nat->nat_outip.s_addr;
ipn->in_redir = NAT_REDIRECT;
}
ipn->in_inip = nat->nat_inip.s_addr;
ipn->in_inmsk = 0xffffffff;
ipn->in_outmsk = 0xffffffff;
ipn->in_srcip = fin->fin_saddr;
ipn->in_srcmsk = 0xffffffff;
bcopy(nat->nat_ptr->in_ifnames[0], ipn->in_ifnames[0],
sizeof(ipn->in_ifnames[0]));
ipn->in_p = IPPROTO_GRE;
pptp->pptp_side[0].pptps_wptr = pptp->pptp_side[0].pptps_buffer;
pptp->pptp_side[1].pptps_wptr = pptp->pptp_side[1].pptps_buffer;
return 0;
}
void ippr_pptp_donatstate(fin, nat, pptp)
fr_info_t *fin;
nat_t *nat;
pptp_pxy_t *pptp;
{
fr_info_t fi;
grehdr_t gre;
nat_t *nat2;
u_char p;
ip_t *ip;
ip = fin->fin_ip;
p = ip->ip_p;
nat2 = pptp->pptp_nat;
if ((nat2 == NULL) || (pptp->pptp_state == NULL)) {
bcopy((char *)fin, (char *)&fi, sizeof(fi));
bzero((char *)&gre, sizeof(gre));
fi.fin_state = NULL;
fi.fin_nat = NULL;
fi.fin_fi.fi_p = IPPROTO_GRE;
fi.fin_fr = &pptpfr;
if ((nat->nat_dir == NAT_OUTBOUND && fin->fin_out) ||
(nat->nat_dir == NAT_INBOUND && !fin->fin_out)) {
fi.fin_data[0] = pptp->pptp_call[0];
fi.fin_data[1] = pptp->pptp_call[1];
} else {
fi.fin_data[0] = pptp->pptp_call[1];
fi.fin_data[1] = pptp->pptp_call[0];
}
ip = fin->fin_ip;
ip->ip_p = IPPROTO_GRE;
fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG);
fi.fin_flx |= FI_IGNORE;
fi.fin_dp = &gre;
gre.gr_flags = htons(1 << 13);
if (fin->fin_out && nat->nat_dir == NAT_INBOUND) {
fi.fin_fi.fi_saddr = fin->fin_fi.fi_daddr;
fi.fin_fi.fi_daddr = nat->nat_outip.s_addr;
} else if (!fin->fin_out && nat->nat_dir == NAT_OUTBOUND) {
fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
fi.fin_fi.fi_daddr = fin->fin_fi.fi_saddr;
}
}
/*
* Update NAT timeout/create NAT if missing.
*/
if (nat2 != NULL)
fr_queueback(&nat2->nat_tqe);
else {
nat2 = nat_new(&fi, &pptp->pptp_rule, &pptp->pptp_nat,
NAT_SLAVE, nat->nat_dir);
pptp->pptp_nat = nat2;
if (nat2 != NULL) {
(void) nat_proto(&fi, nat2, 0);
nat_update(&fi, nat2, nat2->nat_ptr);
}
}
READ_ENTER(&ipf_state);
if (pptp->pptp_state != NULL) {
fr_queueback(&pptp->pptp_state->is_sti);
RWLOCK_EXIT(&ipf_state);
} else {
RWLOCK_EXIT(&ipf_state);
if (nat->nat_dir == NAT_INBOUND)
fi.fin_fi.fi_daddr = nat2->nat_inip.s_addr;
else
fi.fin_fi.fi_saddr = nat2->nat_inip.s_addr;
fi.fin_ifp = NULL;
pptp->pptp_state = fr_addstate(&fi, &pptp->pptp_state,
0);
if (fi.fin_state != NULL)
fr_statederef(&fi, (ipstate_t **)&fi.fin_state);
}
ip->ip_p = p;
return;
}
/*
* Try and build up the next PPTP message in the TCP stream and if we can
* build it up completely (fits in our buffer) then pass it off to the message
* parsing function.
*/
int ippr_pptp_nextmessage(fin, nat, pptp, rev)
fr_info_t *fin;
nat_t *nat;
pptp_pxy_t *pptp;
int rev;
{
static char *funcname = "ippr_pptp_nextmessage";
pptp_side_t *pptps;
u_32_t start, end;
pptp_hdr_t *hdr;
tcphdr_t *tcp;
int dlen, off;
u_short len;
char *msg;
tcp = fin->fin_dp;
dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2);
start = ntohl(tcp->th_seq);
pptps = &pptp->pptp_side[rev];
off = (char *)tcp - (char *)fin->fin_ip + (TCP_OFF(tcp) << 2) +
fin->fin_ipoff;
if (dlen <= 0)
return 0;
/*
* If the complete data packet is before what we expect to see
* "next", just ignore it as the chances are we've already seen it.
* The next if statement following this one really just causes packets
* ahead of what we've seen to be dropped, implying that something in
* the middle went missing and we want to see that first.
*/
end = start + dlen;
if (pptps->pptps_next > end && pptps->pptps_next > start)
return 0;
if (pptps->pptps_next != start) {
if (ippr_pptp_debug > 5)
printf("%s: next (%x) != start (%x)\n", funcname,
pptps->pptps_next, start);
return -1;
}
msg = (char *)fin->fin_dp + (TCP_OFF(tcp) << 2);
while (dlen > 0) {
off += pptps->pptps_bytes;
if (pptps->pptps_gothdr == 0) {
/*
* PPTP has an 8 byte header that inclues the cookie.
* The start of every message should include one and
* it should match 1a2b3c4d. Byte order is ignored,
* deliberately, when printing out the error.
*/
len = MIN(8 - pptps->pptps_bytes, dlen);
COPYDATA(fin->fin_m, off, len, pptps->pptps_wptr);
pptps->pptps_bytes += len;
pptps->pptps_wptr += len;
hdr = (pptp_hdr_t *)pptps->pptps_buffer;
if (pptps->pptps_bytes == 8) {
pptps->pptps_next += 8;
if (ntohl(hdr->pptph_cookie) != 0x1a2b3c4d) {
if (ippr_pptp_debug > 1)
printf("%s: bad cookie (%x)\n",
funcname,
hdr->pptph_cookie);
return -1;
}
}
dlen -= len;
msg += len;
off += len;
pptps->pptps_gothdr = 1;
len = ntohs(hdr->pptph_len);
pptps->pptps_len = len;
pptps->pptps_nexthdr += len;
/*
* If a message is too big for the buffer, just set
* the fields for the next message to come along.
* The messages defined in RFC 2637 will not exceed
* 512 bytes (in total length) so this is likely a
* bad data packet, anyway.
*/
if (len > sizeof(pptps->pptps_buffer)) {
if (ippr_pptp_debug > 3)
printf("%s: message too big (%d)\n",
funcname, len);
pptps->pptps_next = pptps->pptps_nexthdr;
pptps->pptps_wptr = pptps->pptps_buffer;
pptps->pptps_gothdr = 0;
pptps->pptps_bytes = 0;
pptps->pptps_len = 0;
break;
}
}
len = MIN(pptps->pptps_len - pptps->pptps_bytes, dlen);
COPYDATA(fin->fin_m, off, len, pptps->pptps_wptr);
pptps->pptps_bytes += len;
pptps->pptps_wptr += len;
pptps->pptps_next += len;
if (pptps->pptps_len > pptps->pptps_bytes)
break;
ippr_pptp_message(fin, nat, pptp, pptps);
pptps->pptps_wptr = pptps->pptps_buffer;
pptps->pptps_gothdr = 0;
pptps->pptps_bytes = 0;
pptps->pptps_len = 0;
start += len;
msg += len;
dlen -= len;
}
return 0;
}
/*
* handle a complete PPTP message
*/
int ippr_pptp_message(fin, nat, pptp, pptps)
fr_info_t *fin;
nat_t *nat;
pptp_pxy_t *pptp;
pptp_side_t *pptps;
{
pptp_hdr_t *hdr = (pptp_hdr_t *)pptps->pptps_buffer;
switch (ntohs(hdr->pptph_type))
{
case PPTP_MSGTYPE_CTL :
ippr_pptp_mctl(fin, nat, pptp, pptps);
break;
default :
break;
}
return 0;
}
/*
* handle a complete PPTP control message
*/
int ippr_pptp_mctl(fin, nat, pptp, pptps)
fr_info_t *fin;
nat_t *nat;
pptp_pxy_t *pptp;
pptp_side_t *pptps;
{
u_short *buffer = (u_short *)(pptps->pptps_buffer);
pptp_side_t *pptpo;
if (pptps == &pptp->pptp_side[0])
pptpo = &pptp->pptp_side[1];
else
pptpo = &pptp->pptp_side[0];
/*
* Breakout to handle all the various messages. Most are just state
* transition.
*/
switch (ntohs(buffer[4]))
{
case PPTP_MTCTL_STARTREQ :
pptps->pptps_state = PPTP_MTCTL_STARTREQ;
break;
case PPTP_MTCTL_STARTREP :
if (pptpo->pptps_state == PPTP_MTCTL_STARTREQ)
pptps->pptps_state = PPTP_MTCTL_STARTREP;
break;
case PPTP_MTCTL_STOPREQ :
pptps->pptps_state = PPTP_MTCTL_STOPREQ;
break;
case PPTP_MTCTL_STOPREP :
if (pptpo->pptps_state == PPTP_MTCTL_STOPREQ)
pptps->pptps_state = PPTP_MTCTL_STOPREP;
break;
case PPTP_MTCTL_ECHOREQ :
pptps->pptps_state = PPTP_MTCTL_ECHOREQ;
break;
case PPTP_MTCTL_ECHOREP :
if (pptpo->pptps_state == PPTP_MTCTL_ECHOREQ)
pptps->pptps_state = PPTP_MTCTL_ECHOREP;
break;
case PPTP_MTCTL_OUTREQ :
pptps->pptps_state = PPTP_MTCTL_OUTREQ;
break;
case PPTP_MTCTL_OUTREP :
if (pptpo->pptps_state == PPTP_MTCTL_OUTREQ) {
pptps->pptps_state = PPTP_MTCTL_OUTREP;
pptp->pptp_call[0] = buffer[7];
pptp->pptp_call[1] = buffer[6];
ippr_pptp_donatstate(fin, nat, pptp);
}
break;
case PPTP_MTCTL_INREQ :
pptps->pptps_state = PPTP_MTCTL_INREQ;
break;
case PPTP_MTCTL_INREP :
if (pptpo->pptps_state == PPTP_MTCTL_INREQ) {
pptps->pptps_state = PPTP_MTCTL_INREP;
pptp->pptp_call[0] = buffer[7];
pptp->pptp_call[1] = buffer[6];
ippr_pptp_donatstate(fin, nat, pptp);
}
break;
case PPTP_MTCTL_INCONNECT :
pptps->pptps_state = PPTP_MTCTL_INCONNECT;
break;
case PPTP_MTCTL_CLEAR :
pptps->pptps_state = PPTP_MTCTL_CLEAR;
break;
case PPTP_MTCTL_DISCONNECT :
pptps->pptps_state = PPTP_MTCTL_DISCONNECT;
break;
case PPTP_MTCTL_WANERROR :
pptps->pptps_state = PPTP_MTCTL_WANERROR;
break;
case PPTP_MTCTL_LINKINFO :
pptps->pptps_state = PPTP_MTCTL_LINKINFO;
break;
}
return 0;
}
/*
* For outgoing PPTP packets. refresh timeouts for NAT & state entries, if
* we can. If they have disappeared, recreate them.
*/
int ippr_pptp_inout(fin, aps, nat)
fr_info_t *fin;
ap_session_t *aps;
nat_t *nat;
{
pptp_pxy_t *pptp;
tcphdr_t *tcp;
int rev;
if ((fin->fin_out == 1) && (nat->nat_dir == NAT_INBOUND))
rev = 1;
else if ((fin->fin_out == 0) && (nat->nat_dir == NAT_OUTBOUND))
rev = 1;
else
rev = 0;
tcp = (tcphdr_t *)fin->fin_dp;
if ((tcp->th_flags & TH_OPENING) == TH_OPENING) {
pptp = (pptp_pxy_t *)aps->aps_data;
pptp->pptp_side[1 - rev].pptps_next = ntohl(tcp->th_ack);
pptp->pptp_side[1 - rev].pptps_nexthdr = ntohl(tcp->th_ack);
pptp->pptp_side[rev].pptps_next = ntohl(tcp->th_seq) + 1;
pptp->pptp_side[rev].pptps_nexthdr = ntohl(tcp->th_seq) + 1;
}
return ippr_pptp_nextmessage(fin, nat, (pptp_pxy_t *)aps->aps_data,
rev);
}
/*
* clean up after ourselves.
*/
void ippr_pptp_del(aps)
ap_session_t *aps;
{
pptp_pxy_t *pptp;
pptp = aps->aps_data;
if (pptp != NULL) {
/*
* Don't bother changing any of the NAT structure details,
* *_del() is on a callback from aps_free(), from nat_delete()
*/
READ_ENTER(&ipf_state);
if (pptp->pptp_state != NULL) {
pptp->pptp_state->is_die = fr_ticks + 1;
pptp->pptp_state->is_me = NULL;
fr_queuefront(&pptp->pptp_state->is_sti);
}
RWLOCK_EXIT(&ipf_state);
pptp->pptp_state = NULL;
pptp->pptp_nat = NULL;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,229 @@
/* $FreeBSD$ */
/*
* Copyright (C) 1993-2000 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.
*/
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__sgi)
# include <sys/systm.h>
#endif
#include <sys/errno.h>
#include <sys/param.h>
#if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux)
# include <sys/mbuf.h>
#endif
#if defined(__FreeBSD__) && (__FreeBSD_version > 220000)
# include <sys/sockio.h>
#else
# include <sys/ioctl.h>
#endif /* FreeBSD */
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include "netinet/ip_compat.h"
#include "netinet/ip_fil.h"
#include "netinet/ip_rules.h"
#ifndef _KERNEL
# include <string.h>
#endif /* _KERNEL */
#ifdef IPFILTER_COMPILED
static u_long in_rule__0[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80000000, 0x8002, 0, 0, 0, 0xffff, 0, 0, 0x4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static u_long out_rule__0[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80000000, 0x4002, 0, 0, 0, 0xffff, 0, 0, 0x4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
frentry_t *ipf_rules_in_[1] = {
(frentry_t *)&in_rule__0
};
frentry_t *ipfrule_match_in_(fin, passp)
fr_info_t *fin;
u_32_t *passp;
{
frentry_t *fr = NULL;
fr = (frentry_t *)&in_rule__0;
return fr;
}
frentry_t *ipf_rules_out_[1] = {
(frentry_t *)&out_rule__0
};
frentry_t *ipfrule_match_out_(fin, passp)
fr_info_t *fin;
u_32_t *passp;
{
frentry_t *fr = NULL;
fr = (frentry_t *)&out_rule__0;
return fr;
}
static frentry_t ipfrule_out_;
int ipfrule_add_out_()
{
int i, j, err = 0, max;
frentry_t *fp;
max = sizeof(ipf_rules_out_)/sizeof(frentry_t *);
for (i = 0; i < max; i++) {
fp = ipf_rules_out_[i];
fp->fr_next = NULL;
for (j = i + 1; j < max; j++)
if (strncmp(fp->fr_group,
ipf_rules_out_[j]->fr_group,
FR_GROUPLEN) == 0) {
fp->fr_next = ipf_rules_out_[j];
break;
}
}
fp = &ipfrule_out_;
bzero((char *)fp, sizeof(*fp));
fp->fr_type = FR_T_CALLFUNC|FR_T_BUILTIN;
fp->fr_flags = FR_OUTQUE|FR_NOMATCH;
fp->fr_data = (void *)ipf_rules_out_[0];
fp->fr_dsize = sizeof(ipf_rules_out_[0]);
fp->fr_v = 4;
fp->fr_func = (ipfunc_t)ipfrule_match_out_;
err = frrequest(IPL_LOGIPF, SIOCADDFR, (caddr_t)fp, fr_active, 0);
return err;
}
int ipfrule_remove_out_()
{
int err = 0, i;
frentry_t *fp;
/*
* Try to remove the outbound rule.
*/
if (ipfrule_out_.fr_ref > 0) {
err = EBUSY;
} else {
i = sizeof(ipf_rules_out_)/sizeof(frentry_t *) - 1;
for (; i >= 0; i--) {
fp = ipf_rules_out_[i];
if (fp->fr_ref > 1) {
err = EBUSY;
break;
}
}
}
if (err == 0)
err = frrequest(IPL_LOGIPF, SIOCDELFR,
(caddr_t)&ipfrule_out_, fr_active, 0);
if (err)
return err;
return err;
}
static frentry_t ipfrule_in_;
int ipfrule_add_in_()
{
int i, j, err = 0, max;
frentry_t *fp;
max = sizeof(ipf_rules_in_)/sizeof(frentry_t *);
for (i = 0; i < max; i++) {
fp = ipf_rules_in_[i];
fp->fr_next = NULL;
for (j = i + 1; j < max; j++)
if (strncmp(fp->fr_group,
ipf_rules_in_[j]->fr_group,
FR_GROUPLEN) == 0) {
fp->fr_next = ipf_rules_in_[j];
break;
}
}
fp = &ipfrule_in_;
bzero((char *)fp, sizeof(*fp));
fp->fr_type = FR_T_CALLFUNC|FR_T_BUILTIN;
fp->fr_flags = FR_INQUE|FR_NOMATCH;
fp->fr_data = (void *)ipf_rules_in_[0];
fp->fr_dsize = sizeof(ipf_rules_in_[0]);
fp->fr_v = 4;
fp->fr_func = (ipfunc_t)ipfrule_match_in_;
err = frrequest(IPL_LOGIPF, SIOCADDFR, (caddr_t)fp, fr_active, 0);
return err;
}
int ipfrule_remove_in_()
{
int err = 0, i;
frentry_t *fp;
/*
* Try to remove the inbound rule.
*/
if (ipfrule_in_.fr_ref > 0) {
err = EBUSY;
} else {
i = sizeof(ipf_rules_in_)/sizeof(frentry_t *) - 1;
for (; i >= 0; i--) {
fp = ipf_rules_in_[i];
if (fp->fr_ref > 1) {
err = EBUSY;
break;
}
}
}
if (err == 0)
err = frrequest(IPL_LOGIPF, SIOCDELFR,
(caddr_t)&ipfrule_in_, fr_active, 0);
if (err)
return err;
return err;
}
int ipfrule_add()
{
int err;
err = ipfrule_add_out_();
if (err != 0)
return err;
err = ipfrule_add_in_();
if (err != 0)
return err;
return 0;
}
int ipfrule_remove()
{
int err;
err = ipfrule_remove_out_();
if (err != 0)
return err;
err = ipfrule_remove_in_();
if (err != 0)
return err;
return 0;
}
#endif /* IPFILTER_COMPILED */

View File

@ -0,0 +1,16 @@
/* $FreeBSD$ */
extern int ipfrule_add __P((void));
extern int ipfrule_remove __P((void));
extern frentry_t *ipfrule_match_out_ __P((fr_info_t *, u_32_t *));
extern frentry_t *ipf_rules_out_[1];
extern int ipfrule_add_out_ __P((void));
extern int ipfrule_remove_out_ __P((void));
extern frentry_t *ipfrule_match_in_ __P((fr_info_t *, u_32_t *));
extern frentry_t *ipf_rules_in_[1];
extern int ipfrule_add_in_ __P((void));
extern int ipfrule_remove_in_ __P((void));

View File

@ -0,0 +1,594 @@
/* $FreeBSD$ */
/*
* Copyright (C) 1995-2001 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*/
#if defined(KERNEL) || defined(_KERNEL)
# undef KERNEL
# undef _KERNEL
# define KERNEL 1
# define _KERNEL 1
#endif
#include <sys/param.h>
#if defined(__hpux) && (HPUXREV >= 1111) && !defined(_KERNEL)
# include <sys/kern_svcs.h>
#endif
#include <sys/types.h>
#include <sys/time.h>
#include <sys/errno.h>
#if !defined(_KERNEL)
# include <stdlib.h>
# include <string.h>
# define _KERNEL
# ifdef __OpenBSD__
struct file;
# endif
# include <sys/uio.h>
# undef _KERNEL
#else
# include <sys/systm.h>
# if !defined(__svr4__) && !defined(__SVR4)
# include <sys/mbuf.h>
# endif
#endif
#include <sys/socket.h>
#if !defined(__hpux) && !defined(__osf__) && !defined(linux)
# include <sys/ioccom.h>
#endif
#ifdef __FreeBSD__
# include <sys/filio.h>
# include <sys/malloc.h>
#else
# include <sys/ioctl.h>
#endif
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <net/if.h>
#include "netinet/ip_compat.h"
#include "netinet/ip_fil.h"
#include "netinet/ip_state.h"
#include "netinet/ip_scan.h"
/* END OF INCLUDES */
#if !defined(lint)
static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-2000 Darren Reed";
static const char rcsid[] = "@(#)Id: ip_scan.c,v 2.40.2.2 2005/01/18 10:13:16 darrenr Exp";
#endif
#ifdef IPFILTER_SCAN /* endif at bottom of file */
ipscan_t *ipsc_list = NULL,
*ipsc_tail = NULL;
ipscanstat_t ipsc_stat;
# ifdef USE_MUTEXES
ipfrwlock_t ipsc_rwlock;
# endif
# ifndef isalpha
# define isalpha(x) (((x) >= 'A' && 'Z' >= (x)) || \
((x) >= 'a' && 'z' >= (x)))
# endif
int ipsc_add __P((caddr_t));
int ipsc_delete __P((caddr_t));
struct ipscan *ipsc_lookup __P((char *));
int ipsc_matchstr __P((sinfo_t *, char *, int));
int ipsc_matchisc __P((ipscan_t *, ipstate_t *, int, int, int *));
int ipsc_match __P((ipstate_t *));
int ipsc_init()
{
RWLOCK_INIT(&ipsc_rwlock, "ip scan rwlock");
return 0;
}
void fr_scanunload()
{
RW_DESTROY(&ipsc_rwlock);
}
int ipsc_add(data)
caddr_t data;
{
ipscan_t *i, *isc;
int err;
KMALLOC(isc, ipscan_t *);
if (!isc)
return ENOMEM;
err = copyinptr(data, isc, sizeof(*isc));
if (err)
return err;
WRITE_ENTER(&ipsc_rwlock);
i = ipsc_lookup(isc->ipsc_tag);
if (i) {
RWLOCK_EXIT(&ipsc_rwlock);
KFREE(isc);
return EEXIST;
}
if (ipsc_tail) {
ipsc_tail->ipsc_next = isc;
isc->ipsc_pnext = &ipsc_tail->ipsc_next;
ipsc_tail = isc;
} else {
ipsc_list = isc;
ipsc_tail = isc;
isc->ipsc_pnext = &ipsc_list;
}
isc->ipsc_next = NULL;
isc->ipsc_hits = 0;
isc->ipsc_fref = 0;
isc->ipsc_sref = 0;
isc->ipsc_active = 0;
ipsc_stat.iscs_entries++;
RWLOCK_EXIT(&ipsc_rwlock);
return 0;
}
int ipsc_delete(data)
caddr_t data;
{
ipscan_t isc, *i;
int err;
err = copyinptr(data, &isc, sizeof(isc));
if (err)
return err;
WRITE_ENTER(&ipsc_rwlock);
i = ipsc_lookup(isc.ipsc_tag);
if (i == NULL)
err = ENOENT;
else {
if (i->ipsc_fref) {
RWLOCK_EXIT(&ipsc_rwlock);
return EBUSY;
}
*i->ipsc_pnext = i->ipsc_next;
if (i->ipsc_next)
i->ipsc_next->ipsc_pnext = i->ipsc_pnext;
else {
if (i->ipsc_pnext == &ipsc_list)
ipsc_tail = NULL;
else
ipsc_tail = *(*i->ipsc_pnext)->ipsc_pnext;
}
ipsc_stat.iscs_entries--;
KFREE(i);
}
RWLOCK_EXIT(&ipsc_rwlock);
return err;
}
struct ipscan *ipsc_lookup(tag)
char *tag;
{
ipscan_t *i;
for (i = ipsc_list; i; i = i->ipsc_next)
if (!strcmp(i->ipsc_tag, tag))
return i;
return NULL;
}
int ipsc_attachfr(fr)
struct frentry *fr;
{
ipscan_t *i;
if (fr->fr_isctag[0]) {
READ_ENTER(&ipsc_rwlock);
i = ipsc_lookup(fr->fr_isctag);
if (i != NULL) {
ATOMIC_INC32(i->ipsc_fref);
}
RWLOCK_EXIT(&ipsc_rwlock);
if (i == NULL)
return ENOENT;
fr->fr_isc = i;
}
return 0;
}
int ipsc_attachis(is)
struct ipstate *is;
{
frentry_t *fr;
ipscan_t *i;
READ_ENTER(&ipsc_rwlock);
fr = is->is_rule;
if (fr) {
i = fr->fr_isc;
if (!i || (i != (ipscan_t *)-1)) {
is->is_isc = i;
if (i) {
ATOMIC_INC32(i->ipsc_sref);
if (i->ipsc_clen)
is->is_flags |= IS_SC_CLIENT;
else
is->is_flags |= IS_SC_MATCHC;
if (i->ipsc_slen)
is->is_flags |= IS_SC_SERVER;
else
is->is_flags |= IS_SC_MATCHS;
} else
is->is_flags |= (IS_SC_CLIENT|IS_SC_SERVER);
}
}
RWLOCK_EXIT(&ipsc_rwlock);
return 0;
}
int ipsc_detachfr(fr)
struct frentry *fr;
{
ipscan_t *i;
i = fr->fr_isc;
if (i != NULL) {
ATOMIC_DEC32(i->ipsc_fref);
}
return 0;
}
int ipsc_detachis(is)
struct ipstate *is;
{
ipscan_t *i;
READ_ENTER(&ipsc_rwlock);
if ((i = is->is_isc) && (i != (ipscan_t *)-1)) {
ATOMIC_DEC32(i->ipsc_sref);
is->is_isc = NULL;
is->is_flags &= ~(IS_SC_CLIENT|IS_SC_SERVER);
}
RWLOCK_EXIT(&ipsc_rwlock);
return 0;
}
/*
* 'string' compare for scanning
*/
int ipsc_matchstr(sp, str, n)
sinfo_t *sp;
char *str;
int n;
{
char *s, *t, *up;
int i = n;
if (i > sp->s_len)
i = sp->s_len;
up = str;
for (s = sp->s_txt, t = sp->s_msk; i; i--, s++, t++, up++)
switch ((int)*t)
{
case '.' :
if (*s != *up)
return 1;
break;
case '?' :
if (!ISALPHA(*up) || ((*s & 0x5f) != (*up & 0x5f)))
return 1;
break;
case '*' :
break;
}
return 0;
}
/*
* Returns 3 if both server and client match, 2 if just server,
* 1 if just client
*/
int ipsc_matchisc(isc, is, cl, sl, maxm)
ipscan_t *isc;
ipstate_t *is;
int cl, sl, maxm[2];
{
int i, j, k, n, ret = 0, flags;
flags = is->is_flags;
/*
* If we've already matched more than what is on offer, then
* assume we have a better match already and forget this one.
*/
if (maxm != NULL) {
if (isc->ipsc_clen < maxm[0])
return 0;
if (isc->ipsc_slen < maxm[1])
return 0;
j = maxm[0];
k = maxm[1];
} else {
j = 0;
k = 0;
}
if (!isc->ipsc_clen)
ret = 1;
else if (((flags & (IS_SC_MATCHC|IS_SC_CLIENT)) == IS_SC_CLIENT) &&
cl && isc->ipsc_clen) {
i = 0;
n = MIN(cl, isc->ipsc_clen);
if ((n > 0) && (!maxm || (n >= maxm[1]))) {
if (!ipsc_matchstr(&isc->ipsc_cl, is->is_sbuf[0], n)) {
i++;
ret |= 1;
if (n > j)
j = n;
}
}
}
if (!isc->ipsc_slen)
ret |= 2;
else if (((flags & (IS_SC_MATCHS|IS_SC_SERVER)) == IS_SC_SERVER) &&
sl && isc->ipsc_slen) {
i = 0;
n = MIN(cl, isc->ipsc_slen);
if ((n > 0) && (!maxm || (n >= maxm[1]))) {
if (!ipsc_matchstr(&isc->ipsc_sl, is->is_sbuf[1], n)) {
i++;
ret |= 2;
if (n > k)
k = n;
}
}
}
if (maxm && (ret == 3)) {
maxm[0] = j;
maxm[1] = k;
}
return ret;
}
int ipsc_match(is)
ipstate_t *is;
{
int i, j, k, n, cl, sl, maxm[2];
ipscan_t *isc, *lm;
tcpdata_t *t;
for (cl = 0, n = is->is_smsk[0]; n & 1; n >>= 1)
cl++;
for (sl = 0, n = is->is_smsk[1]; n & 1; n >>= 1)
sl++;
j = 0;
isc = is->is_isc;
if (isc != NULL) {
/*
* Known object to scan for.
*/
i = ipsc_matchisc(isc, is, cl, sl, NULL);
if (i & 1) {
is->is_flags |= IS_SC_MATCHC;
is->is_flags &= ~IS_SC_CLIENT;
} else if (cl >= isc->ipsc_clen)
is->is_flags &= ~IS_SC_CLIENT;
if (i & 2) {
is->is_flags |= IS_SC_MATCHS;
is->is_flags &= ~IS_SC_SERVER;
} else if (sl >= isc->ipsc_slen)
is->is_flags &= ~IS_SC_SERVER;
} else {
i = 0;
lm = NULL;
maxm[0] = 0;
maxm[1] = 0;
for (k = 0, isc = ipsc_list; isc; isc = isc->ipsc_next) {
i = ipsc_matchisc(isc, is, cl, sl, maxm);
if (i) {
/*
* We only want to remember the best match
* and the number of times we get a best
* match.
*/
if ((j == 3) && (i < 3))
continue;
if ((i == 3) && (j != 3))
k = 1;
else
k++;
j = i;
lm = isc;
}
}
if (k == 1)
isc = lm;
/*
* No matches or partial matches, so reset the respective
* search flag.
*/
if (!(j & 1))
is->is_flags &= ~IS_SC_CLIENT;
if (!(j & 2))
is->is_flags &= ~IS_SC_SERVER;
/*
* If we found the best match, then set flags appropriately.
*/
if ((j == 3) && (k == 1)) {
is->is_flags &= ~(IS_SC_SERVER|IS_SC_CLIENT);
is->is_flags |= (IS_SC_MATCHS|IS_SC_MATCHC);
}
}
/*
* If the acknowledged side of a connection has moved past the data in
* which we are interested, then reset respective flag.
*/
t = &is->is_tcp.ts_data[0];
if (t->td_end > is->is_s0[0] + 15)
is->is_flags &= ~IS_SC_CLIENT;
t = &is->is_tcp.ts_data[1];
if (t->td_end > is->is_s0[1] + 15)
is->is_flags &= ~IS_SC_SERVER;
/*
* Matching complete ?
*/
j = ISC_A_NONE;
if ((is->is_flags & IS_SC_MATCHALL) == IS_SC_MATCHALL) {
j = isc->ipsc_action;
ipsc_stat.iscs_acted++;
} else if ((is->is_isc != NULL) &&
((is->is_flags & IS_SC_MATCHALL) != IS_SC_MATCHALL) &&
!(is->is_flags & (IS_SC_CLIENT|IS_SC_SERVER))) {
/*
* Matching failed...
*/
j = isc->ipsc_else;
ipsc_stat.iscs_else++;
}
switch (j)
{
case ISC_A_CLOSE :
/*
* If as a result of a successful match we are to
* close a connection, change the "keep state" info.
* to block packets and generate TCP RST's.
*/
is->is_pass &= ~FR_RETICMP;
is->is_pass |= FR_RETRST;
break;
default :
break;
}
return i;
}
/*
* check if a packet matches what we're scanning for
*/
int ipsc_packet(fin, is)
fr_info_t *fin;
ipstate_t *is;
{
int i, j, rv, dlen, off, thoff;
u_32_t seq, s0;
tcphdr_t *tcp;
rv = !IP6_EQ(&fin->fin_fi.fi_src, &is->is_src);
tcp = fin->fin_dp;
seq = ntohl(tcp->th_seq);
if (!is->is_s0[rv])
return 1;
/*
* check if this packet has more data that falls within the first
* 16 bytes sent in either direction.
*/
s0 = is->is_s0[rv];
off = seq - s0;
if ((off > 15) || (off < 0))
return 1;
thoff = TCP_OFF(tcp) << 2;
dlen = fin->fin_dlen - thoff;
if (dlen <= 0)
return 1;
if (dlen > 16)
dlen = 16;
if (off + dlen > 16)
dlen = 16 - off;
j = 0xffff >> (16 - dlen);
i = (0xffff & j) << off;
#ifdef _KERNEL
COPYDATA(*(mb_t **)fin->fin_mp, fin->fin_hlen + thoff, dlen,
(caddr_t)is->is_sbuf[rv] + off);
#endif
is->is_smsk[rv] |= i;
for (j = 0, i = is->is_smsk[rv]; i & 1; i >>= 1)
j++;
if (j == 0)
return 1;
(void) ipsc_match(is);
#if 0
/*
* There is the potential here for plain text passwords to get
* buffered and stored for some time...
*/
if (!(is->is_flags & IS_SC_CLIENT))
bzero(is->is_sbuf[0], sizeof(is->is_sbuf[0]));
if (!(is->is_flags & IS_SC_SERVER))
bzero(is->is_sbuf[1], sizeof(is->is_sbuf[1]));
#endif
return 0;
}
int fr_scan_ioctl(data, cmd, mode)
caddr_t data;
ioctlcmd_t cmd;
int mode;
{
ipscanstat_t ipscs;
int err = 0;
switch (cmd)
{
case SIOCADSCA :
err = ipsc_add(data);
break;
case SIOCRMSCA :
err = ipsc_delete(data);
break;
case SIOCGSCST :
bcopy((char *)&ipsc_stat, (char *)&ipscs, sizeof(ipscs));
ipscs.iscs_list = ipsc_list;
BCOPYOUT(&ipscs, data, sizeof(ipscs));
break;
default :
err = EINVAL;
break;
}
return err;
}
#endif /* IPFILTER_SCAN */

View File

@ -0,0 +1,108 @@
/* $FreeBSD$ */
/*
* Copyright (C) 1993-2001 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
* @(#)ip_fil.h 1.35 6/5/96
* Id: ip_scan.h,v 2.9 2003/07/25 22:05:01 darrenr Exp
*/
#ifndef __IP_SCAN_H__
#define __IP_SCAN_H__ 1
#ifdef sun
# include <sys/ioccom.h>
#endif
#define IPSCAN_NAME "/dev/ipscan"
#define IPL_SCAN IPSCAN_NAME
#define ISC_TLEN 16
struct fr_info;
struct frentry;
struct ip;
struct ipstate;
#if defined(__STDC__) || defined(__GNUC__)
# define SIOCADSCA _IOWR('r', 60, struct ipscan *)
# define SIOCRMSCA _IOWR('r', 61, struct ipscan *)
# define SIOCGSCST _IOWR('r', 62, struct ipscan *)
#else
# define SIOCADSCA _IOWR(r, 60, struct ipscan *)
# define SIOCRMSCA _IOWR(r, 61, struct ipscan *)
# define SIOCGSCST _IOWR(r, 62, struct ipscan *)
#endif
struct action {
int act_val; /* what to do */
struct in_addr act_ip; /* redirect IP# */
u_short act_port; /* redirect port number */
int act_else; /* what to do */
struct in_addr act_eip; /* redirect IP# */
u_short act_eport; /* redirect port number */
};
typedef struct sinfo {
char s_txt[ISC_TLEN]; /* text to match */
char s_msk[ISC_TLEN]; /* mask of the above to check */
int s_len; /* length of server text */
} sinfo_t;
typedef struct ipscan {
struct ipscan *ipsc_next;
struct ipscan **ipsc_pnext;
char ipsc_tag[ISC_TLEN]; /* table entry protocol tag */
sinfo_t ipsc_si[2]; /* client/server side information */
int ipsc_hits; /* times this has been matched */
int ipsc_active; /* # of active matches */
int ipsc_fref; /* # of references from filter rules */
int ipsc_sref; /* # of references from state entries */
struct action ipsc_act;
} ipscan_t;
#define ipsc_cl ipsc_si[0]
#define ipsc_sl ipsc_si[1]
#define ipsc_ctxt ipsc_cl.s_txt
#define ipsc_cmsk ipsc_cl.s_msk
#define ipsc_clen ipsc_cl.s_len
#define ipsc_stxt ipsc_sl.s_txt
#define ipsc_smsk ipsc_sl.s_msk
#define ipsc_slen ipsc_sl.s_len
#define ipsc_action ipsc_act.act_val
#define ipsc_ip ipsc_act.act_ip
#define ipsc_port ipsc_act.act_port
#define ipsc_else ipsc_act.act_else
#define ipsc_eip ipsc_act.act_eip
#define ipsc_eport ipsc_act.act_eport
#define ISC_A_NONE 0
#define ISC_A_TRACK 1
#define ISC_A_CLOSE 2
#define ISC_A_REDIRECT 3
typedef struct ipscanstat {
struct ipscan *iscs_list;
u_long iscs_acted;
u_long iscs_else;
int iscs_entries;
} ipscanstat_t;
extern int fr_scan_ioctl __P((caddr_t, ioctlcmd_t, int));
extern int ipsc_init __P((void));
extern int ipsc_attachis __P((struct ipstate *));
extern int ipsc_attachfr __P((struct frentry *));
extern int ipsc_detachis __P((struct ipstate *));
extern int ipsc_detachfr __P((struct frentry *));
extern int ipsc_packet __P((struct fr_info *, struct ipstate *));
extern void fr_scanunload __P((void));
#endif /* __IP_SCAN_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,117 @@
/* $FreeBSD$ */
/*
* Copyright (C) 1993-2001 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
* @(#)ip_fil.h 1.35 6/5/96
* Id: ip_sync.h,v 2.11.2.2 2004/11/04 19:29:07 darrenr Exp
*/
#ifndef __IP_SYNC_H__
#define __IP_SYNC_H__
typedef struct synchdr {
u_32_t sm_magic; /* magic */
u_char sm_v; /* version: 4,6 */
u_char sm_p; /* protocol */
u_char sm_cmd; /* command */
u_char sm_table; /* NAT, STATE, etc */
u_int sm_num; /* table entry number */
int sm_rev; /* forward/reverse */
int sm_len; /* length of the data section */
struct synclist *sm_sl; /* back pointer to parent */
} synchdr_t;
#define SYNHDRMAGIC 0x0FF51DE5
/*
* Commands
* No delete required as expirey will take care of that!
*/
#define SMC_CREATE 0 /* pass ipstate_t after synchdr_t */
#define SMC_UPDATE 1
#define SMC_MAXCMD 1
/*
* Tables
*/
#define SMC_NAT 0
#define SMC_STATE 1
#define SMC_MAXTBL 1
/*
* Only TCP requires "more" information than just a reference to the entry
* for which an update is being made.
*/
typedef struct synctcp_update {
u_long stu_age;
tcpdata_t stu_data[2];
int stu_state[2];
} synctcp_update_t;
typedef struct synclist {
struct synclist *sl_next;
struct synclist **sl_pnext;
int sl_idx; /* update index */
struct synchdr sl_hdr;
union {
struct ipstate *slu_ips;
struct nat *slu_ipn;
void *slu_ptr;
} sl_un;
} synclist_t;
#define sl_ptr sl_un.slu_ptr
#define sl_ips sl_un.slu_ips
#define sl_ipn sl_un.slu_ipn
#define sl_magic sl_hdr.sm_magic
#define sl_v sl_hdr.sm_v
#define sl_p sl_hdr.sm_p
#define sl_cmd sl_hdr.sm_cmd
#define sl_rev sl_hdr.sm_rev
#define sl_table sl_hdr.sm_table
#define sl_num sl_hdr.sm_num
#define sl_len sl_hdr.sm_len
/*
* NOTE: SYNCLOG_SZ is defined *low*. It should be the next power of two
* up for whatever number of packets per second you expect to see. Be
* warned: this index's a table of large elements (upto 272 bytes in size
* each), and thus a size of 8192, for example, results in a 2MB table.
* The lesson here is not to use small machines for running fast firewalls
* (100BaseT) in sync, where you might have upwards of 10k pps.
*/
#define SYNCLOG_SZ 256
typedef struct synclogent {
struct synchdr sle_hdr;
union {
struct ipstate sleu_ips;
struct nat sleu_ipn;
} sle_un;
} synclogent_t;
typedef struct syncupdent { /* 28 or 32 bytes */
struct synchdr sup_hdr;
struct synctcp_update sup_tcp;
} syncupdent_t;
extern synclogent_t synclog[SYNCLOG_SZ];
extern int fr_sync_ioctl __P((caddr_t, ioctlcmd_t, int));
extern synclist_t *ipfsync_new __P((int, fr_info_t *, void *));
extern void ipfsync_del __P((synclist_t *));
extern void ipfsync_update __P((int, fr_info_t *, synclist_t *));
extern int ipfsync_init __P((void));
extern int ipfsync_nat __P((synchdr_t *sp, void *data));
extern int ipfsync_state __P((synchdr_t *sp, void *data));
extern int ipfsync_read __P((struct uio *uio));
extern int ipfsync_write __P((struct uio *uio));
#endif /* IP_SYNC */