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:
commit
d607092b37
1692
sys/contrib/ipfilter/netinet/ip_fil_freebsd.c
Normal file
1692
sys/contrib/ipfilter/netinet/ip_fil_freebsd.c
Normal file
File diff suppressed because it is too large
Load Diff
455
sys/contrib/ipfilter/netinet/ip_htable.c
Normal file
455
sys/contrib/ipfilter/netinet/ip_htable.c
Normal 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 */
|
71
sys/contrib/ipfilter/netinet/ip_htable.h
Normal file
71
sys/contrib/ipfilter/netinet/ip_htable.h
Normal 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__ */
|
@ -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;
|
||||
|
435
sys/contrib/ipfilter/netinet/ip_irc_pxy.c
Normal file
435
sys/contrib/ipfilter/netinet/ip_irc_pxy.c
Normal 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);
|
||||
}
|
530
sys/contrib/ipfilter/netinet/ip_lookup.c
Normal file
530
sys/contrib/ipfilter/netinet/ip_lookup.c
Normal 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 */
|
65
sys/contrib/ipfilter/netinet/ip_lookup.h
Normal file
65
sys/contrib/ipfilter/netinet/ip_lookup.h
Normal 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__ */
|
@ -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;
|
||||
}
|
||||
|
786
sys/contrib/ipfilter/netinet/ip_pool.c
Normal file
786
sys/contrib/ipfilter/netinet/ip_pool.c
Normal 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 */
|
87
sys/contrib/ipfilter/netinet/ip_pool.h
Normal file
87
sys/contrib/ipfilter/netinet/ip_pool.h
Normal 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__ */
|
527
sys/contrib/ipfilter/netinet/ip_pptp_pxy.c
Normal file
527
sys/contrib/ipfilter/netinet/ip_pptp_pxy.c
Normal 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;
|
||||
}
|
||||
}
|
1460
sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c
Normal file
1460
sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c
Normal file
File diff suppressed because it is too large
Load Diff
229
sys/contrib/ipfilter/netinet/ip_rules.c
Normal file
229
sys/contrib/ipfilter/netinet/ip_rules.c
Normal 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 */
|
16
sys/contrib/ipfilter/netinet/ip_rules.h
Normal file
16
sys/contrib/ipfilter/netinet/ip_rules.h
Normal 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));
|
594
sys/contrib/ipfilter/netinet/ip_scan.c
Normal file
594
sys/contrib/ipfilter/netinet/ip_scan.c
Normal 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 */
|
108
sys/contrib/ipfilter/netinet/ip_scan.h
Normal file
108
sys/contrib/ipfilter/netinet/ip_scan.h
Normal 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__ */
|
1001
sys/contrib/ipfilter/netinet/ip_sync.c
Normal file
1001
sys/contrib/ipfilter/netinet/ip_sync.c
Normal file
File diff suppressed because it is too large
Load Diff
117
sys/contrib/ipfilter/netinet/ip_sync.h
Normal file
117
sys/contrib/ipfilter/netinet/ip_sync.h
Normal 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 */
|
Loading…
x
Reference in New Issue
Block a user