Index: vendor-sys/ipfilter/v3_4_4/sys/netinet/fil.c =================================================================== --- vendor-sys/ipfilter/v3_4_4/sys/netinet/fil.c (nonexistent) +++ vendor-sys/ipfilter/v3_4_4/sys/netinet/fil.c (revision 60849) @@ -0,0 +1,2010 @@ +/* + * 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. + */ +#if !defined(lint) +static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.8 2000/05/22 10:26:09 darrenr Exp $"; +#endif + +#if defined(_KERNEL) && defined(__FreeBSD_version) && \ + (__FreeBSD_version >= 400000) && !defined(KLD_MODULE) +#include "opt_inet6.h" +#endif +#include +#include +#include +#include +#include +#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ + defined(_KERNEL) +# include "opt_ipfilter_log.h" +#endif +#if (defined(KERNEL) || defined(_KERNEL)) && defined(__FreeBSD_version) && \ + (__FreeBSD_version >= 220000) +# include +# include +#else +# include +#endif +#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux) +# include +#else +# include +# include +# include +#endif +#include +#if !defined(__SVR4) && !defined(__svr4__) +# ifndef linux +# include +# endif +#else +# include +# if SOLARIS2 < 5 +# include +# endif +# include +#endif +#ifndef linux +# include +# include +#endif +#include +#ifdef sun +# include +#endif +#include +#include +#include +#include +#ifndef linux +# include +#endif +#if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */ +# include +# include +#endif +#include +#include +#include +#include "netinet/ip_compat.h" +#ifdef USE_INET6 +# include +# if !SOLARIS && defined(_KERNEL) +# include +# endif +#endif +#include +#include "netinet/ip_fil.h" +#include "netinet/ip_proxy.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_frag.h" +#include "netinet/ip_state.h" +#include "netinet/ip_auth.h" +# if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) +# include +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# include "opt_ipfilter.h" +# endif +# endif +#ifndef MIN +# define MIN(a,b) (((a)<(b))?(a):(b)) +#endif +#include "netinet/ipl.h" + +#ifndef _KERNEL +# include "ipf.h" +# include "ipt.h" +extern int opts; + +# define FR_VERBOSE(verb_pr) verbose verb_pr +# define FR_DEBUG(verb_pr) debug verb_pr +# define IPLLOG(a, c, d, e) ipllog() +#else /* #ifndef _KERNEL */ +# define FR_VERBOSE(verb_pr) +# define FR_DEBUG(verb_pr) +# define IPLLOG(a, c, d, e) ipflog(a, c, d, e) +# if SOLARIS || defined(__sgi) +extern KRWLOCK_T ipf_mutex, ipf_auth, ipf_nat; +extern kmutex_t ipf_rw; +# endif +# if SOLARIS +# define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, \ + ip, qif) +# define SEND_RESET(ip, qif, if, fin) send_reset(fin, ip, qif) +# else /* SOLARIS */ +# define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, ip) +# define SEND_RESET(ip, qif, if, fin) send_reset(fin, ip) +# endif /* SOLARIS || __sgi */ +#endif /* _KERNEL */ + + +struct filterstats frstats[2] = {{0,0,0,0,0},{0,0,0,0,0}}; +struct frentry *ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } }, +#ifdef USE_INET6 + *ipfilter6[2][2] = { { NULL, NULL }, { NULL, NULL } }, + *ipacct6[2][2] = { { NULL, NULL }, { NULL, NULL } }, +#endif + *ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } }; +struct frgroup *ipfgroups[3][2]; +int fr_flags = IPF_LOGGING; +int fr_active = 0; +int fr_chksrc = 0; +#if defined(IPFILTER_DEFAULT_BLOCK) +int fr_pass = FR_NOMATCH|FR_BLOCK; +#else +int fr_pass = (IPF_DEFAULT_PASS|FR_NOMATCH); +#endif +char ipfilter_version[] = IPL_VERSION; + +fr_info_t frcache[2]; + +static int frflushlist __P((int, minor_t, int *, frentry_t **)); +#ifdef _KERNEL +static void frsynclist __P((frentry_t *)); +#endif + + +/* + * bit values for identifying presence of individual IP options + */ +struct optlist ipopts[20] = { + { IPOPT_NOP, 0x000001 }, + { IPOPT_RR, 0x000002 }, + { IPOPT_ZSU, 0x000004 }, + { IPOPT_MTUP, 0x000008 }, + { IPOPT_MTUR, 0x000010 }, + { IPOPT_ENCODE, 0x000020 }, + { IPOPT_TS, 0x000040 }, + { IPOPT_TR, 0x000080 }, + { IPOPT_SECURITY, 0x000100 }, + { IPOPT_LSRR, 0x000200 }, + { IPOPT_E_SEC, 0x000400 }, + { IPOPT_CIPSO, 0x000800 }, + { IPOPT_SATID, 0x001000 }, + { IPOPT_SSRR, 0x002000 }, + { IPOPT_ADDEXT, 0x004000 }, + { IPOPT_VISA, 0x008000 }, + { IPOPT_IMITD, 0x010000 }, + { IPOPT_EIP, 0x020000 }, + { IPOPT_FINN, 0x040000 }, + { 0, 0x000000 } +}; + +/* + * bit values for identifying presence of individual IP security options + */ +struct optlist secopt[8] = { + { IPSO_CLASS_RES4, 0x01 }, + { IPSO_CLASS_TOPS, 0x02 }, + { IPSO_CLASS_SECR, 0x04 }, + { IPSO_CLASS_RES3, 0x08 }, + { IPSO_CLASS_CONF, 0x10 }, + { IPSO_CLASS_UNCL, 0x20 }, + { IPSO_CLASS_RES2, 0x40 }, + { IPSO_CLASS_RES1, 0x80 } +}; + + +/* + * compact the IP header into a structure which contains just the info. + * which is useful for comparing IP headers with. + */ +void fr_makefrip(hlen, ip, fin) +int hlen; +ip_t *ip; +fr_info_t *fin; +{ + u_short optmsk = 0, secmsk = 0, auth = 0; + int i, mv, ol, off, p, plen, v; + fr_ip_t *fi = &fin->fin_fi; + struct optlist *op; + u_char *s, opt; + tcphdr_t *tcp; + + fin->fin_rev = 0; + fin->fin_fr = NULL; + fin->fin_tcpf = 0; + fin->fin_data[0] = 0; + fin->fin_data[1] = 0; + fin->fin_rule = -1; + fin->fin_group = -1; +#ifdef _KERNEL + fin->fin_icode = ipl_unreach; +#endif + v = fin->fin_v; + fi->fi_v = v; + fin->fin_hlen = hlen; + if (v == 4) { + fin->fin_id = ip->ip_id; + fi->fi_tos = ip->ip_tos; + off = (ip->ip_off & IP_OFFMASK) << 3; + tcp = (tcphdr_t *)((char *)ip + hlen); + (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4)); + fi->fi_src.i6[1] = 0; + fi->fi_src.i6[2] = 0; + fi->fi_src.i6[3] = 0; + fi->fi_dst.i6[1] = 0; + fi->fi_dst.i6[2] = 0; + fi->fi_dst.i6[3] = 0; + fi->fi_saddr = ip->ip_src.s_addr; + fi->fi_daddr = ip->ip_dst.s_addr; + p = ip->ip_p; + fi->fi_fl = (hlen > sizeof(ip_t)) ? FI_OPTIONS : 0; + if (ip->ip_off & 0x3fff) + fi->fi_fl |= FI_FRAG; + plen = ip->ip_len; + fin->fin_dlen = plen - hlen; + } +#ifdef USE_INET6 + else if (v == 6) { + ip6_t *ip6 = (ip6_t *)ip; + + off = 0; + p = ip6->ip6_nxt; + fi->fi_p = p; + fi->fi_ttl = ip6->ip6_hlim; + tcp = (tcphdr_t *)(ip6 + 1); + fi->fi_src.in6 = ip6->ip6_src; + fi->fi_dst.in6 = ip6->ip6_dst; + fin->fin_id = (u_short)(ip6->ip6_flow & 0xffff); + fi->fi_tos = 0; + fi->fi_fl = 0; + plen = ntohs(ip6->ip6_plen); + fin->fin_dlen = plen; + } +#endif + else + return; + + fin->fin_off = off; + fin->fin_plen = plen; + fin->fin_dp = (void *)tcp; + + switch (p) + { + case IPPROTO_ICMP : + { + int minicmpsz = sizeof(struct icmp); + icmphdr_t *icmp; + + icmp = (icmphdr_t *)tcp; + + if (!off && (icmp->icmp_type == ICMP_ECHOREPLY || + icmp->icmp_type == ICMP_ECHO)) + minicmpsz = ICMP_MINLEN; + + /* type(1) + code(1) + cksum(2) + id(2) seq(2) + + * 3*timestamp(3*4) */ + else if (!off && (icmp->icmp_type == ICMP_TSTAMP || + icmp->icmp_type == ICMP_TSTAMPREPLY)) + minicmpsz = 20; + + /* type(1) + code(1) + cksum(2) + id(2) seq(2) + mask(4) */ + else if (!off && (icmp->icmp_type == ICMP_MASKREQ || + icmp->icmp_type == ICMP_MASKREPLY)) + minicmpsz = 12; + + if ((!(plen >= hlen + minicmpsz) && !off) || + (off && off < sizeof(struct icmp))) + fi->fi_fl |= FI_SHORT; + if (fin->fin_dlen > 1) + fin->fin_data[0] = *(u_short *)tcp; + break; + } + case IPPROTO_TCP : + fi->fi_fl |= FI_TCPUDP; +#ifdef USE_INET6 + if (v == 6) { + if (plen < sizeof(struct tcphdr)) + fi->fi_fl |= FI_SHORT; + } else +#endif + if (v == 4) { + if ((!IPMINLEN(ip, tcphdr) && !off) || + (off && off < sizeof(struct tcphdr))) + fi->fi_fl |= FI_SHORT; + } + if (!(fi->fi_fl & FI_SHORT) && !off) + fin->fin_tcpf = tcp->th_flags; + goto getports; + case IPPROTO_UDP : + fi->fi_fl |= FI_TCPUDP; +#ifdef USE_INET6 + if (v == 6) { + if (plen < sizeof(struct udphdr)) + fi->fi_fl |= FI_SHORT; + } else +#endif + if (v == 4) { + if ((!IPMINLEN(ip, udphdr) && !off) || + (off && off < sizeof(struct udphdr))) + fi->fi_fl |= FI_SHORT; + } +getports: + if (!off && (fin->fin_dlen > 3)) { + fin->fin_data[0] = ntohs(tcp->th_sport); + fin->fin_data[1] = ntohs(tcp->th_dport); + } + break; + default : + break; + } + +#ifdef USE_INET6 + if (v == 6) { + fi->fi_optmsk = 0; + fi->fi_secmsk = 0; + fi->fi_auth = 0; + return; + } +#endif + + for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) { + opt = *s; + if (opt == '\0') + break; + else if (opt == IPOPT_NOP) + ol = 1; + else { + if (hlen < 2) + break; + ol = (int)*(s + 1); + if (ol < 2 || ol > hlen) + break; + } + for (i = 9, mv = 4; mv >= 0; ) { + op = ipopts + i; + if (opt == (u_char)op->ol_val) { + optmsk |= op->ol_bit; + if (opt == IPOPT_SECURITY) { + struct optlist *sp; + u_char sec; + int j, m; + + sec = *(s + 2); /* classification */ + for (j = 3, m = 2; m >= 0; ) { + sp = secopt + j; + if (sec == sp->ol_val) { + secmsk |= sp->ol_bit; + auth = *(s + 3); + auth *= 256; + auth += *(s + 4); + break; + } + if (sec < sp->ol_val) + j -= m--; + else + j += m--; + } + } + break; + } + if (opt < op->ol_val) + i -= mv--; + else + i += mv--; + } + hlen -= ol; + s += ol; + } + if (auth && !(auth & 0x0100)) + auth &= 0xff00; + fi->fi_optmsk = optmsk; + fi->fi_secmsk = secmsk; + fi->fi_auth = auth; +} + + +/* + * check an IP packet for TCP/UDP characteristics such as ports and flags. + */ +int fr_tcpudpchk(ft, fin) +frtuc_t *ft; +fr_info_t *fin; +{ + register u_short po, tup; + register char i; + register int err = 1; + + /* + * Both ports should *always* be in the first fragment. + * So far, I cannot find any cases where they can not be. + * + * compare destination ports + */ + if ((i = (int)ft->ftu_dcmp)) { + po = ft->ftu_dport; + tup = fin->fin_data[1]; + /* + * Do opposite test to that required and + * continue if that succeeds. + */ + if (!--i && tup != po) /* EQUAL */ + err = 0; + else if (!--i && tup == po) /* NOTEQUAL */ + err = 0; + else if (!--i && tup >= po) /* LESSTHAN */ + err = 0; + else if (!--i && tup <= po) /* GREATERTHAN */ + err = 0; + else if (!--i && tup > po) /* LT or EQ */ + err = 0; + else if (!--i && tup < po) /* GT or EQ */ + err = 0; + else if (!--i && /* Out of range */ + (tup >= po && tup <= ft->ftu_dtop)) + err = 0; + else if (!--i && /* In range */ + (tup <= po || tup >= ft->ftu_dtop)) + err = 0; + } + /* + * compare source ports + */ + if (err && (i = (int)ft->ftu_scmp)) { + po = ft->ftu_sport; + tup = fin->fin_data[0]; + if (!--i && tup != po) + err = 0; + else if (!--i && tup == po) + err = 0; + else if (!--i && tup >= po) + err = 0; + else if (!--i && tup <= po) + err = 0; + else if (!--i && tup > po) + err = 0; + else if (!--i && tup < po) + err = 0; + else if (!--i && /* Out of range */ + (tup >= po && tup <= ft->ftu_stop)) + err = 0; + else if (!--i && /* In range */ + (tup <= po || tup >= ft->ftu_stop)) + err = 0; + } + + /* + * If we don't have all the TCP/UDP header, then how can we + * expect to do any sort of match on it ? If we were looking for + * TCP flags, then NO match. If not, then match (which should + * satisfy the "short" class too). + */ + if (err && (fin->fin_fi.fi_p == IPPROTO_TCP)) { + if (fin->fin_fi.fi_fl & FI_SHORT) + return !(ft->ftu_tcpf | ft->ftu_tcpfm); + /* + * Match the flags ? If not, abort this match. + */ + if (ft->ftu_tcpfm && + ft->ftu_tcpf != (fin->fin_tcpf & ft->ftu_tcpfm)) { + FR_DEBUG(("f. %#x & %#x != %#x\n", fin->fin_tcpf, + ft->ftu_tcpfm, ft->ftu_tcpf)); + err = 0; + } + } + return err; +} + +/* + * Check the input/output list of rules for a match and result. + * Could be per interface, but this gets real nasty when you don't have + * kernel sauce. + */ +int fr_scanlist(pass, ip, fin, m) +u_32_t pass; +ip_t *ip; +register fr_info_t *fin; +void *m; +{ + register struct frentry *fr; + register fr_ip_t *fi = &fin->fin_fi; + int rulen, portcmp = 0, off, skip = 0, logged = 0; + u_32_t passt; + + fr = fin->fin_fr; + fin->fin_fr = NULL; + fin->fin_rule = 0; + fin->fin_group = 0; + if (fin->fin_v == 4) + off = ip->ip_off & IP_OFFMASK; + else + off = 0; + pass |= (fi->fi_fl << 24); + + if ((fi->fi_fl & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) + portcmp = 1; + + for (rulen = 0; fr; fr = fr->fr_next, rulen++) { + if (skip) { + skip--; + continue; + } + /* + * In all checks below, a null (zero) value in the + * filter struture is taken to mean a wildcard. + * + * check that we are working for the right interface + */ +#ifdef _KERNEL +# if BSD >= 199306 + if (fin->fin_out != 0) { + if ((fr->fr_oifa && + fr->fr_oifa != ((mb_t *)m)->m_pkthdr.rcvif) || + (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)) + continue; + } else +# endif + if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) + continue; +#else + if (opts & (OPT_VERBOSE|OPT_DEBUG)) + printf("\n"); + FR_VERBOSE(("%c", (pass & FR_PASS) ? 'p' : + (pass & FR_AUTH) ? 'a' : 'b')); + if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) + continue; + FR_VERBOSE((":i")); +#endif + { + register u_32_t *ld, *lm, *lip; + register int i; + + lip = (u_32_t *)fi; + lm = (u_32_t *)&fr->fr_mip; + ld = (u_32_t *)&fr->fr_ip; + i = ((*lip & *lm) != *ld); + FR_DEBUG(("0. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + if (i) + continue; + /* + * We now know whether the packet version and the + * rule version match, along with protocol, ttl and + * tos. + */ + lip++, lm++, ld++; + /* + * Unrolled loops (4 each, for 32 bits). + */ + i |= ((*lip & *lm) != *ld) << 19; + FR_DEBUG(("1a. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + if (fi->fi_v == 6) { + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 19; + FR_DEBUG(("1b. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 19; + FR_DEBUG(("1c. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 19; + FR_DEBUG(("1d. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + } else { + lip += 3; + lm += 3; + ld += 3; + } + i ^= (fr->fr_flags & FR_NOTSRCIP); + if (i) + continue; + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 20; + FR_DEBUG(("2a. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + if (fi->fi_v == 6) { + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 20; + FR_DEBUG(("2b. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 20; + FR_DEBUG(("2c. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 20; + FR_DEBUG(("2d. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + } else { + lip += 3; + lm += 3; + ld += 3; + } + i ^= (fr->fr_flags & FR_NOTDSTIP); + if (i) + continue; + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("3. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("4. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + if (i) + continue; + } + + /* + * If a fragment, then only the first has what we're looking + * for here... + */ + if (!portcmp && (fr->fr_dcmp || fr->fr_scmp || fr->fr_tcpf || + fr->fr_tcpfm)) + continue; + if (fi->fi_fl & FI_TCPUDP) { + if (!fr_tcpudpchk(&fr->fr_tuc, fin)) + continue; + } else if (fr->fr_icmpm || fr->fr_icmp) { + if ((fi->fi_p != IPPROTO_ICMP) || off || + (fin->fin_dlen < 2)) + continue; + if ((fin->fin_data[0] & fr->fr_icmpm) != fr->fr_icmp) { + FR_DEBUG(("i. %#x & %#x != %#x\n", + fin->fin_data[0], fr->fr_icmpm, + fr->fr_icmp)); + continue; + } + } + FR_VERBOSE(("*")); + /* + * Just log this packet... + */ + passt = fr->fr_flags; + if ((passt & FR_CALLNOW) && fr->fr_func) + passt = (*fr->fr_func)(passt, ip, fin); + fin->fin_fr = fr; +#ifdef IPFILTER_LOG + if ((passt & FR_LOGMASK) == FR_LOG) { + if (!IPLLOG(passt, ip, fin, m)) { + if (passt & FR_LOGORBLOCK) + passt |= FR_BLOCK|FR_QUICK; + ATOMIC_INCL(frstats[fin->fin_out].fr_skip); + } + ATOMIC_INCL(frstats[fin->fin_out].fr_pkl); + logged = 1; + } +#endif /* IPFILTER_LOG */ + if (!(skip = fr->fr_skip) && (passt & FR_LOGMASK) != FR_LOG) + pass = passt; + FR_DEBUG(("pass %#x\n", pass)); + ATOMIC_INCL(fr->fr_hits); + if (pass & FR_ACCOUNT) + fr->fr_bytes += (U_QUAD_T)ip->ip_len; + else + fin->fin_icode = fr->fr_icode; + fin->fin_rule = rulen; + fin->fin_group = fr->fr_group; + if (fr->fr_grp) { + fin->fin_fr = fr->fr_grp; + pass = fr_scanlist(pass, ip, fin, m); + if (fin->fin_fr == NULL) { + fin->fin_rule = rulen; + fin->fin_group = fr->fr_group; + fin->fin_fr = fr; + } + if (pass & FR_DONTCACHE) + logged = 1; + } + if (pass & FR_QUICK) + break; + } + if (logged) + pass |= FR_DONTCACHE; + return pass; +} + + +/* + * frcheck - filter check + * check using source and destination addresses/ports in a packet whether + * or not to pass it on or not. + */ +int fr_check(ip, hlen, ifp, out +#if defined(_KERNEL) && SOLARIS +, qif, mp) +qif_t *qif; +#else +, mp) +#endif +mb_t **mp; +ip_t *ip; +int hlen; +void *ifp; +int out; +{ + /* + * The above really sucks, but short of writing a diff + */ + fr_info_t frinfo, *fc; + register fr_info_t *fin = &frinfo; + int changed, error = EHOSTUNREACH, v = ip->ip_v; + frentry_t *fr = NULL, *list; + u_32_t pass, apass; +#if !SOLARIS || !defined(_KERNEL) + register mb_t *m = *mp; +#endif + +#ifdef _KERNEL + mb_t *mc = NULL; +# if !defined(__SVR4) && !defined(__svr4__) +# ifdef __sgi + char hbuf[(0xf << 2) + sizeof(struct icmp) + sizeof(ip_t) + 8]; +# endif + int up; + +# ifdef M_CANFASTFWD + /* + * XXX For now, IP Filter and fast-forwarding of cached flows + * XXX are mutually exclusive. Eventually, IP Filter should + * XXX get a "can-fast-forward" filter rule. + */ + m->m_flags &= ~M_CANFASTFWD; +# endif /* M_CANFASTFWD */ +# ifdef CSUM_DELAY_DATA + /* + * disable delayed checksums. + */ + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { + in_delayed_cksum(m); + m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; + } +# endif /* CSUM_DELAY_DATA */ + + + if ((ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP || + ip->ip_p == IPPROTO_ICMP)) { + int plen = 0; + + if ((ip->ip_off & IP_OFFMASK) == 0) + switch(ip->ip_p) + { + case IPPROTO_TCP: + plen = sizeof(tcphdr_t); + break; + case IPPROTO_UDP: + plen = sizeof(udphdr_t); + break; + /* 96 - enough for complete ICMP error IP header */ + case IPPROTO_ICMP: + plen = ICMPERR_MAXPKTLEN - sizeof(ip_t); + break; + } + up = MIN(hlen + plen, ip->ip_len); + + if (up > m->m_len) { +# ifdef __sgi + /* Under IRIX, avoid m_pullup as it makes ping panic */ + if ((up > sizeof(hbuf)) || (m_length(m) < up)) { + ATOMIC_INCL(frstats[out].fr_pull[1]); + return -1; + } + m_copydata(m, 0, up, hbuf); + ATOMIC_INCL(frstats[out].fr_pull[0]); + ip = (ip_t *)hbuf; +# else /* __ sgi */ +# ifndef linux + if ((*mp = m_pullup(m, up)) == 0) { + ATOMIC_INCL(frstats[out].fr_pull[1]); + return -1; + } else { + ATOMIC_INCL(frstats[out].fr_pull[0]); + m = *mp; + ip = mtod(m, ip_t *); + } +# endif /* !linux */ +# endif /* __sgi */ + } else + up = 0; + } else + up = 0; +# endif /* !defined(__SVR4) && !defined(__svr4__) */ +# if SOLARIS + mb_t *m = qif->qf_m; + + if ((u_int)ip & 0x3) + return 2; + fin->fin_qfm = m; + fin->fin_qif = qif; +# endif +# ifdef USE_INET6 + if (v == 6) { + ATOMIC_INCL(frstats[0].fr_ipv6[out]); + } else +# endif + if (!out && fr_chksrc && !fr_verifysrc(ip->ip_src, ifp)) { + ATOMIC_INCL(frstats[0].fr_badsrc); +# if !SOLARIS + m_freem(m); +# endif + return error; + } +#endif /* _KERNEL */ + + /* + * Be careful here: ip_id is in network byte order when called + * from ip_output() + */ + if ((out) && (v == 4)) + ip->ip_id = ntohs(ip->ip_id); + + changed = 0; + fin->fin_v = v; + fin->fin_ifp = ifp; + fin->fin_out = out; + fin->fin_mp = mp; + fr_makefrip(hlen, ip, fin); + pass = fr_pass; + + if (fin->fin_fi.fi_fl & FI_SHORT) { + ATOMIC_INCL(frstats[out].fr_short); + } + + READ_ENTER(&ipf_mutex); + + if (fin->fin_fi.fi_fl & FI_SHORT) + ATOMIC_INCL(frstats[out].fr_short); + + /* + * Check auth now. This, combined with the check below to see if apass + * is 0 is to ensure that we don't count the packet twice, which can + * otherwise occur when we reprocess it. As it is, we only count it + * after it has no auth. table matchup. This also stops NAT from + * occuring until after the packet has been auth'd. + */ + apass = fr_checkauth(ip, fin); + + if (!out) { +#ifdef USE_INET6 + if (v == 6) + list = ipacct6[0][fr_active]; + else +#endif + list = ipacct[0][fr_active]; + changed = ip_natin(ip, fin); + if (!apass && (fin->fin_fr = list) && + (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { + ATOMIC_INCL(frstats[0].fr_acct); + } + } + + if (apass || (!(fr = ipfr_knownfrag(ip, fin)) && + !(fr = fr_checkstate(ip, fin)))) { + /* + * If a packet is found in the auth table, then skip checking + * the access lists for permission but we do need to consider + * the result as if it were from the ACL's. + */ + if (!apass) { + fc = frcache + out; + if (!bcmp((char *)fin, (char *)fc, FI_CSIZE)) { + /* + * copy cached data so we can unlock the mutex + * earlier. + */ + bcopy((char *)fc, (char *)fin, FI_COPYSIZE); + ATOMIC_INCL(frstats[out].fr_chit); + if ((fr = fin->fin_fr)) { + ATOMIC_INCL(fr->fr_hits); + pass = fr->fr_flags; + } + } else { +#ifdef USE_INET6 + if (v == 6) + list = ipfilter6[out][fr_active]; + else +#endif + list = ipfilter[out][fr_active]; + if ((fin->fin_fr = list)) + pass = fr_scanlist(fr_pass, ip, fin, m); + if (!(pass & (FR_KEEPSTATE|FR_DONTCACHE))) + bcopy((char *)fin, (char *)fc, + FI_COPYSIZE); + if (pass & FR_NOMATCH) { + ATOMIC_INCL(frstats[out].fr_nom); + } + } + fr = fin->fin_fr; + } else + pass = apass; + + /* + * If we fail to add a packet to the authorization queue, + * then we drop the packet later. However, if it was added + * then pretend we've dropped it already. + */ + if ((pass & FR_AUTH)) + if (fr_newauth((mb_t *)m, fin, ip) != 0) +#ifdef _KERNEL + m = *mp = NULL; +#else + ; +#endif + + if (pass & FR_PREAUTH) { + READ_ENTER(&ipf_auth); + if ((fin->fin_fr = ipauth) && + (pass = fr_scanlist(0, ip, fin, m))) { + ATOMIC_INCL(fr_authstats.fas_hits); + } else { + ATOMIC_INCL(fr_authstats.fas_miss); + } + RWLOCK_EXIT(&ipf_auth); + } + + fin->fin_fr = fr; + if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) { + if (fin->fin_fi.fi_fl & FI_FRAG) { + if (ipfr_newfrag(ip, fin, pass) == -1) { + ATOMIC_INCL(frstats[out].fr_bnfr); + } else { + ATOMIC_INCL(frstats[out].fr_nfr); + } + } else { + ATOMIC_INCL(frstats[out].fr_cfr); + } + } + if (pass & FR_KEEPSTATE) { + if (fr_addstate(ip, fin, 0) == NULL) { + ATOMIC_INCL(frstats[out].fr_bads); + } else { + ATOMIC_INCL(frstats[out].fr_ads); + } + } + } else if (fr != NULL) { + pass = fr->fr_flags; + if (pass & FR_LOGFIRST) + pass &= ~(FR_LOGFIRST|FR_LOG); + } + + if (fr && fr->fr_func && !(pass & FR_CALLNOW)) + pass = (*fr->fr_func)(pass, ip, fin); + + /* + * Only count/translate packets which will be passed on, out the + * interface. + */ + if (out && (pass & FR_PASS)) { +#ifdef USE_INET6 + if (v == 6) + list = ipacct6[0][fr_active]; + else +#endif + list = ipacct[0][fr_active]; + if ((fin->fin_fr = list) && + (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { + ATOMIC_INCL(frstats[1].fr_acct); + } + fin->fin_fr = fr; + changed = ip_natout(ip, fin); + } else + fin->fin_fr = fr; + RWLOCK_EXIT(&ipf_mutex); + +#ifdef IPFILTER_LOG + if ((fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) { + if ((fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) { + pass |= FF_LOGNOMATCH; + ATOMIC_INCL(frstats[out].fr_npkl); + goto logit; + } else if (((pass & FR_LOGMASK) == FR_LOGP) || + ((pass & FR_PASS) && (fr_flags & FF_LOGPASS))) { + if ((pass & FR_LOGMASK) != FR_LOGP) + pass |= FF_LOGPASS; + ATOMIC_INCL(frstats[out].fr_ppkl); + goto logit; + } else if (((pass & FR_LOGMASK) == FR_LOGB) || + ((pass & FR_BLOCK) && (fr_flags & FF_LOGBLOCK))) { + if ((pass & FR_LOGMASK) != FR_LOGB) + pass |= FF_LOGBLOCK; + ATOMIC_INCL(frstats[out].fr_bpkl); +logit: + if (!IPLLOG(pass, ip, fin, m)) { + ATOMIC_INCL(frstats[out].fr_skip); + if ((pass & (FR_PASS|FR_LOGORBLOCK)) == + (FR_PASS|FR_LOGORBLOCK)) + pass ^= FR_PASS|FR_BLOCK; + } + } + } +#endif /* IPFILTER_LOG */ + + if ((out) && (v == 4)) + ip->ip_id = htons(ip->ip_id); + +#ifdef _KERNEL + /* + * Only allow FR_DUP to work if a rule matched - it makes no sense to + * set FR_DUP as a "default" as there are no instructions about where + * to send the packet. + */ + if (fr && (pass & FR_DUP)) +# if SOLARIS + mc = dupmsg(m); +# else +# ifndef linux + mc = m_copy(m, 0, M_COPYALL); +# else + ; +# endif +# endif +#endif + if (pass & FR_PASS) { + ATOMIC_INCL(frstats[out].fr_pass); + } else if (pass & FR_BLOCK) { + ATOMIC_INCL(frstats[out].fr_block); + /* + * Should we return an ICMP packet to indicate error + * status passing through the packet filter ? + * WARNING: ICMP error packets AND TCP RST packets should + * ONLY be sent in repsonse to incoming packets. Sending them + * in response to outbound packets can result in a panic on + * some operating systems. + */ + if (!out) { +#ifdef _KERNEL + if (pass & FR_RETICMP) { + int dst; + + if ((pass & FR_RETMASK) == FR_FAKEICMP) + dst = 1; + else + dst = 0; + send_icmp_err(ip, ICMP_UNREACH, fin, dst); + ATOMIC_INCL(frstats[0].fr_ret); + } else if (((pass & FR_RETMASK) == FR_RETRST) && + !(fin->fin_fi.fi_fl & FI_SHORT)) { + if (send_reset(ip, fin) == 0) { + ATOMIC_INCL(frstats[1].fr_ret); + } + } +#else + if ((pass & FR_RETMASK) == FR_RETICMP) { + verbose("- ICMP unreachable sent\n"); + ATOMIC_INCL(frstats[0].fr_ret); + } else if ((pass & FR_RETMASK) == FR_FAKEICMP) { + verbose("- forged ICMP unreachable sent\n"); + ATOMIC_INCL(frstats[0].fr_ret); + } else if (((pass & FR_RETMASK) == FR_RETRST) && + !(fin->fin_fi.fi_fl & FI_SHORT)) { + verbose("- TCP RST sent\n"); + ATOMIC_INCL(frstats[1].fr_ret); + } +#endif + } else { + if (pass & FR_RETRST) + error = ECONNRESET; + } + } + + /* + * If we didn't drop off the bottom of the list of rules (and thus + * the 'current' rule fr is not NULL), then we may have some extra + * instructions about what to do with a packet. + * Once we're finished return to our caller, freeing the packet if + * we are dropping it (* BSD ONLY *). + */ + if ((changed == -1) && (pass & FR_PASS)) { + pass &= ~FR_PASS; + pass |= FR_BLOCK; + } +#if defined(_KERNEL) +# if !SOLARIS +# if !defined(linux) + if (fr) { + frdest_t *fdp = &fr->fr_tif; + + if (((pass & FR_FASTROUTE) && !out) || + (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) { + if (ipfr_fastroute(m, fin, fdp) == 0) + m = *mp = NULL; + } + if (mc) + ipfr_fastroute(mc, fin, &fr->fr_dif); + } + if (!(pass & FR_PASS) && m) + m_freem(m); +# ifdef __sgi + else if (changed && up && m) + m_copyback(m, 0, up, hbuf); +# endif +# endif /* !linux */ +# else /* !SOLARIS */ + if (fr) { + frdest_t *fdp = &fr->fr_tif; + + if (((pass & FR_FASTROUTE) && !out) || + (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) { + if (ipfr_fastroute(qif, ip, m, mp, fin, fdp) == 0) + m = *mp = NULL; + } + if (mc) + ipfr_fastroute(qif, ip, mc, mp, fin, &fr->fr_dif); + } +# endif /* !SOLARIS */ + return (pass & FR_PASS) ? 0 : error; +#else /* _KERNEL */ + if (pass & FR_NOMATCH) + return 1; + if (pass & FR_PASS) + return 0; + if (pass & FR_AUTH) + return -2; + return -1; +#endif /* _KERNEL */ +} + + +/* + * ipf_cksum + * addr should be 16bit aligned and len is in bytes. + * length is in bytes + */ +u_short ipf_cksum(addr, len) +register u_short *addr; +register int len; +{ + register u_32_t sum = 0; + + for (sum = 0; len > 1; len -= 2) + sum += *addr++; + + /* mop up an odd byte, if necessary */ + if (len == 1) + sum += *(u_char *)addr; + + /* + * add back carry outs from top 16 bits to low 16 bits + */ + sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ + sum += (sum >> 16); /* add carry */ + return (u_short)(~sum); +} + + +/* + * NB: This function assumes we've pullup'd enough for all of the IP header + * and the TCP header. We also assume that data blocks aren't allocated in + * odd sizes. + */ +u_short fr_tcpsum(m, ip, tcp) +mb_t *m; +ip_t *ip; +tcphdr_t *tcp; +{ + u_short *sp, slen, ts; + u_int sum, sum2; + int hlen; + + /* + * Add up IP Header portion + */ + hlen = ip->ip_hl << 2; + slen = ip->ip_len - hlen; + sum = htons((u_short)ip->ip_p); + sum += htons(slen); + sp = (u_short *)&ip->ip_src; + sum += *sp++; /* ip_src */ + sum += *sp++; + sum += *sp++; /* ip_dst */ + sum += *sp++; + ts = tcp->th_sum; + tcp->th_sum = 0; +#ifdef KERNEL +# if SOLARIS + sum2 = ip_cksum(m, hlen, sum); /* hlen == offset */ + sum2 = (sum2 & 0xffff) + (sum2 >> 16); + sum2 = ~sum2 & 0xffff; +# else /* SOLARIS */ +# if defined(BSD) || defined(sun) +# if BSD >= 199306 + m->m_data += hlen; +# else + m->m_off += hlen; +# endif + m->m_len -= hlen; + sum2 = in_cksum(m, slen); + m->m_len += hlen; +# if BSD >= 199306 + m->m_data -= hlen; +# else + m->m_off -= hlen; +# endif + /* + * Both sum and sum2 are partial sums, so combine them together. + */ + sum = (sum & 0xffff) + (sum >> 16); + sum = ~sum & 0xffff; + sum2 += sum; + sum2 = (sum2 & 0xffff) + (sum2 >> 16); +# else /* defined(BSD) || defined(sun) */ +{ + union { + u_char c[2]; + u_short s; + } bytes; + u_short len = ip->ip_len; +# if defined(__sgi) + int add; +# endif + + /* + * Add up IP Header portion + */ + sp = (u_short *)&ip->ip_src; + len -= (ip->ip_hl << 2); + sum = ntohs(IPPROTO_TCP); + sum += htons(len); + sum += *sp++; /* ip_src */ + sum += *sp++; + sum += *sp++; /* ip_dst */ + sum += *sp++; + if (sp != (u_short *)tcp) + sp = (u_short *)tcp; + sum += *sp++; /* sport */ + sum += *sp++; /* dport */ + sum += *sp++; /* seq */ + sum += *sp++; + sum += *sp++; /* ack */ + sum += *sp++; + sum += *sp++; /* off */ + sum += *sp++; /* win */ + sum += *sp++; /* Skip over checksum */ + sum += *sp++; /* urp */ + +# ifdef __sgi + /* + * In case we had to copy the IP & TCP header out of mbufs, + * skip over the mbuf bits which are the header + */ + if ((caddr_t)ip != mtod(m, caddr_t)) { + hlen = (caddr_t)sp - (caddr_t)ip; + while (hlen) { + add = MIN(hlen, m->m_len); + sp = (u_short *)(mtod(m, caddr_t) + add); + hlen -= add; + if (add == m->m_len) { + m = m->m_next; + if (!hlen) { + if (!m) + break; + sp = mtod(m, u_short *); + } + PANIC((!m),("fr_tcpsum(1): not enough data")); + } + } + } +# endif + + if (!(len -= sizeof(*tcp))) + goto nodata; + while (len > 1) { + if (((caddr_t)sp - mtod(m, caddr_t)) >= m->m_len) { + m = m->m_next; + PANIC((!m),("fr_tcpsum(2): not enough data")); + sp = mtod(m, u_short *); + } + if (((caddr_t)(sp + 1) - mtod(m, caddr_t)) > m->m_len) { + bytes.c[0] = *(u_char *)sp; + m = m->m_next; + PANIC((!m),("fr_tcpsum(3): not enough data")); + sp = mtod(m, u_short *); + bytes.c[1] = *(u_char *)sp; + sum += bytes.s; + sp = (u_short *)((u_char *)sp + 1); + } + if ((u_long)sp & 1) { + bcopy((char *)sp++, (char *)&bytes.s, sizeof(bytes.s)); + sum += bytes.s; + } else + sum += *sp++; + len -= 2; + } + if (len) + sum += ntohs(*(u_char *)sp << 8); +nodata: + while (sum > 0xffff) + sum = (sum & 0xffff) + (sum >> 16); + sum2 = (u_short)(~sum & 0xffff); +} +# endif /* defined(BSD) || defined(sun) */ +# endif /* SOLARIS */ +#else /* KERNEL */ + sum2 = 0; +#endif /* KERNEL */ + tcp->th_sum = ts; + return sum2; +} + + +#if defined(_KERNEL) && ( ((BSD < 199306) && !SOLARIS) || defined(__sgi) ) +/* + * Copyright (c) 1982, 1986, 1988, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 + * $Id: fil.c,v 2.35.2.8 2000/05/22 10:26:09 darrenr Exp $ + */ +/* + * Copy data from an mbuf chain starting "off" bytes from the beginning, + * continuing for "len" bytes, into the indicated buffer. + */ +void +m_copydata(m, off, len, cp) + register mb_t *m; + register int off; + register int len; + caddr_t cp; +{ + register unsigned count; + + if (off < 0 || len < 0) + panic("m_copydata"); + while (off > 0) { + if (m == 0) + panic("m_copydata"); + if (off < m->m_len) + break; + off -= m->m_len; + m = m->m_next; + } + while (len > 0) { + if (m == 0) + panic("m_copydata"); + count = MIN(m->m_len - off, len); + bcopy(mtod(m, caddr_t) + off, cp, count); + len -= count; + cp += count; + off = 0; + m = m->m_next; + } +} + + +# ifndef linux +/* + * Copy data from a buffer back into the indicated mbuf chain, + * starting "off" bytes from the beginning, extending the mbuf + * chain if necessary. + */ +void +m_copyback(m0, off, len, cp) + struct mbuf *m0; + register int off; + register int len; + caddr_t cp; +{ + register int mlen; + register struct mbuf *m = m0, *n; + int totlen = 0; + + if (m0 == 0) + return; + while (off > (mlen = m->m_len)) { + off -= mlen; + totlen += mlen; + if (m->m_next == 0) { + n = m_getclr(M_DONTWAIT, m->m_type); + if (n == 0) + goto out; + n->m_len = min(MLEN, len + off); + m->m_next = n; + } + m = m->m_next; + } + while (len > 0) { + mlen = min (m->m_len - off, len); + bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); + cp += mlen; + len -= mlen; + mlen += off; + off = 0; + totlen += mlen; + if (len == 0) + break; + if (m->m_next == 0) { + n = m_get(M_DONTWAIT, m->m_type); + if (n == 0) + break; + n->m_len = min(MLEN, len); + m->m_next = n; + } + m = m->m_next; + } +out: +#if 0 + if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) + m->m_pkthdr.len = totlen; +#endif + return; +} +# endif /* linux */ +#endif /* (_KERNEL) && ( ((BSD < 199306) && !SOLARIS) || __sgi) */ + + +frgroup_t *fr_findgroup(num, flags, which, set, fgpp) +u_32_t num, flags; +minor_t which; +int set; +frgroup_t ***fgpp; +{ + frgroup_t *fg, **fgp; + + if (which == IPL_LOGAUTH) + fgp = &ipfgroups[2][set]; + else if (flags & FR_ACCOUNT) + fgp = &ipfgroups[1][set]; + else if (flags & (FR_OUTQUE|FR_INQUE)) + fgp = &ipfgroups[0][set]; + else + return NULL; + num &= 0xffff; + + while ((fg = *fgp)) + if (fg->fg_num == num) + break; + else + fgp = &fg->fg_next; + if (fgpp) + *fgpp = fgp; + return fg; +} + + +frgroup_t *fr_addgroup(num, fp, which, set) +u_32_t num; +frentry_t *fp; +minor_t which; +int set; +{ + frgroup_t *fg, **fgp; + + if ((fg = fr_findgroup(num, fp->fr_flags, which, set, &fgp))) + return fg; + + KMALLOC(fg, frgroup_t *); + if (fg) { + fg->fg_num = num; + fg->fg_next = *fgp; + fg->fg_head = fp; + fg->fg_start = &fp->fr_grp; + *fgp = fg; + } + return fg; +} + + +void fr_delgroup(num, flags, which, set) +u_32_t num, flags; +minor_t which; +int set; +{ + frgroup_t *fg, **fgp; + + if (!(fg = fr_findgroup(num, flags, which, set, &fgp))) + return; + + *fgp = fg->fg_next; + KFREE(fg); +} + + + +/* + * recursively flush rules from the list, descending groups as they are + * encountered. if a rule is the head of a group and it has lost all its + * group members, then also delete the group reference. + */ +static int frflushlist(set, unit, nfreedp, listp) +int set; +minor_t unit; +int *nfreedp; +frentry_t **listp; +{ + register int freed = 0, i; + register frentry_t *fp; + + while ((fp = *listp)) { + *listp = fp->fr_next; + if (fp->fr_grp) { + i = frflushlist(set, unit, nfreedp, &fp->fr_grp); + MUTEX_ENTER(&ipf_rw); + fp->fr_ref -= i; + MUTEX_EXIT(&ipf_rw); + } + + ATOMIC_DEC32(fp->fr_ref); + if (fp->fr_grhead) { + fr_delgroup(fp->fr_grhead, fp->fr_flags, + unit, set); + fp->fr_grhead = 0; + } + if (fp->fr_ref == 0) { + KFREE(fp); + freed++; + } else + fp->fr_next = NULL; + } + *nfreedp += freed; + return freed; +} + + +int frflush(unit, flags) +minor_t unit; +int flags; +{ + int flushed = 0, set; + + if (unit != IPL_LOGIPF) + return 0; + WRITE_ENTER(&ipf_mutex); + bzero((char *)frcache, sizeof(frcache[0]) * 2); + + set = fr_active; + if (flags & FR_INACTIVE) + set = 1 - set; + + if (flags & FR_OUTQUE) { +#ifdef USE_INET6 + (void) frflushlist(set, unit, &flushed, &ipfilter6[1][set]); + (void) frflushlist(set, unit, &flushed, &ipacct6[1][set]); +#endif + (void) frflushlist(set, unit, &flushed, &ipfilter[1][set]); + (void) frflushlist(set, unit, &flushed, &ipacct[1][set]); + } + if (flags & FR_INQUE) { +#ifdef USE_INET6 + (void) frflushlist(set, unit, &flushed, &ipfilter6[0][set]); + (void) frflushlist(set, unit, &flushed, &ipacct6[0][set]); +#endif + (void) frflushlist(set, unit, &flushed, &ipfilter[0][set]); + (void) frflushlist(set, unit, &flushed, &ipacct[0][set]); + } + RWLOCK_EXIT(&ipf_mutex); + return flushed; +} + + +char *memstr(src, dst, slen, dlen) +char *src, *dst; +int slen, dlen; +{ + char *s = NULL; + + while (dlen >= slen) { + if (bcmp(src, dst, slen) == 0) { + s = dst; + break; + } + dst++; + dlen--; + } + return s; +} + + +void fixskip(listp, rp, addremove) +frentry_t **listp, *rp; +int addremove; +{ + frentry_t *fp; + int rules = 0, rn = 0; + + for (fp = *listp; fp && (fp != rp); fp = fp->fr_next, rules++) + ; + + if (!fp) + return; + + for (fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++) + if (fp->fr_skip && (rn + fp->fr_skip >= rules)) + fp->fr_skip += addremove; +} + + +#ifdef _KERNEL +/* + * count consecutive 1's in bit mask. If the mask generated by counting + * consecutive 1's is different to that passed, return -1, else return # + * of bits. + */ +int countbits(ip) +u_32_t ip; +{ + u_32_t ipn; + int cnt = 0, i, j; + + ip = ipn = ntohl(ip); + for (i = 32; i; i--, ipn *= 2) + if (ipn & 0x80000000) + cnt++; + else + break; + ipn = 0; + for (i = 32, j = cnt; i; i--, j--) { + ipn *= 2; + if (j > 0) + ipn++; + } + if (ipn == ip) + return cnt; + return -1; +} + + +/* + * return the first IP Address associated with an interface + */ +int fr_ifpaddr(v, ifptr, inp) +int v; +void *ifptr; +struct in_addr *inp; +{ +# ifdef USE_INET6 + struct in6_addr *inp6 = NULL; +# endif +# if SOLARIS + ill_t *ill = ifptr; +# else + struct ifnet *ifp = ifptr; +# endif + struct in_addr in; + +# if SOLARIS +# ifdef USE_INET6 + if (v == 6) { + struct in6_addr in6; + + /* + * First is always link local. + */ + if (ill->ill_ipif->ipif_next) + in6 = ill->ill_ipif->ipif_next->ipif_v6lcl_addr; + else + bzero((char *)&in6, sizeof(in6)); + bcopy((char *)&in6, (char *)inp, sizeof(in6)); + } else +# endif + { + in.s_addr = ill->ill_ipif->ipif_local_addr; + *inp = in; + } +# else /* SOLARIS */ +# if linux + ; +# else /* linux */ + struct sockaddr_in *sin; + struct ifaddr *ifa; + +# if (__FreeBSD_version >= 300000) + ifa = TAILQ_FIRST(&ifp->if_addrhead); +# else +# if defined(__NetBSD__) || defined(__OpenBSD__) + ifa = ifp->if_addrlist.tqh_first; +# else +# if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */ + ifa = &((struct in_ifaddr *)ifp->in_ifaddr)->ia_ifa; +# else + ifa = ifp->if_addrlist; +# endif +# endif /* __NetBSD__ || __OpenBSD__ */ +# endif /* __FreeBSD_version >= 300000 */ +# if (BSD < 199306) && !(/*IRIX6*/defined(__sgi) && defined(IFF_DRVRLOCK)) + sin = (struct sockaddr_in *)&ifa->ifa_addr; +# else + sin = (struct sockaddr_in *)ifa->ifa_addr; + while (sin && ifa) { + if ((v == 4) && (sin->sin_family == AF_INET)) + break; +# ifdef USE_INET6 + if ((v == 6) && (sin->sin_family == AF_INET6)) { + inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr; + if (!IN6_IS_ADDR_LINKLOCAL(inp6) && + !IN6_IS_ADDR_LOOPBACK(inp6)) + break; + } +# endif +# if (__FreeBSD_version >= 300000) + ifa = TAILQ_NEXT(ifa, ifa_link); +# else +# if defined(__NetBSD__) || defined(__OpenBSD__) + ifa = ifa->ifa_list.tqe_next; +# else + ifa = ifa->ifa_next; +# endif +# endif /* __FreeBSD_version >= 300000 */ + if (ifa) + sin = (struct sockaddr_in *)ifa->ifa_addr; + } + if (ifa == NULL) + sin = NULL; + if (sin == NULL) + return -1; +# endif /* (BSD < 199306) && (!__sgi && IFF_DRVLOCK) */ +# ifdef USE_INET6 + if (v == 6) + bcopy((char *)inp6, (char *)inp, sizeof(*inp6)); + else +# endif + { + in = sin->sin_addr; + *inp = in; + } +# endif /* linux */ +# endif /* SOLARIS */ + return 0; +} + + +static void frsynclist(fr) +register frentry_t *fr; +{ + for (; fr; fr = fr->fr_next) { + if (fr->fr_ifa != NULL) { + fr->fr_ifa = GETUNIT(fr->fr_ifname, fr->fr_ip.fi_v); + if (fr->fr_ifa == NULL) + fr->fr_ifa = (void *)-1; + } + if (fr->fr_grp) + frsynclist(fr->fr_grp); + } +} + + +void frsync() +{ +# if !SOLARIS + register struct ifnet *ifp; + +# if defined(__OpenBSD__) || ((NetBSD >= 199511) && (NetBSD < 1991011)) || \ + (defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)) +# if (NetBSD >= 199905) || defined(__OpenBSD__) + for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) +# else + for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) +# endif +# else + for (ifp = ifnet; ifp; ifp = ifp->if_next) +# endif + { + ip_natsync(ifp); + ip_statesync(ifp); + } +# endif + + WRITE_ENTER(&ipf_mutex); + frsynclist(ipacct[0][fr_active]); + frsynclist(ipacct[1][fr_active]); + frsynclist(ipfilter[0][fr_active]); + frsynclist(ipfilter[1][fr_active]); +#ifdef USE_INET6 + frsynclist(ipacct6[0][fr_active]); + frsynclist(ipacct6[1][fr_active]); + frsynclist(ipfilter6[0][fr_active]); + frsynclist(ipfilter6[1][fr_active]); +#endif + RWLOCK_EXIT(&ipf_mutex); +} + + +/* + * In the functions below, bcopy() is called because the pointer being + * copied _from_ in this instance is a pointer to a char buf (which could + * end up being unaligned) and on the kernel's local stack. + */ +int ircopyptr(a, b, c) +void *a, *b; +size_t c; +{ + caddr_t ca; + int err; + +#if SOLARIS + copyin(a, &ca, sizeof(ca)); +#else + bcopy(a, &ca, sizeof(ca)); +#endif + err = copyin(ca, b, c); + return err; +} + + +int iwcopyptr(a, b, c) +void *a, *b; +size_t c; +{ + caddr_t ca; + int err; + +#if SOLARIS + copyin(b, &ca, sizeof(ca)); +#else + bcopy(b, &ca, sizeof(ca)); +#endif + err = copyout(a, ca, c); + return err; +} + +#else /* _KERNEL */ + + +/* + * return the first IP Address associated with an interface + */ +int fr_ifpaddr(v, ifptr, inp) +int v; +void *ifptr; +struct in_addr *inp; +{ + return 0; +} + + +int ircopyptr(a, b, c) +void *a, *b; +size_t c; +{ + caddr_t ca; + + bcopy(a, &ca, sizeof(ca)); + bcopy(ca, b, c); + return 0; +} + + +int iwcopyptr(a, b, c) +void *a, *b; +size_t c; +{ + caddr_t ca; + + bcopy(b, &ca, sizeof(ca)); + bcopy(a, ca, c); + return 0; +} + + +#endif + + +int fr_lock(data, lockp) +caddr_t data; +int *lockp; +{ + int arg, error; + + error = IRCOPY(data, (caddr_t)&arg, sizeof(arg)); + if (!error) { + error = IWCOPY((caddr_t)lockp, data, sizeof(*lockp)); + if (!error) + *lockp = arg; + } + return error; +} + + +void fr_getstat(fiop) +friostat_t *fiop; +{ + bcopy((char *)frstats, (char *)fiop->f_st, sizeof(filterstats_t) * 2); + fiop->f_locks[0] = fr_state_lock; + fiop->f_locks[1] = fr_nat_lock; + fiop->f_locks[2] = fr_frag_lock; + fiop->f_locks[3] = fr_auth_lock; + fiop->f_fin[0] = ipfilter[0][0]; + fiop->f_fin[1] = ipfilter[0][1]; + fiop->f_fout[0] = ipfilter[1][0]; + fiop->f_fout[1] = ipfilter[1][1]; + fiop->f_acctin[0] = ipacct[0][0]; + fiop->f_acctin[1] = ipacct[0][1]; + fiop->f_acctout[0] = ipacct[1][0]; + fiop->f_acctout[1] = ipacct[1][1]; +#ifdef USE_INET6 + fiop->f_fin6[0] = ipfilter6[0][0]; + fiop->f_fin6[1] = ipfilter6[0][1]; + fiop->f_fout6[0] = ipfilter6[1][0]; + fiop->f_fout6[1] = ipfilter6[1][1]; + fiop->f_acctin6[0] = ipacct6[0][0]; + fiop->f_acctin6[1] = ipacct6[0][1]; + fiop->f_acctout6[0] = ipacct6[1][0]; + fiop->f_acctout6[1] = ipacct6[1][1]; +#endif + fiop->f_active = fr_active; + fiop->f_froute[0] = ipl_frouteok[0]; + fiop->f_froute[1] = ipl_frouteok[1]; + + fiop->f_running = fr_running; + fiop->f_groups[0][0] = ipfgroups[0][0]; + fiop->f_groups[0][1] = ipfgroups[0][1]; + fiop->f_groups[1][0] = ipfgroups[1][0]; + fiop->f_groups[1][1] = ipfgroups[1][1]; + fiop->f_groups[2][0] = ipfgroups[2][0]; + fiop->f_groups[2][1] = ipfgroups[2][1]; +#ifdef IPFILTER_LOG + fiop->f_logging = 1; +#else + fiop->f_logging = 0; +#endif + fiop->f_defpass = fr_pass; + strncpy(fiop->f_version, ipfilter_version, sizeof(fiop->f_version)); +} + + +#ifdef USE_INET6 +int icmptoicmp6types[ICMP_MAXTYPE+1] = { + ICMP6_ECHO_REPLY, /* 0: ICMP_ECHOREPLY */ + -1, /* 1: UNUSED */ + -1, /* 2: UNUSED */ + ICMP6_DST_UNREACH, /* 3: ICMP_UNREACH */ + -1, /* 4: ICMP_SOURCEQUENCH */ + ND_REDIRECT, /* 5: ICMP_REDIRECT */ + -1, /* 6: UNUSED */ + -1, /* 7: UNUSED */ + ICMP6_ECHO_REQUEST, /* 8: ICMP_ECHO */ + -1, /* 9: UNUSED */ + -1, /* 10: UNUSED */ + ICMP6_TIME_EXCEEDED, /* 11: ICMP_TIMXCEED */ + ICMP6_PARAM_PROB, /* 12: ICMP_PARAMPROB */ + -1, /* 13: ICMP_TSTAMP */ + -1, /* 14: ICMP_TSTAMPREPLY */ + -1, /* 15: ICMP_IREQ */ + -1, /* 16: ICMP_IREQREPLY */ + -1, /* 17: ICMP_MASKREQ */ + -1, /* 18: ICMP_MASKREPLY */ +}; + + +int icmptoicmp6unreach[ICMP_MAX_UNREACH] = { + ICMP6_DST_UNREACH_ADDR, /* 0: ICMP_UNREACH_NET */ + ICMP6_DST_UNREACH_ADDR, /* 1: ICMP_UNREACH_HOST */ + -1, /* 2: ICMP_UNREACH_PROTOCOL */ + ICMP6_DST_UNREACH_NOPORT, /* 3: ICMP_UNREACH_PORT */ + -1, /* 4: ICMP_UNREACH_NEEDFRAG */ + ICMP6_DST_UNREACH_NOTNEIGHBOR, /* 5: ICMP_UNREACH_SRCFAIL */ + ICMP6_DST_UNREACH_ADDR, /* 6: ICMP_UNREACH_NET_UNKNOWN */ + ICMP6_DST_UNREACH_ADDR, /* 7: ICMP_UNREACH_HOST_UNKNOWN */ + -1, /* 8: ICMP_UNREACH_ISOLATED */ + ICMP6_DST_UNREACH_ADMIN, /* 9: ICMP_UNREACH_NET_PROHIB */ + ICMP6_DST_UNREACH_ADMIN, /* 10: ICMP_UNREACH_HOST_PROHIB */ + -1, /* 11: ICMP_UNREACH_TOSNET */ + -1, /* 12: ICMP_UNREACH_TOSHOST */ + ICMP6_DST_UNREACH_ADMIN, /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */ +}; +#endif Property changes on: vendor-sys/ipfilter/v3_4_4/sys/netinet/fil.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_auth.c =================================================================== --- vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_auth.c (nonexistent) +++ vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_auth.c (revision 60849) @@ -0,0 +1,550 @@ +/* + * Copyright (C) 1998-2000 by Darren Reed & Guido van Rooij. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and due credit is given + * to the original author and the contributors. + */ +#if !defined(lint) +static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.11.2.2 2000/05/22 10:26:11 darrenr Exp $"; +#endif + +#include +#include +#include +#include +#include +#if !defined(_KERNEL) && !defined(KERNEL) +# include +# include +# include +#endif +#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) +# include +# include +#else +# include +#endif +#include +#ifndef linux +# include +#endif +#include +#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux) +# include +#endif +#if !defined(__SVR4) && !defined(__svr4__) +# ifndef linux +# include +# endif +#else +# include +# include +# ifdef _KERNEL +# include +# endif +# include +# include +#endif +#if _BSDI_VERSION >= 199802 +# include +#endif +#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) +# include +#endif +#include +#ifdef sun +# include +#endif +#include +#include +#include +#include +#ifndef KERNEL +# define KERNEL +# define NOT_KERNEL +#endif +#ifndef linux +# include +#endif +#ifdef NOT_KERNEL +# undef KERNEL +#endif +#ifdef __sgi +# ifdef IFF_DRVRLOCK /* IRIX6 */ +# include +# endif +#endif +#include +#if defined(__sgi) && !defined(IFF_DRVRLOCK) /* IRIX < 6 */ +extern struct ifqueue ipintrq; /* ip packet input queue */ +#else +# ifndef linux +# if __FreeBSD_version >= 300000 +# include +# endif +# include +# include +# endif +#endif +#include +#include +#include "netinet/ip_compat.h" +#include +#include "netinet/ip_fil.h" +#include "netinet/ip_auth.h" +#if !SOLARIS && !defined(linux) +# include +# ifdef __FreeBSD__ +# include +# endif +#endif +#if (__FreeBSD_version >= 300000) +# include +# if (defined(_KERNEL) || defined(KERNEL)) && !defined(IPFILTER_LKM) +# include +# include +# endif +#endif + + + +#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) +extern KRWLOCK_T ipf_auth; +extern kmutex_t ipf_authmx; +# if SOLARIS +extern kcondvar_t ipfauthwait; +# endif +#endif +#ifdef linux +static struct wait_queue *ipfauthwait = NULL; +#endif + +int fr_authsize = FR_NUMAUTH; +int fr_authused = 0; +int fr_defaultauthage = 600; +int fr_auth_lock = 0; +fr_authstat_t fr_authstats; +static frauth_t fr_auth[FR_NUMAUTH]; +mb_t *fr_authpkts[FR_NUMAUTH]; +static int fr_authstart = 0, fr_authend = 0, fr_authnext = 0; +static frauthent_t *fae_list = NULL; +frentry_t *ipauth = NULL; + + +/* + * Check if a packet has authorization. If the packet is found to match an + * authorization result and that would result in a feedback loop (i.e. it + * will end up returning FR_AUTH) then return FR_BLOCK instead. + */ +u_32_t fr_checkauth(ip, fin) +ip_t *ip; +fr_info_t *fin; +{ + u_short id = ip->ip_id; + u_32_t pass; + int i; + + if (fr_auth_lock) + return 0; + + READ_ENTER(&ipf_auth); + for (i = fr_authstart; i != fr_authend; ) { + /* + * index becomes -2 only after an SIOCAUTHW. Check this in + * case the same packet gets sent again and it hasn't yet been + * auth'd. + */ + if ((fr_auth[i].fra_index == -2) && + (id == fr_auth[i].fra_info.fin_id) && + !bcmp((char *)fin,(char *)&fr_auth[i].fra_info,FI_CSIZE)) { + /* + * Avoid feedback loop. + */ + if (!(pass = fr_auth[i].fra_pass) || (pass & FR_AUTH)) + pass = FR_BLOCK; + RWLOCK_EXIT(&ipf_auth); + WRITE_ENTER(&ipf_auth); + fr_authstats.fas_hits++; + fr_auth[i].fra_index = -1; + fr_authused--; + if (i == fr_authstart) { + while (fr_auth[i].fra_index == -1) { + i++; + if (i == FR_NUMAUTH) + i = 0; + fr_authstart = i; + if (i == fr_authend) + break; + } + if (fr_authstart == fr_authend) { + fr_authnext = 0; + fr_authstart = fr_authend = 0; + } + } + RWLOCK_EXIT(&ipf_auth); + return pass; + } + i++; + if (i == FR_NUMAUTH) + i = 0; + } + fr_authstats.fas_miss++; + RWLOCK_EXIT(&ipf_auth); + return 0; +} + + +/* + * Check if we have room in the auth array to hold details for another packet. + * If we do, store it and wake up any user programs which are waiting to + * hear about these events. + */ +int fr_newauth(m, fin, ip) +mb_t *m; +fr_info_t *fin; +ip_t *ip; +{ +#if defined(_KERNEL) && SOLARIS + qif_t *qif = fin->fin_qif; +#endif + int i; + + if (fr_auth_lock) + return 0; + + WRITE_ENTER(&ipf_auth); + if (fr_authstart > fr_authend) { + fr_authstats.fas_nospace++; + RWLOCK_EXIT(&ipf_auth); + return 0; + } else { + if ((fr_authstart == 0) && (fr_authend == FR_NUMAUTH - 1)) { + fr_authstats.fas_nospace++; + RWLOCK_EXIT(&ipf_auth); + return 0; + } + } + + fr_authstats.fas_added++; + fr_authused++; + i = fr_authend++; + if (fr_authend == FR_NUMAUTH) + fr_authend = 0; + RWLOCK_EXIT(&ipf_auth); + fr_auth[i].fra_index = i; + fr_auth[i].fra_pass = 0; + fr_auth[i].fra_age = fr_defaultauthage; + bcopy((char *)fin, (char *)&fr_auth[i].fra_info, sizeof(*fin)); +#if !defined(sparc) && !defined(m68k) + /* + * No need to copyback here as we want to undo the changes, not keep + * them. + */ +# if SOLARIS && defined(_KERNEL) + if ((ip == (ip_t *)m->b_rptr) && (ip->ip_v == 4)) +# endif + { + register u_short bo; + + bo = ip->ip_len; + ip->ip_len = htons(bo); +# if !SOLARIS && !defined(__NetBSD__) + /* 4.4BSD converts this ip_input.c, but I don't in solaris.c */ + bo = ip->ip_id; + ip->ip_id = htons(bo); +# endif + bo = ip->ip_off; + ip->ip_off = htons(bo); + } +#endif +#if SOLARIS && defined(_KERNEL) + m->b_rptr -= qif->qf_off; + fr_authpkts[i] = *(mblk_t **)fin->fin_mp; + fr_auth[i].fra_q = qif->qf_q; + cv_signal(&ipfauthwait); +#else + fr_authpkts[i] = m; +# if defined(linux) && defined(_KERNEL) + wake_up_interruptible(&ipfauthwait); +# else + WAKEUP(&fr_authnext); +# endif +#endif + return 1; +} + + +int fr_auth_ioctl(data, cmd, fr, frptr) +caddr_t data; +#if defined(__NetBSD__) || defined(__OpenBSD__) || (FreeBSD_version >= 300003) +u_long cmd; +#else +int cmd; +#endif +frentry_t *fr, **frptr; +{ + mb_t *m; +#if defined(_KERNEL) && !SOLARIS + struct ifqueue *ifq; +#endif + frauth_t auth, *au = &auth; + frauthent_t *fae, **faep; + int i, error = 0; + + switch (cmd) + { + case SIOCSTLCK : + error = fr_lock(data, &fr_auth_lock); + break; + case SIOCINIFR : + case SIOCRMIFR : + case SIOCADIFR : + error = EINVAL; + break; + case SIOCINAFR : + error = EINVAL; + break; + case SIOCRMAFR : + case SIOCADAFR : + for (faep = &fae_list; (fae = *faep); ) + if (&fae->fae_fr == fr) + break; + else + faep = &fae->fae_next; + if (cmd == SIOCRMAFR) { + if (!fae) + error = ESRCH; + else { + WRITE_ENTER(&ipf_auth); + *faep = fae->fae_next; + *frptr = fr->fr_next; + RWLOCK_EXIT(&ipf_auth); + KFREE(fae); + } + } else { + KMALLOC(fae, frauthent_t *); + if (fae != NULL) { + bcopy((char *)fr, (char *)&fae->fae_fr, + sizeof(*fr)); + WRITE_ENTER(&ipf_auth); + fae->fae_age = fr_defaultauthage; + fae->fae_fr.fr_hits = 0; + fae->fae_fr.fr_next = *frptr; + *frptr = &fae->fae_fr; + fae->fae_next = *faep; + *faep = fae; + ipauth = &fae_list->fae_fr; + RWLOCK_EXIT(&ipf_auth); + } else + error = ENOMEM; + } + break; + case SIOCATHST: + READ_ENTER(&ipf_auth); + fr_authstats.fas_faelist = fae_list; + RWLOCK_EXIT(&ipf_auth); + error = IWCOPYPTR((char *)&fr_authstats, data, + sizeof(fr_authstats)); + break; + case SIOCAUTHW: +fr_authioctlloop: + READ_ENTER(&ipf_auth); + if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) { + error = IWCOPYPTR((char *)&fr_auth[fr_authnext], data, + sizeof(fr_info_t)); + RWLOCK_EXIT(&ipf_auth); + if (error) + break; + WRITE_ENTER(&ipf_auth); + fr_authnext++; + if (fr_authnext == FR_NUMAUTH) + fr_authnext = 0; + RWLOCK_EXIT(&ipf_auth); + return 0; + } +#ifdef _KERNEL +# if SOLARIS + mutex_enter(&ipf_authmx); + if (!cv_wait_sig(&ipfauthwait, &ipf_authmx)) { + mutex_exit(&ipf_authmx); + return EINTR; + } + mutex_exit(&ipf_authmx); +# else +# ifdef linux + interruptible_sleep_on(&ipfauthwait); + if (current->signal & ~current->blocked) + error = -EINTR; +# else + error = SLEEP(&fr_authnext, "fr_authnext"); +# endif +# endif +#endif + RWLOCK_EXIT(&ipf_auth); + if (!error) + goto fr_authioctlloop; + break; + case SIOCAUTHR: + error = IRCOPYPTR(data, (caddr_t)&auth, sizeof(auth)); + if (error) + return error; + WRITE_ENTER(&ipf_auth); + i = au->fra_index; + if ((i < 0) || (i > FR_NUMAUTH) || + (fr_auth[i].fra_info.fin_id != au->fra_info.fin_id)) { + RWLOCK_EXIT(&ipf_auth); + return EINVAL; + } + m = fr_authpkts[i]; + fr_auth[i].fra_index = -2; + fr_auth[i].fra_pass = au->fra_pass; + fr_authpkts[i] = NULL; +#ifdef _KERNEL + RWLOCK_EXIT(&ipf_auth); +# ifndef linux + if (m && au->fra_info.fin_out) { +# if SOLARIS + error = fr_qout(fr_auth[i].fra_q, m); +# else /* SOLARIS */ +# if (_BSDI_VERSION >= 199802) || defined(__OpenBSD__) + error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, + NULL); +# else + error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL); +# endif +# endif /* SOLARIS */ + if (error) + fr_authstats.fas_sendfail++; + else + fr_authstats.fas_sendok++; + } else if (m) { +# if SOLARIS + error = fr_qin(fr_auth[i].fra_q, m); +# else /* SOLARIS */ + ifq = &ipintrq; + if (IF_QFULL(ifq)) { + IF_DROP(ifq); + m_freem(m); + error = ENOBUFS; + } else { + IF_ENQUEUE(ifq, m); + schednetisr(NETISR_IP); + } +# endif /* SOLARIS */ + if (error) + fr_authstats.fas_quefail++; + else + fr_authstats.fas_queok++; + } else + error = EINVAL; +# endif +# if SOLARIS + if (error) + error = EINVAL; +# else + /* + * If we experience an error which will result in the packet + * not being processed, make sure we advance to the next one. + */ + if (error == ENOBUFS) { + fr_authused--; + fr_auth[i].fra_index = -1; + fr_auth[i].fra_pass = 0; + if (i == fr_authstart) { + while (fr_auth[i].fra_index == -1) { + i++; + if (i == FR_NUMAUTH) + i = 0; + fr_authstart = i; + if (i == fr_authend) + break; + } + if (fr_authstart == fr_authend) { + fr_authnext = 0; + fr_authstart = fr_authend = 0; + } + } + } +# endif +#endif /* _KERNEL */ + break; + default : + error = EINVAL; + break; + } + return error; +} + + +#ifdef _KERNEL +/* + * Free all network buffer memory used to keep saved packets. + */ +void fr_authunload() +{ + register int i; + register frauthent_t *fae, **faep; + mb_t *m; + + WRITE_ENTER(&ipf_auth); + for (i = 0; i < FR_NUMAUTH; i++) { + if ((m = fr_authpkts[i])) { + FREE_MB_T(m); + fr_authpkts[i] = NULL; + fr_auth[i].fra_index = -1; + } + } + + + for (faep = &fae_list; (fae = *faep); ) { + *faep = fae->fae_next; + KFREE(fae); + } + ipauth = NULL; + RWLOCK_EXIT(&ipf_auth); +} + + +/* + * Slowly expire held auth records. Timeouts are set + * in expectation of this being called twice per second. + */ +void fr_authexpire() +{ + register int i; + register frauth_t *fra; + register frauthent_t *fae, **faep; + mb_t *m; +#if !SOLARIS + int s; +#endif + + if (fr_auth_lock) + return; + + SPL_NET(s); + WRITE_ENTER(&ipf_auth); + for (i = 0, fra = fr_auth; i < FR_NUMAUTH; i++, fra++) { + if ((!--fra->fra_age) && (m = fr_authpkts[i])) { + FREE_MB_T(m); + fr_authpkts[i] = NULL; + fr_auth[i].fra_index = -1; + fr_authstats.fas_expire++; + fr_authused--; + } + } + + for (faep = &fae_list; (fae = *faep); ) { + if (!--fae->fae_age) { + *faep = fae->fae_next; + KFREE(fae); + fr_authstats.fas_expire++; + } else + faep = &fae->fae_next; + } + ipauth = &fae_list->fae_fr; + RWLOCK_EXIT(&ipf_auth); + SPL_X(s); +} +#endif Property changes on: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_auth.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_auth.h =================================================================== --- vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_auth.h (nonexistent) +++ vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_auth.h (revision 60849) @@ -0,0 +1,64 @@ +/* + * Copyright (C) 1997-2000 by Darren Reed & Guido Van Rooij. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and due credit is given + * to the original author and the contributors. + * + * $Id: ip_auth.h,v 2.3.2.1 2000/05/22 10:26:11 darrenr Exp $ + * + */ +#ifndef __IP_AUTH_H__ +#define __IP_AUTH_H__ + +#define FR_NUMAUTH 32 + +typedef struct frauth { + int fra_age; + int fra_index; + u_32_t fra_pass; + fr_info_t fra_info; +#if SOLARIS + queue_t *fra_q; +#endif +} frauth_t; + +typedef struct frauthent { + struct frentry fae_fr; + struct frauthent *fae_next; + u_long fae_age; +} frauthent_t; + +typedef struct fr_authstat { + U_QUAD_T fas_hits; + U_QUAD_T fas_miss; + u_long fas_nospace; + u_long fas_added; + u_long fas_sendfail; + u_long fas_sendok; + u_long fas_queok; + u_long fas_quefail; + u_long fas_expire; + frauthent_t *fas_faelist; +} fr_authstat_t; + + +extern frentry_t *ipauth; +extern struct fr_authstat fr_authstats; +extern int fr_defaultauthage; +extern int fr_authstart; +extern int fr_authend; +extern int fr_authsize; +extern int fr_authused; +extern int fr_auth_lock; +extern u_32_t fr_checkauth __P((ip_t *, fr_info_t *)); +extern void fr_authexpire __P((void)); +extern void fr_authunload __P((void)); +extern mb_t *fr_authpkts[]; +extern int fr_newauth __P((mb_t *, fr_info_t *, ip_t *)); +#if defined(__NetBSD__) || defined(__OpenBSD__) +extern int fr_auth_ioctl __P((caddr_t, u_long, frentry_t *, frentry_t **)); +#else +extern int fr_auth_ioctl __P((caddr_t, int, frentry_t *, frentry_t **)); +#endif +#endif /* __IP_AUTH_H__ */ Property changes on: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_auth.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_compat.h =================================================================== --- vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_compat.h (nonexistent) +++ vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_compat.h (revision 60849) @@ -0,0 +1,986 @@ +/* + * 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. + * + * @(#)ip_compat.h 1.8 1/14/96 + * $Id: ip_compat.h,v 2.26.2.3 2000/04/28 14:56:49 darrenr Exp $ + */ + +#ifndef __IP_COMPAT_H__ +#define __IP_COMPAT_H__ + +#ifndef __P +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif +#ifndef __STDC__ +# undef const +# define const +#endif + +#ifndef SOLARIS +#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +#endif +#if SOLARIS2 >= 8 +# ifndef USE_INET6 +# define USE_INET6 +# endif +#endif + +#if defined(_KERNEL) || defined(KERNEL) || defined(__KERNEL__) +# undef KERNEL +# undef _KERNEL +# undef __KERNEL__ +# define KERNEL +# define _KERNEL +# define __KERNEL__ +#endif + +#if defined(__SVR4) || defined(__svr4__) || defined(__sgi) +#define index strchr +# if !defined(KERNEL) +# define bzero(a,b) memset(a,0,b) +# define bcmp memcmp +# define bcopy(a,b,c) memmove(b,a,c) +# endif +#endif + +#ifndef offsetof +#define offsetof(t,m) (int)((&((t *)0L)->m)) +#endif + +#if defined(__sgi) || defined(bsdi) +struct ether_addr { + u_char ether_addr_octet[6]; +}; +#endif + +#if defined(__sgi) && !defined(IPFILTER_LKM) +# ifdef __STDC__ +# define IPL_EXTERN(ep) ipfilter##ep +# else +# define IPL_EXTERN(ep) ipfilter/**/ep +# endif +#else +# ifdef __STDC__ +# define IPL_EXTERN(ep) ipl##ep +# else +# define IPL_EXTERN(ep) ipl/**/ep +# endif +#endif + +#ifdef linux +# include +#endif +#if SOLARIS +# define MTYPE(m) ((m)->b_datap->db_type) +# include +# include +# include +# include +/* + * because Solaris 2 defines these in two places :-/ + */ +# undef IPOPT_EOL +# undef IPOPT_NOP +# undef IPOPT_LSRR +# undef IPOPT_RR +# undef IPOPT_SSRR +# ifndef KERNEL +# define _KERNEL +# undef RES_INIT +# if SOLARIS2 >= 8 +# include +# endif +# include +# include +# include +# undef _KERNEL +# else /* _KERNEL */ +# if SOLARIS2 >= 8 +# include +# endif +# include +# include +# include +# endif /* _KERNEL */ +# if SOLARIS2 >= 8 +# include +# include +# define ipif_local_addr ipif_lcl_addr +/* Only defined in private include file */ +# ifndef V4_PART_OF_V6 +# define V4_PART_OF_V6(v6) v6.s6_addr32[3] +# endif +# endif +#else +# if !defined(__sgi) +typedef int minor_t; +#endif +#endif /* SOLARIS */ +#define IPMINLEN(i, h) ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h))) + +#ifndef IP_OFFMASK +#define IP_OFFMASK 0x1fff +#endif + +#if BSD > 199306 +# define USE_QUAD_T +# define U_QUAD_T u_quad_t +# define QUAD_T quad_t +#else /* BSD > 199306 */ +# define U_QUAD_T u_long +# define QUAD_T long +#endif /* BSD > 199306 */ + + +/* + * These operating systems already take care of the problem for us. + */ +#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \ + defined(__sgi) +typedef u_int32_t u_32_t; +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 104110000) +# include "opt_inet.h" +# endif +# if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \ + !defined(KLD_MODULE) +# include "opt_inet6.h" +# endif +# ifdef INET6 +# define USE_INET6 +# endif +# endif +#else +/* + * Really, any arch where sizeof(long) != sizeof(int). + */ +# if defined(__alpha__) || defined(__alpha) || defined(_LP64) +typedef unsigned int u_32_t; +# else +# if SOLARIS2 >= 6 +typedef uint32_t u_32_t; +# else +typedef unsigned int u_32_t; +# endif +# endif +#endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ || __sgi */ + +#ifdef USE_INET6 +# if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) +# include +# ifdef _KERNEL +# include +# endif +typedef struct ip6_hdr ip6_t; +# endif +union i6addr { + u_32_t i6[4]; + struct in_addr in4; + struct in6_addr in6; +}; +#else +union i6addr { + u_32_t i6[4]; + struct in_addr in4; +}; +#endif + +#define IP6CMP(a,b) bcmp((char *)&(a), (char *)&(b), sizeof(a)) +#define IP6EQ(a,b) (bcmp((char *)&(a), (char *)&(b), sizeof(a)) == 0) +#define IP6NEQ(a,b) (bcmp((char *)&(a), (char *)&(b), sizeof(a)) != 0) + +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +/* + * Security Options for Intenet Protocol (IPSO) as defined in RFC 1108. + * + * Basic Option + * + * 00000001 - (Reserved 4) + * 00111101 - Top Secret + * 01011010 - Secret + * 10010110 - Confidential + * 01100110 - (Reserved 3) + * 11001100 - (Reserved 2) + * 10101011 - Unclassified + * 11110001 - (Reserved 1) + */ +#define IPSO_CLASS_RES4 0x01 +#define IPSO_CLASS_TOPS 0x3d +#define IPSO_CLASS_SECR 0x5a +#define IPSO_CLASS_CONF 0x96 +#define IPSO_CLASS_RES3 0x66 +#define IPSO_CLASS_RES2 0xcc +#define IPSO_CLASS_UNCL 0xab +#define IPSO_CLASS_RES1 0xf1 + +#define IPSO_AUTH_GENSER 0x80 +#define IPSO_AUTH_ESI 0x40 +#define IPSO_AUTH_SCI 0x20 +#define IPSO_AUTH_NSA 0x10 +#define IPSO_AUTH_DOE 0x08 +#define IPSO_AUTH_UN 0x06 +#define IPSO_AUTH_FTE 0x01 + +/* + * IP option #defines + */ +/*#define IPOPT_RR 7 */ +#define IPOPT_ZSU 10 /* ZSU */ +#define IPOPT_MTUP 11 /* MTUP */ +#define IPOPT_MTUR 12 /* MTUR */ +#define IPOPT_ENCODE 15 /* ENCODE */ +/*#define IPOPT_TS 68 */ +#define IPOPT_TR 82 /* TR */ +/*#define IPOPT_SECURITY 130 */ +/*#define IPOPT_LSRR 131 */ +#define IPOPT_E_SEC 133 /* E-SEC */ +#define IPOPT_CIPSO 134 /* CIPSO */ +/*#define IPOPT_SATID 136 */ +#ifndef IPOPT_SID +# define IPOPT_SID IPOPT_SATID +#endif +/*#define IPOPT_SSRR 137 */ +#define IPOPT_ADDEXT 147 /* ADDEXT */ +#define IPOPT_VISA 142 /* VISA */ +#define IPOPT_IMITD 144 /* IMITD */ +#define IPOPT_EIP 145 /* EIP */ +#define IPOPT_FINN 205 /* FINN */ + + +#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL)) +# if __FreeBSD__ < 3 +# include +# else +# if __FreeBSD__ == 3 +# if defined(IPFILTER_LKM) && !defined(ACTUALLY_LKM_NOT_KERNEL) +# define ACTUALLY_LKM_NOT_KERNEL +# endif +# endif +# endif +#endif /* __FreeBSD__ && KERNEL */ + +/* + * Build some macros and #defines to enable the same code to compile anywhere + * Well, that's the idea, anyway :-) + */ +#if !SOLARIS || (SOLARIS2 < 6) || !defined(KERNEL) +# define ATOMIC_INCL ATOMIC_INC +# define ATOMIC_INC64 ATOMIC_INC +# define ATOMIC_INC32 ATOMIC_INC +# define ATOMIC_INC16 ATOMIC_INC +# define ATOMIC_DECL ATOMIC_DEC +# define ATOMIC_DEC64 ATOMIC_DEC +# define ATOMIC_DEC32 ATOMIC_DEC +# define ATOMIC_DEC16 ATOMIC_DEC +#endif +#ifdef KERNEL +# if SOLARIS +# if SOLARIS2 >= 6 +# include +# if SOLARIS2 == 6 +# define ATOMIC_INCL(x) atomic_add_long((uint32_t*)&(x), 1) +# define ATOMIC_DECL(x) atomic_add_long((uint32_t*)&(x), -1) +# else +# define ATOMIC_INCL(x) atomic_add_long(&(x), 1) +# define ATOMIC_DECL(x) atomic_add_long(&(x), -1) +# endif +# define ATOMIC_INC64(x) atomic_add_64((uint64_t*)&(x), 1) +# define ATOMIC_INC32(x) atomic_add_32((uint32_t*)&(x), 1) +# define ATOMIC_INC16(x) atomic_add_16((uint16_t*)&(x), 1) +# define ATOMIC_DEC64(x) atomic_add_64((uint64_t*)&(x), -1) +# define ATOMIC_DEC32(x) atomic_add_32((uint32_t*)&(x), -1) +# define ATOMIC_DEC16(x) atomic_add_16((uint16_t*)&(x), -1) +# else +# define ATOMIC_INC(x) { mutex_enter(&ipf_rw); (x)++; \ + mutex_exit(&ipf_rw); } +# define ATOMIC_DEC(x) { mutex_enter(&ipf_rw); (x)--; \ + mutex_exit(&ipf_rw); } +# endif +# define MUTEX_ENTER(x) mutex_enter(x) +# if 1 +# define KRWLOCK_T krwlock_t +# define READ_ENTER(x) rw_enter(x, RW_READER) +# define WRITE_ENTER(x) rw_enter(x, RW_WRITER) +# define RW_UPGRADE(x) { if (rw_tryupgrade(x) == 0) { \ + rw_exit(x); \ + rw_enter(x, RW_WRITER); } \ + } +# define MUTEX_DOWNGRADE(x) rw_downgrade(x) +# define RWLOCK_INIT(x, y, z) rw_init((x), (y), RW_DRIVER, (z)) +# define RWLOCK_EXIT(x) rw_exit(x) +# define RW_DESTROY(x) rw_destroy(x) +# else +# define KRWLOCK_T kmutex_t +# define READ_ENTER(x) mutex_enter(x) +# define WRITE_ENTER(x) mutex_enter(x) +# define MUTEX_DOWNGRADE(x) ; +# define RWLOCK_INIT(x, y, z) mutex_init((x), (y), MUTEX_DRIVER, (z)) +# define RWLOCK_EXIT(x) mutex_exit(x) +# define RW_DESTROY(x) mutex_destroy(x) +# endif +# define MUTEX_INIT(x, y, z) mutex_init((x), (y), MUTEX_DRIVER, (z)) +# define MUTEX_DESTROY(x) mutex_destroy(x) +# define MUTEX_EXIT(x) mutex_exit(x) +# define MTOD(m,t) (t)((m)->b_rptr) +# define IRCOPY(a,b,c) copyin((a), (b), (c)) +# define IWCOPY(a,b,c) copyout((a), (b), (c)) +# define IRCOPYPTR ircopyptr +# define IWCOPYPTR iwcopyptr +# define FREE_MB_T(m) freemsg(m) +# define SPL_NET(x) ; +# define SPL_IMP(x) ; +# undef SPL_X +# define SPL_X(x) ; +# ifdef sparc +# define ntohs(x) (x) +# define ntohl(x) (x) +# define htons(x) (x) +# define htonl(x) (x) +# endif /* sparc */ +# define KMALLOC(a,b) (a) = (b)kmem_alloc(sizeof(*(a)), KM_NOSLEEP) +# define KMALLOCS(a,b,c) (a) = (b)kmem_alloc((c), KM_NOSLEEP) +# define GET_MINOR(x) getminor(x) +typedef struct qif { + struct qif *qf_next; + ill_t *qf_ill; + kmutex_t qf_lock; + void *qf_iptr; + void *qf_optr; + queue_t *qf_in; + queue_t *qf_out; + struct qinit *qf_wqinfo; + struct qinit *qf_rqinfo; + struct qinit qf_wqinit; + struct qinit qf_rqinit; + mblk_t *qf_m; /* These three fields are for passing data up from */ + queue_t *qf_q; /* fr_qin and fr_qout to the packet processing. */ + size_t qf_off; + size_t qf_len; /* this field is used for in ipfr_fastroute */ + char qf_name[8]; + /* + * in case the ILL has disappeared... + */ + size_t qf_hl; /* header length */ + int qf_sap; +} qif_t; +extern ill_t *get_unit __P((char *, int)); +# define GETUNIT(n, v) get_unit(n, v) +# define IFNAME(x) ((ill_t *)x)->ill_name +# else /* SOLARIS */ +# if defined(__sgi) +# define hz HZ +# include +# define IPF_LOCK_PL plhi +# include +#undef kmutex_t +typedef struct { + lock_t *l; + int pl; +} kmutex_t; +# define ATOMIC_INC(x) { MUTEX_ENTER(&ipf_rw); \ + (x)++; MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_DEC(x) { MUTEX_ENTER(&ipf_rw); \ + (x)--; MUTEX_EXIT(&ipf_rw); } +# define MUTEX_ENTER(x) (x)->pl = LOCK((x)->l, IPF_LOCK_PL); +# define KRWLOCK_T kmutex_t +# define READ_ENTER(x) MUTEX_ENTER(x) +# define WRITE_ENTER(x) MUTEX_ENTER(x) +# define RW_UPGRADE(x) ; +# define MUTEX_DOWNGRADE(x) ; +# define RWLOCK_EXIT(x) MUTEX_EXIT(x) +# define MUTEX_EXIT(x) UNLOCK((x)->l, (x)->pl); +# define MUTEX_INIT(x,y,z) (x).l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP) +# define MUTEX_DESTROY(x) LOCK_DEALLOC((x).l) +# else /* __sgi */ +# define ATOMIC_INC(x) (x)++ +# define ATOMIC_DEC(x) (x)-- +# define MUTEX_ENTER(x) ; +# define READ_ENTER(x) ; +# define WRITE_ENTER(x) ; +# define RW_UPGRADE(x) ; +# define MUTEX_DOWNGRADE(x) ; +# define RWLOCK_EXIT(x) ; +# define MUTEX_EXIT(x) ; +# define MUTEX_INIT(x,y,z) ; +# define MUTEX_DESTROY(x) ; +# endif /* __sgi */ +# ifndef linux +# define FREE_MB_T(m) m_freem(m) +# define MTOD(m,t) mtod(m,t) +# define IRCOPY(a,b,c) (bcopy((a), (b), (c)), 0) +# define IWCOPY(a,b,c) (bcopy((a), (b), (c)), 0) +# define IRCOPYPTR ircopyptr +# define IWCOPYPTR iwcopyptr +# endif /* !linux */ +# endif /* SOLARIS */ + +# ifdef sun +# if !SOLARIS +# include +# define GETUNIT(n, v) ifunit(n, IFNAMSIZ) +# define IFNAME(x) ((struct ifnet *)x)->if_name +# endif +# else +# ifndef linux +# define GETUNIT(n, v) ifunit(n) +# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) +# define IFNAME(x) ((struct ifnet *)x)->if_xname +# else +# define IFNAME(x) ((struct ifnet *)x)->if_name +# endif +# endif +# endif /* sun */ + +# if defined(sun) && !defined(linux) || defined(__sgi) +# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d) +# define SLEEP(id, n) sleep((id), PZERO+1) +# define WAKEUP(id) wakeup(id) +# define KFREE(x) kmem_free((char *)(x), sizeof(*(x))) +# define KFREES(x,s) kmem_free((char *)(x), (s)) +# if !SOLARIS +extern void m_copydata __P((struct mbuf *, int, int, caddr_t)); +extern void m_copyback __P((struct mbuf *, int, int, caddr_t)); +# endif +# ifdef __sgi +# include +# include +# define KMALLOC(a,b) (a) = (b)kmem_alloc(sizeof(*(a)), KM_NOSLEEP) +# define KMALLOCS(a,b,c) (a) = (b)kmem_alloc((c), KM_NOSLEEP) +# define GET_MINOR(x) getminor(x) +# else +# if !SOLARIS +# define KMALLOC(a,b) (a) = (b)new_kmem_alloc(sizeof(*(a)), \ + KMEM_NOSLEEP) +# define KMALLOCS(a,b,c) (a) = (b)new_kmem_alloc((c), KMEM_NOSLEEP) +# endif /* SOLARIS */ +# endif /* __sgi */ +# endif /* sun && !linux */ +# ifndef GET_MINOR +# define GET_MINOR(x) minor(x) +# endif +# if (BSD >= 199306) || defined(__FreeBSD__) +# include +# if !defined(__FreeBSD__) || (defined (__FreeBSD__) && __FreeBSD__>=3) +# include +# include +extern vm_map_t kmem_map; +# else /* !__FreeBSD__ || (__FreeBSD__ && __FreeBSD__>=3) */ +# include +# endif /* !__FreeBSD__ || (__FreeBSD__ && __FreeBSD__>=3) */ +# ifdef M_PFIL +# define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), M_PFIL, M_NOWAIT) +# define KMALLOCS(a, b, c) MALLOC((a), b, (c), M_PFIL, M_NOWAIT) +# define KFREE(x) FREE((x), M_PFIL) +# define KFREES(x,s) FREE((x), M_PFIL) +# else +# define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), M_TEMP, M_NOWAIT) +# define KMALLOCS(a, b, c) MALLOC((a), b, (c), M_TEMP, M_NOWAIT) +# define KFREE(x) FREE((x), M_TEMP) +# define KFREES(x,s) FREE((x), M_TEMP) +# endif /* M_PFIL */ +# define UIOMOVE(a,b,c,d) uiomove(a,b,d) +# define SLEEP(id, n) tsleep((id), PPAUSE|PCATCH, n, 0) +# define WAKEUP(id) wakeup(id) +# endif /* BSD */ +# if defined(NetBSD) && NetBSD <= 1991011 && NetBSD >= 199407 +# define SPL_NET(x) x = splsoftnet() +# define SPL_X(x) (void) splx(x) +# else +# if !SOLARIS && !defined(linux) +# define SPL_IMP(x) x = splimp() +# define SPL_NET(x) x = splnet() +# define SPL_X(x) (void) splx(x) +# endif +# endif /* NetBSD && NetBSD <= 1991011 && NetBSD >= 199407 */ +# define PANIC(x,y) if (x) panic y +#else /* KERNEL */ +# define SLEEP(x,y) ; +# define WAKEUP(x) ; +# define PANIC(x,y) ; +# define ATOMIC_INC(x) (x)++ +# define ATOMIC_DEC(x) (x)-- +# define MUTEX_ENTER(x) ; +# define READ_ENTER(x) ; +# define MUTEX_INIT(x,y,z) ; +# define MUTEX_DESTROY(x) ; +# define WRITE_ENTER(x) ; +# define RW_UPGRADE(x) ; +# define MUTEX_DOWNGRADE(x) ; +# define RWLOCK_EXIT(x) ; +# define MUTEX_EXIT(x) ; +# define SPL_NET(x) ; +# define SPL_IMP(x) ; +# undef SPL_X +# define SPL_X(x) ; +# define KMALLOC(a,b) (a) = (b)malloc(sizeof(*a)) +# define KMALLOCS(a,b,c) (a) = (b)malloc(c) +# define KFREE(x) free(x) +# define KFREES(x,s) free(x) +# define GETUNIT(x, v) get_unit(x,v) +# define IRCOPY(a,b,c) (bcopy((a), (b), (c)), 0) +# define IWCOPY(a,b,c) (bcopy((a), (b), (c)), 0) +# define IRCOPYPTR ircopyptr +# define IWCOPYPTR iwcopyptr +#endif /* KERNEL */ + +#if SOLARIS +typedef mblk_t mb_t; +# if SOLARIS2 >= 7 +# ifdef lint +# define ALIGN32(ptr) (ptr ? 0L : 0L) +# define ALIGN16(ptr) (ptr ? 0L : 0L) +# else +# define ALIGN32(ptr) (ptr) +# define ALIGN16(ptr) (ptr) +# endif +# endif +#else +# ifdef linux +# ifndef kernel +typedef struct mb { + struct mb *next; + u_int len; + u_char *data; +} mb_t; +# else +typedef struct sk_buff mb_t; +# endif +# else +typedef struct mbuf mb_t; +# endif +#endif /* SOLARIS */ + +#if defined(linux) || defined(__sgi) +/* + * These #ifdef's are here mainly for linux, but who knows, they may + * not be in other places or maybe one day linux will grow up and some + * of these will turn up there too. + */ +#ifndef ICMP_MINLEN +# define ICMP_MINLEN 8 +#endif +#ifndef ICMP_UNREACH +# define ICMP_UNREACH ICMP_DEST_UNREACH +#endif +#ifndef ICMP_SOURCEQUENCH +# define ICMP_SOURCEQUENCH ICMP_SOURCE_QUENCH +#endif +#ifndef ICMP_TIMXCEED +# define ICMP_TIMXCEED ICMP_TIME_EXCEEDED +#endif +#ifndef ICMP_PARAMPROB +# define ICMP_PARAMPROB ICMP_PARAMETERPROB +#endif +#ifndef ICMP_TSTAMP +# define ICMP_TSTAMP ICMP_TIMESTAMP +#endif +#ifndef ICMP_TSTAMPREPLY +# define ICMP_TSTAMPREPLY ICMP_TIMESTAMPREPLY +#endif +#ifndef ICMP_IREQ +# define ICMP_IREQ ICMP_INFO_REQUEST +#endif +#ifndef ICMP_IREQREPLY +# define ICMP_IREQREPLY ICMP_INFO_REPLY +#endif +#ifndef ICMP_MASKREQ +# define ICMP_MASKREQ ICMP_ADDRESS +#endif +#ifndef ICMP_MASKREPLY +# define ICMP_MASKREPLY ICMP_ADDRESSREPLY +#endif +#ifndef IPVERSION +# define IPVERSION 4 +#endif +#ifndef IPOPT_MINOFF +# define IPOPT_MINOFF 4 +#endif +#ifndef IPOPT_COPIED +# define IPOPT_COPIED(x) ((x)&0x80) +#endif +#ifndef IPOPT_EOL +# define IPOPT_EOL 0 +#endif +#ifndef IPOPT_NOP +# define IPOPT_NOP 1 +#endif +#ifndef IP_MF +# define IP_MF ((u_short)0x2000) +#endif +#ifndef ETHERTYPE_IP +# define ETHERTYPE_IP ((u_short)0x0800) +#endif +#ifndef TH_FIN +# define TH_FIN 0x01 +#endif +#ifndef TH_SYN +# define TH_SYN 0x02 +#endif +#ifndef TH_RST +# define TH_RST 0x04 +#endif +#ifndef TH_PUSH +# define TH_PUSH 0x08 +#endif +#ifndef TH_ACK +# define TH_ACK 0x10 +#endif +#ifndef TH_URG +# define TH_URG 0x20 +#endif +#ifndef IPOPT_EOL +# define IPOPT_EOL 0 +#endif +#ifndef IPOPT_NOP +# define IPOPT_NOP 1 +#endif +#ifndef IPOPT_RR +# define IPOPT_RR 7 +#endif +#ifndef IPOPT_TS +# define IPOPT_TS 68 +#endif +#ifndef IPOPT_SECURITY +# define IPOPT_SECURITY 130 +#endif +#ifndef IPOPT_LSRR +# define IPOPT_LSRR 131 +#endif +#ifndef IPOPT_SATID +# define IPOPT_SATID 136 +#endif +#ifndef IPOPT_SSRR +# define IPOPT_SSRR 137 +#endif +#ifndef IPOPT_SECUR_UNCLASS +# define IPOPT_SECUR_UNCLASS ((u_short)0x0000) +#endif +#ifndef IPOPT_SECUR_CONFID +# define IPOPT_SECUR_CONFID ((u_short)0xf135) +#endif +#ifndef IPOPT_SECUR_EFTO +# define IPOPT_SECUR_EFTO ((u_short)0x789a) +#endif +#ifndef IPOPT_SECUR_MMMM +# define IPOPT_SECUR_MMMM ((u_short)0xbc4d) +#endif +#ifndef IPOPT_SECUR_RESTR +# define IPOPT_SECUR_RESTR ((u_short)0xaf13) +#endif +#ifndef IPOPT_SECUR_SECRET +# define IPOPT_SECUR_SECRET ((u_short)0xd788) +#endif +#ifndef IPOPT_SECUR_TOPSECRET +# define IPOPT_SECUR_TOPSECRET ((u_short)0x6bc5) +#endif +#ifndef IPOPT_OLEN +# define IPOPT_OLEN 1 +#endif +#endif /* linux || __sgi */ + +#ifdef linux +#include +/* + * TCP States + */ +#define TCPS_CLOSED 0 /* closed */ +#define TCPS_LISTEN 1 /* listening for connection */ +#define TCPS_SYN_SENT 2 /* active, have sent syn */ +#define TCPS_SYN_RECEIVED 3 /* have send and received syn */ +/* states < TCPS_ESTABLISHED are those where connections not established */ +#define TCPS_ESTABLISHED 4 /* established */ +#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ +/* states > TCPS_CLOSE_WAIT are those where user has closed */ +#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ +#define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */ +#define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ +/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */ +#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ +#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ + +/* + * file flags. + */ +#ifdef WRITE +#define FWRITE WRITE +#define FREAD READ +#else +#define FWRITE _IOC_WRITE +#define FREAD _IOC_READ +#endif +/* + * mbuf related problems. + */ +#define mtod(m,t) (t)((m)->data) +#define m_len len +#define m_next next + +#ifdef IP_DF +#undef IP_DF +#endif +#define IP_DF 0x4000 + +typedef struct { + __u16 th_sport; + __u16 th_dport; + __u32 th_seq; + __u32 th_ack; +# if defined(__i386__) || defined(__MIPSEL__) || defined(__alpha__) ||\ + defined(vax) + __u8 th_res:4; + __u8 th_off:4; +#else + __u8 th_off:4; + __u8 th_res:4; +#endif + __u8 th_flags; + __u16 th_win; + __u16 th_sum; + __u16 th_urp; +} tcphdr_t; + +typedef struct { + __u16 uh_sport; + __u16 uh_dport; + __u16 uh_ulen; + __u16 uh_sum; +} udphdr_t; + +typedef struct { +# if defined(__i386__) || defined(__MIPSEL__) || defined(__alpha__) ||\ + defined(vax) + __u8 ip_hl:4; + __u8 ip_v:4; +# else + __u8 ip_v:4; + __u8 ip_hl:4; +# endif + __u8 ip_tos; + __u16 ip_len; + __u16 ip_id; + __u16 ip_off; + __u8 ip_ttl; + __u8 ip_p; + __u16 ip_sum; + struct in_addr ip_src; + struct in_addr ip_dst; +} ip_t; + +/* + * Structure of an icmp header. + */ +typedef struct icmp { + __u8 icmp_type; /* type of message, see below */ + __u8 icmp_code; /* type sub code */ + __u16 icmp_cksum; /* ones complement cksum of struct */ + union { + __u8 ih_pptr; /* ICMP_PARAMPROB */ + struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ + struct ih_idseq { + __u16 icd_id; + __u16 icd_seq; + } ih_idseq; + int ih_void; + } icmp_hun; +# define icmp_pptr icmp_hun.ih_pptr +# define icmp_gwaddr icmp_hun.ih_gwaddr +# define icmp_id icmp_hun.ih_idseq.icd_id +# define icmp_seq icmp_hun.ih_idseq.icd_seq +# define icmp_void icmp_hun.ih_void + union { + struct id_ts { + n_time its_otime; + n_time its_rtime; + n_time its_ttime; + } id_ts; + struct id_ip { + ip_t idi_ip; + /* options and then 64 bits of data */ + } id_ip; + u_long id_mask; + char id_data[1]; + } icmp_dun; +# define icmp_otime icmp_dun.id_ts.its_otime +# define icmp_rtime icmp_dun.id_ts.its_rtime +# define icmp_ttime icmp_dun.id_ts.its_ttime +# define icmp_ip icmp_dun.id_ip.idi_ip +# define icmp_mask icmp_dun.id_mask +# define icmp_data icmp_dun.id_data +} icmphdr_t; + +# ifndef LINUX_IPOVLY +# define LINUX_IPOVLY +struct ipovly { + caddr_t ih_next, ih_prev; /* for protocol sequence q's */ + u_char ih_x1; /* (unused) */ + u_char ih_pr; /* protocol */ + short ih_len; /* protocol length */ + struct in_addr ih_src; /* source internet address */ + struct in_addr ih_dst; /* destination internet address */ +}; +# endif + +typedef struct { + __u8 ether_dhost[6]; + __u8 ether_shost[6]; + __u16 ether_type; +} ether_header_t; + +typedef struct uio { + int uio_resid; + int uio_rw; + caddr_t uio_buf; +} uio_t; + +# define UIO_READ 0 +# define UIO_WRITE 1 +# define UIOMOVE(a, b, c, d) uiomove(a,b,c,d) + +/* + * For masking struct ifnet onto struct device + */ +# define if_name name + +# ifdef KERNEL +# define GETUNIT(x, v) dev_get(x) +# define FREE_MB_T(m) kfree_skb(m, FREE_WRITE) +# define uniqtime do_gettimeofday +# undef INT_MAX +# undef UINT_MAX +# undef LONG_MAX +# undef ULONG_MAX +# include +# define SPL_X(x) +# define SPL_NET(x) +# define SPL_IMP(x) + +# define bcmp(a,b,c) memcmp(a,b,c) +# define bcopy(a,b,c) memcpy(b,a,c) +# define bzero(a,c) memset(a,0,c) + +# define UNITNAME(n) dev_get((n)) + +# define KMALLOC(a,b) (a) = (b)kmalloc(sizeof(*(a)), GFP_ATOMIC) +# define KMALLOCS(a,b,c) (a) = (b)kmalloc((c), GFP_ATOMIC) +# define KFREE(x) kfree_s((x), sizeof(*(x))) +# define KFREES(x,s) kfree_s((x), (s)) +#define IRCOPY(const void *a, void *b, size_t c) { \ + int error; \ + + error = verify_area(VERIFY_READ, a ,c); \ + if (!error) \ + memcpy_fromfs(b, a, c); \ + return error; \ +} +static inline int IWCOPY(const void *a, void *b, size_t c) +{ + int error; + + error = verify_area(VERIFY_WRITE, b, c); + if (!error) + memcpy_tofs(b, a, c); + return error; +} +static inline int IRCOPYPTR(const void *a, void *b, size_t c) { + caddr_t ca; + int error; + + error = verify_area(VERIFY_READ, a ,sizeof(ca)); + if (!error) { + memcpy_fromfs(ca, a, sizeof(ca)); + error = verify_area(VERIFY_READ, ca , c); + if (!error) + memcpy_fromfs(b, ca, c); + } + return error; +} +static inline int IWCOPYPTR(const void *a, void *b, size_t c) { + caddr_t ca; + int error; + + + error = verify_area(VERIFY_READ, b ,sizeof(ca)); + if (!error) { + memcpy_fromfs(ca, b, sizeof(ca)); + error = verify_area(VERIFY_WRITE, ca, c); + if (!error) + memcpy_tofs(ca, a, c); + } + return error; +} +# else +# define __KERNEL__ +# undef INT_MAX +# undef UINT_MAX +# undef LONG_MAX +# undef ULONG_MAX +# define s8 __s8 +# define u8 __u8 +# define s16 __s16 +# define u16 __u16 +# define s32 __s32 +# define u32 __u32 +# include +# undef __KERNEL__ +# endif +# define ifnet device +#else +typedef struct tcphdr tcphdr_t; +typedef struct udphdr udphdr_t; +typedef struct icmp icmphdr_t; +typedef struct ip ip_t; +typedef struct ether_header ether_header_t; +#endif /* linux */ +typedef struct tcpiphdr tcpiphdr_t; + +#if defined(hpux) || defined(linux) +struct ether_addr { + char ether_addr_octet[6]; +}; +#endif + +/* + * XXX - This is one of those *awful* hacks which nobody likes + */ +#ifdef ultrix +#define A_A +#else +#define A_A & +#endif + +#define TCPF_ALL (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG) + +#ifndef ICMP_ROUTERADVERT +# define ICMP_ROUTERADVERT 9 +#endif +#ifndef ICMP_ROUTERSOLICIT +# define ICMP_ROUTERSOLICIT 10 +#endif +#undef ICMP_MAX_UNREACH +#define ICMP_MAX_UNREACH 14 +#undef ICMP_MAXTYPE +#define ICMP_MAXTYPE 18 +/* + * ICMP error replies have an IP header (20 bytes), 8 bytes of ICMP data, + * another IP header and then 64 bits of data, totalling 56. Of course, + * the last 64 bits is dependant on that being available. + */ +#define ICMPERR_ICMPHLEN 8 +#define ICMPERR_IPICMPHLEN (20 + 8) +#define ICMPERR_MINPKTLEN (20 + 8 + 20) +#define ICMPERR_MAXPKTLEN (20 + 8 + 20 + 8) +#define ICMP6ERR_MINPKTLEN (20 + 8) + +#endif /* __IP_COMPAT_H__ */ Property changes on: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_compat.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_fil.c =================================================================== --- vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_fil.c (nonexistent) +++ vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_fil.c (revision 60849) @@ -0,0 +1,1705 @@ +/* + * 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. + */ +#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_fil.c,v 2.42.2.9 2000/05/22 12:48:28 darrenr Exp $"; +#endif + +#ifndef SOLARIS +#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +#endif + +#if defined(KERNEL) && !defined(_KERNEL) +# define _KERNEL +#endif +#if defined(_KERNEL) && defined(__FreeBSD_version) && \ + (__FreeBSD_version >= 400000) && !defined(KLD_MODULE) +#include "opt_inet6.h" +#endif +#include +#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ + defined(_KERNEL) +# include "opt_ipfilter_log.h" +#endif +#if defined(__FreeBSD__) && !defined(__FreeBSD_version) +# if !defined(_KERNEL) || defined(IPFILTER_LKM) +# include +# endif +#endif +#ifndef _KERNEL +# include +# include +# include +# include +# include +#endif +#include +#include +#include +#if __FreeBSD_version >= 220000 && defined(_KERNEL) +# include +# include +#else +# include +#endif +#include +#ifdef _KERNEL +# include +#endif +#include +#if !SOLARIS +# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000) +# include +# else +# include +# endif +# include +#else +# include +#endif +#include +#include + +#include +#ifdef sun +# include +#endif +#if __FreeBSD_version >= 300000 +# include +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# include "opt_ipfilter.h" +# endif +#endif +#ifdef __sgi +#include +# ifdef IFF_DRVRLOCK /* IRIX6 */ +#include +# endif +#endif +#include +#include +#if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */ +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#ifndef _KERNEL +# include +# include +#endif +#include "netinet/ip_compat.h" +#ifdef USE_INET6 +# include +#endif +#include "netinet/ip_fil.h" +#include "netinet/ip_proxy.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_frag.h" +#include "netinet/ip_state.h" +#include "netinet/ip_auth.h" +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) +# include +#endif +#ifndef MIN +# define MIN(a,b) (((a)<(b))?(a):(b)) +#endif +#if !SOLARIS && defined(_KERNEL) && !defined(__sgi) +# include +extern int ip_optcopy __P((struct ip *, struct ip *)); +#endif + + +extern struct protosw inetsw[]; + +#ifndef _KERNEL +# include "ipt.h" +static struct ifnet **ifneta = NULL; +static int nifs = 0; +#else +# if (BSD < 199306) || defined(__sgi) +extern int tcp_ttl; +# endif +#endif + +int ipl_unreach = ICMP_UNREACH_FILTER; +u_long ipl_frouteok[2] = {0, 0}; + +static int frzerostats __P((caddr_t)); +#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) +static int frrequest __P((int, u_long, caddr_t, int)); +#else +static int frrequest __P((int, int, caddr_t, int)); +#endif +#ifdef _KERNEL +static int (*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **)); +static int send_ip __P((ip_t *, fr_info_t *, struct mbuf *)); +# ifdef __sgi +extern kmutex_t ipf_rw; +extern KRWLOCK_T ipf_mutex; +# endif +#else +int ipllog __P((void)); +void init_ifp __P((void)); +# ifdef __sgi +static int no_output __P((struct ifnet *, struct mbuf *, + struct sockaddr *)); +static int write_output __P((struct ifnet *, struct mbuf *, + struct sockaddr *)); +# else +static int no_output __P((struct ifnet *, struct mbuf *, + struct sockaddr *, struct rtentry *)); +static int write_output __P((struct ifnet *, struct mbuf *, + struct sockaddr *, struct rtentry *)); +# endif +#endif +int fr_running = 0; + +#if (__FreeBSD_version >= 300000) && defined(_KERNEL) +struct callout_handle ipfr_slowtimer_ch; +#endif +#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) +# include +struct callout ipfr_slowtimer_ch; +#endif + +#if (_BSDI_VERSION >= 199510) && defined(_KERNEL) +# include +# include + +struct cfdriver iplcd = { + NULL, "ipl", NULL, NULL, DV_DULL, 0 +}; + +struct devsw iplsw = { + &iplcd, + iplopen, iplclose, iplread, nowrite, iplioctl, noselect, nommap, + nostrat, nodump, nopsize, 0, + nostop +}; +#endif /* _BSDI_VERSION >= 199510 && _KERNEL */ + +#if defined(__NetBSD__) || defined(__OpenBSD__) || (_BSDI_VERSION >= 199701) +# include +# if defined(NETBSD_PF) +# include +/* + * We provide the fr_checkp name just to minimize changes later. + */ +int (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp)); +# endif /* NETBSD_PF */ +#endif /* __NetBSD__ */ + +#ifdef _KERNEL +# if defined(IPFILTER_LKM) && !defined(__sgi) +int iplidentify(s) +char *s; +{ + if (strcmp(s, "ipl") == 0) + return 1; + return 0; +} +# endif /* IPFILTER_LKM */ + + +/* + * Try to detect the case when compiling for NetBSD with pseudo-device + */ +# if defined(__NetBSD__) && defined(PFIL_HOOKS) +void +ipfilterattach(count) +int count; +{ + if (iplattach() != 0) + printf("IP Filter failed to attach\n"); +} +# endif + + +int iplattach() +{ + char *defpass; + int s; +# if defined(__sgi) || (defined(NETBSD_PF) && (__NetBSD_Version__ >= 104200000)) + int error = 0; +# endif + + SPL_NET(s); + if (fr_running || (fr_checkp == fr_check)) { + printf("IP Filter: already initialized\n"); + SPL_X(s); + return EBUSY; + } + +# ifdef IPFILTER_LOG + ipflog_init(); +# endif + if (nat_init() == -1) + return -1; + if (fr_stateinit() == -1) + return -1; + if (appr_init() == -1) + return -1; + +# ifdef NETBSD_PF +# if __NetBSD_Version__ >= 104200000 + error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT, + &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); + if (error) { +# ifdef USE_INET6 + goto pfil_error; +# else + appr_unload(); + ip_natunload(); + fr_stateunload(); + return error; +# endif + } +# else + pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT); +# endif +# ifdef USE_INET6 + error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT, + &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh); + if (error) { + pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, + &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); +pfil_error: + appr_unload(); + ip_natunload(); + fr_stateunload(); + return error; + } +# endif +# endif + +# ifdef __sgi + error = ipfilter_sgi_attach(); + if (error) { + SPL_X(s); + appr_unload(); + ip_natunload(); + fr_stateunload(); + return error; + } +# endif + + bzero((char *)frcache, sizeof(frcache)); + fr_savep = fr_checkp; + fr_checkp = fr_check; + fr_running = 1; + + SPL_X(s); + if (fr_pass & FR_PASS) + defpass = "pass"; + else if (fr_pass & FR_BLOCK) + defpass = "block"; + else + defpass = "no-match -> block"; + + printf("%s initialized. Default = %s all, Logging = %s\n", + ipfilter_version, defpass, +# ifdef IPFILTER_LOG + "enabled"); +# else + "disabled"); +# endif +#ifdef _KERNEL +# if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) + callout_init(&ipfr_slowtimer_ch); + callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL); +# else +# if (__FreeBSD_version >= 300000) && defined(_KERNEL) + ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); +# else + timeout(ipfr_slowtimer, NULL, hz/2); +# endif +# endif +#endif + return 0; +} + + +/* + * Disable the filter by removing the hooks from the IP input/output + * stream. + */ +int ipldetach() +{ + int s, i = FR_INQUE|FR_OUTQUE; +#if defined(NETBSD_PF) && (__NetBSD_Version__ >= 104200000) + int error = 0; +#endif + +#ifdef _KERNEL +# if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) + callout_stop(&ipfr_slowtimer_ch); +# else +# if (__FreeBSD_version >= 300000) + untimeout(ipfr_slowtimer, NULL, ipfr_slowtimer_ch); +# else +# ifdef __sgi + untimeout(ipfr_slowtimer); +# else + untimeout(ipfr_slowtimer, NULL); +# endif +# endif /* FreeBSD */ +# endif /* NetBSD */ +#endif + SPL_NET(s); + if (!fr_running) + { + printf("IP Filter: not initialized\n"); + SPL_X(s); + return 0; + } + + printf("%s unloaded\n", ipfilter_version); + + fr_checkp = fr_savep; + i = frflush(IPL_LOGIPF, i); + fr_running = 0; + +# ifdef NETBSD_PF +# if __NetBSD_Version__ >= 104200000 + error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, + &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); + if (error) + return error; +# else + pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT); +# endif +# ifdef USE_INET6 + error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, + &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh); + if (error) + return error; +# endif +# endif + +# ifdef __sgi + ipfilter_sgi_detach(); +# endif + + appr_unload(); + ipfr_unload(); + ip_natunload(); + fr_stateunload(); + fr_authunload(); + + SPL_X(s); + return 0; +} +#endif /* _KERNEL */ + + +static int frzerostats(data) +caddr_t data; +{ + friostat_t fio; + int error; + + fr_getstat(&fio); + error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio)); + if (error) + return EFAULT; + + bzero((char *)frstats, sizeof(*frstats) * 2); + + return 0; +} + + +/* + * Filter ioctl interface. + */ +#ifdef __sgi +int IPL_EXTERN(ioctl)(dev_t dev, int cmd, caddr_t data, int mode +# ifdef _KERNEL + , cred_t *cp, int *rp +# endif +) +#else +int IPL_EXTERN(ioctl)(dev, cmd, data, mode +# if (defined(_KERNEL) && ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || \ + (NetBSD >= 199511) || (__FreeBSD_version >= 220000) || \ + defined(__OpenBSD__))) +, p) +struct proc *p; +# else +) +# endif +dev_t dev; +# if defined(__NetBSD__) || defined(__OpenBSD__) || \ + (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) +u_long cmd; +# else +int cmd; +# endif +caddr_t data; +int mode; +#endif /* __sgi */ +{ +#if defined(_KERNEL) && !SOLARIS + int s; +#endif + int error = 0, unit = 0, tmp; + +#if (BSD >= 199306) && defined(_KERNEL) + if ((securelevel >= 2) && (mode & FWRITE)) + return EPERM; +#endif +#ifdef _KERNEL + unit = GET_MINOR(dev); + if ((IPL_LOGMAX < unit) || (unit < 0)) + return ENXIO; +#else + unit = dev; +#endif + + SPL_NET(s); + + if (unit == IPL_LOGNAT) { + if (fr_running) + error = nat_ioctl(data, cmd, mode); + else + error = EIO; + SPL_X(s); + return error; + } + if (unit == IPL_LOGSTATE) { + if (fr_running) + error = fr_state_ioctl(data, cmd, mode); + else + error = EIO; + SPL_X(s); + return error; + } + if (unit == IPL_LOGAUTH) { + if (!fr_running) + return EIO; + error = fr_auth_ioctl(data, cmd, NULL, NULL); + SPL_X(s); + return error; + } + + switch (cmd) { + case FIONREAD : +#ifdef IPFILTER_LOG + error = IWCOPY((caddr_t)&iplused[IPL_LOGIPF], (caddr_t)data, + sizeof(iplused[IPL_LOGIPF])); +#endif + break; +#if !defined(IPFILTER_LKM) && defined(_KERNEL) + case SIOCFRENB : + { + u_int enable; + + if (!(mode & FWRITE)) + error = EPERM; + else { + error = IRCOPY(data, (caddr_t)&enable, sizeof(enable)); + if (error) + break; + if (enable) + error = iplattach(); + else + error = ipldetach(); + } + break; + } +#endif + case SIOCSETFF : + if (!(mode & FWRITE)) + error = EPERM; + else + error = IRCOPY(data, (caddr_t)&fr_flags, + sizeof(fr_flags)); + break; + case SIOCGETFF : + error = IWCOPY((caddr_t)&fr_flags, data, sizeof(fr_flags)); + break; + case SIOCINAFR : + case SIOCRMAFR : + case SIOCADAFR : + case SIOCZRLST : + if (!(mode & FWRITE)) + error = EPERM; + else + error = frrequest(unit, cmd, data, fr_active); + break; + case SIOCINIFR : + case SIOCRMIFR : + case SIOCADIFR : + if (!(mode & FWRITE)) + error = EPERM; + else + error = frrequest(unit, cmd, data, 1 - fr_active); + break; + case SIOCSWAPA : + if (!(mode & FWRITE)) + error = EPERM; + else { + bzero((char *)frcache, sizeof(frcache[0]) * 2); + *(u_int *)data = fr_active; + fr_active = 1 - fr_active; + } + break; + case SIOCGETFS : + { + friostat_t fio; + + fr_getstat(&fio); + error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio)); + if (error) + return EFAULT; + break; + } + case SIOCFRZST : + if (!(mode & FWRITE)) + error = EPERM; + else + error = frzerostats(data); + break; + case SIOCIPFFL : + if (!(mode & FWRITE)) + error = EPERM; + else { + error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp)); + if (!error) { + tmp = frflush(unit, tmp); + error = IWCOPY((caddr_t)&tmp, data, + sizeof(tmp)); + } + } + break; + case SIOCSTLCK : + error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp)); + if (!error) { + fr_state_lock = tmp; + fr_nat_lock = tmp; + fr_frag_lock = tmp; + fr_auth_lock = tmp; + } else + error = EFAULT; + break; +#ifdef IPFILTER_LOG + case SIOCIPFFB : + if (!(mode & FWRITE)) + error = EPERM; + else + *(int *)data = ipflog_clear(unit); + break; +#endif /* IPFILTER_LOG */ + case SIOCGFRST : + error = IWCOPYPTR((caddr_t)ipfr_fragstats(), data, + sizeof(ipfrstat_t)); + if (error) + return EFAULT; + break; + case SIOCAUTHW : + case SIOCAUTHR : + if (!(mode & FWRITE)) { + error = EPERM; + break; + } + case SIOCFRSYN : + if (!(mode & FWRITE)) + error = EPERM; + else { +#if defined(_KERNEL) && defined(__sgi) + ipfsync(); +#endif + frsync(); + } + break; + default : + error = EINVAL; + break; + } + SPL_X(s); + return error; +} + + +void fr_forgetifp(ifp) +void *ifp; +{ + register frentry_t *f; + + WRITE_ENTER(&ipf_mutex); + for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; +#ifdef USE_INET6 + for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; +#endif + RWLOCK_EXIT(&ipf_mutex); + ip_natsync(ifp); +} + + +static int frrequest(unit, req, data, set) +int unit; +#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) +u_long req; +#else +int req; +#endif +int set; +caddr_t data; +{ + register frentry_t *fp, *f, **fprev; + register frentry_t **ftail; + frentry_t frd; + frdest_t *fdp; + frgroup_t *fg = NULL; + u_int *p, *pp; + int error = 0, in; + u_int group; + + fp = &frd; + error = IRCOPYPTR(data, (caddr_t)fp, sizeof(*fp)); + if (error) + return EFAULT; + fp->fr_ref = 0; + + /* + * Check that the group number does exist and that if a head group + * has been specified, doesn't exist. + */ + if ((req != SIOCZRLST) && fp->fr_grhead && + fr_findgroup((u_int)fp->fr_grhead, fp->fr_flags, unit, set, NULL)) + return EEXIST; + if ((req != SIOCZRLST) && fp->fr_group && + !fr_findgroup((u_int)fp->fr_group, fp->fr_flags, unit, set, NULL)) + return ESRCH; + + in = (fp->fr_flags & FR_INQUE) ? 0 : 1; + + if (unit == IPL_LOGAUTH) + ftail = fprev = &ipauth; + else if ((fp->fr_flags & FR_ACCOUNT) && (fp->fr_v == 4)) + ftail = fprev = &ipacct[in][set]; + else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) && (fp->fr_v == 4)) + ftail = fprev = &ipfilter[in][set]; +#ifdef USE_INET6 + else if ((fp->fr_flags & FR_ACCOUNT) && (fp->fr_v == 6)) + ftail = fprev = &ipacct6[in][set]; + else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) && (fp->fr_v == 6)) + ftail = fprev = &ipfilter6[in][set]; +#endif + else + return ESRCH; + + if ((group = fp->fr_group)) { + if (!(fg = fr_findgroup(group, fp->fr_flags, unit, set, NULL))) + return ESRCH; + ftail = fprev = fg->fg_start; + } + + bzero((char *)frcache, sizeof(frcache[0]) * 2); + + if (*fp->fr_ifname) { + fp->fr_ifa = GETUNIT(fp->fr_ifname, fp->fr_v); + if (!fp->fr_ifa) + fp->fr_ifa = (void *)-1; + } +#if BSD >= 199306 + if (*fp->fr_oifname) { + fp->fr_oifa = GETUNIT(fp->fr_oifname, fp->fr_v); + if (!fp->fr_oifa) + fp->fr_oifa = (void *)-1; + } +#endif + + fdp = &fp->fr_dif; + fp->fr_flags &= ~FR_DUP; + if (*fdp->fd_ifname) { + fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fp->fr_v); + if (!fdp->fd_ifp) + fdp->fd_ifp = (struct ifnet *)-1; + else + fp->fr_flags |= FR_DUP; + } + + fdp = &fp->fr_tif; + if (*fdp->fd_ifname) { + fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fp->fr_v); + if (!fdp->fd_ifp) + fdp->fd_ifp = (struct ifnet *)-1; + } + + /* + * Look for a matching filter rule, but don't include the next or + * interface pointer in the comparison (fr_next, fr_ifa). + */ + for (fp->fr_cksum = 0, p = (u_int *)&fp->fr_ip, pp = &fp->fr_cksum; + p != pp; p++) + fp->fr_cksum += *p; + + for (; (f = *ftail); ftail = &f->fr_next) + if ((fp->fr_cksum == f->fr_cksum) && + !bcmp((char *)&f->fr_ip, (char *)&fp->fr_ip, FR_CMPSIZ)) + break; + + /* + * If zero'ing statistics, copy current to caller and zero. + */ + if (req == SIOCZRLST) { + if (!f) + return ESRCH; + error = IWCOPYPTR((caddr_t)f, data, sizeof(*f)); + if (error) + return EFAULT; + f->fr_hits = 0; + f->fr_bytes = 0; + return 0; + } + + if (!f) { + if (req != SIOCINAFR && req != SIOCINIFR) + while ((f = *ftail)) + ftail = &f->fr_next; + else { + if (fp->fr_hits) { + ftail = fprev; + while (--fp->fr_hits && (f = *ftail)) + ftail = &f->fr_next; + } + f = NULL; + } + } + + if (req == SIOCRMAFR || req == SIOCRMIFR) { + if (!f) + error = ESRCH; + else { + /* + * Only return EBUSY if there is a group list, else + * it's probably just state information referencing + * the rule. + */ + if ((f->fr_ref > 1) && f->fr_grp) + return EBUSY; + if (fg && fg->fg_head) + fg->fg_head->fr_ref--; + if (unit == IPL_LOGAUTH) + return fr_auth_ioctl(data, req, f, ftail); + if (f->fr_grhead) + fr_delgroup((u_int)f->fr_grhead, fp->fr_flags, + unit, set); + fixskip(fprev, f, -1); + *ftail = f->fr_next; + f->fr_next = NULL; + if (f->fr_ref == 0) + KFREE(f); + } + } else { + if (f) + error = EEXIST; + else { + if (unit == IPL_LOGAUTH) + return fr_auth_ioctl(data, req, fp, ftail); + KMALLOC(f, frentry_t *); + if (f != NULL) { + if (fg && fg->fg_head) + fg->fg_head->fr_ref++; + bcopy((char *)fp, (char *)f, sizeof(*f)); + f->fr_ref = 1; + f->fr_hits = 0; + f->fr_next = *ftail; + *ftail = f; + if (req == SIOCINIFR || req == SIOCINAFR) + fixskip(fprev, f, 1); + f->fr_grp = NULL; + if ((group = f->fr_grhead)) + fg = fr_addgroup(group, f, unit, set); + } else + error = ENOMEM; + } + } + return (error); +} + + +#ifdef _KERNEL +/* + * routines below for saving IP headers to buffer + */ +# ifdef __sgi +# ifdef _KERNEL +int IPL_EXTERN(open)(dev_t *pdev, int flags, int devtype, cred_t *cp) +# else +int IPL_EXTERN(open)(dev_t dev, int flags) +# endif +# else +int IPL_EXTERN(open)(dev, flags +# if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ + (__FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL) +, devtype, p) +int devtype; +struct proc *p; +# else +) +# endif +dev_t dev; +int flags; +# endif /* __sgi */ +{ +# if defined(__sgi) && defined(_KERNEL) + u_int min = geteminor(*pdev); +# else + u_int min = GET_MINOR(dev); +# endif + + if (IPL_LOGMAX < min) + min = ENXIO; + else + min = 0; + return min; +} + + +# ifdef __sgi +int IPL_EXTERN(close)(dev_t dev, int flags, int devtype, cred_t *cp) +#else +int IPL_EXTERN(close)(dev, flags +# if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ + (__FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL) +, devtype, p) +int devtype; +struct proc *p; +# else +) +# endif +dev_t dev; +int flags; +# endif /* __sgi */ +{ + u_int min = GET_MINOR(dev); + + if (IPL_LOGMAX < min) + min = ENXIO; + else + min = 0; + return min; +} + +/* + * iplread/ipllog + * both of these must operate with at least splnet() lest they be + * called during packet processing and cause an inconsistancy to appear in + * the filter lists. + */ +# ifdef __sgi +int IPL_EXTERN(read)(dev_t dev, uio_t *uio, cred_t *crp) +# else +# if BSD >= 199306 +int IPL_EXTERN(read)(dev, uio, ioflag) +int ioflag; +# else +int IPL_EXTERN(read)(dev, uio) +# endif +dev_t dev; +register struct uio *uio; +# endif /* __sgi */ +{ +# ifdef IPFILTER_LOG + return ipflog_read(GET_MINOR(dev), uio); +# else + return ENXIO; +# endif +} + + +/* + * send_reset - this could conceivably be a call to tcp_respond(), but that + * requires a large amount of setting up and isn't any more efficient. + */ +int send_reset(oip, fin) +struct ip *oip; +fr_info_t *fin; +{ + struct tcphdr *tcp, *tcp2; + int tlen = 0, hlen; + struct mbuf *m; +#ifdef USE_INET6 + ip6_t *ip6, *oip6 = (ip6_t *)oip; +#endif + ip_t *ip; + + tcp = (struct tcphdr *)fin->fin_dp; + if (tcp->th_flags & TH_RST) + return -1; /* feedback loop */ +# if (BSD < 199306) || defined(__sgi) + m = m_get(M_DONTWAIT, MT_HEADER); +# else + m = m_gethdr(M_DONTWAIT, MT_HEADER); +# endif + if (m == NULL) + return ENOBUFS; + if (m == NULL) + return -1; + + if (tcp->th_flags & TH_SYN) + tlen = 1; +#ifdef USE_INET6 + hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t); +#else + hlen = sizeof(ip_t); +#endif + m->m_len = sizeof(*tcp2) + hlen; +# if BSD >= 199306 + m->m_data += max_linkhdr; + m->m_pkthdr.len = m->m_len; + m->m_pkthdr.rcvif = (struct ifnet *)0; +# endif + ip = mtod(m, struct ip *); +# ifdef USE_INET6 + ip6 = (ip6_t *)ip; +# endif + bzero((char *)ip, sizeof(*tcp2) + hlen); + tcp2 = (struct tcphdr *)((char *)ip + hlen); + + tcp2->th_sport = tcp->th_dport; + tcp2->th_dport = tcp->th_sport; + tcp2->th_ack = ntohl(tcp->th_seq); + tcp2->th_ack += tlen; + tcp2->th_ack = htonl(tcp2->th_ack); + tcp2->th_off = sizeof(*tcp2) >> 2; + tcp2->th_flags = TH_RST|TH_ACK; +# ifdef USE_INET6 + if (fin->fin_v == 6) { + ip6->ip6_plen = htons(sizeof(struct tcphdr)); + ip6->ip6_nxt = IPPROTO_TCP; + ip6->ip6_src = oip6->ip6_dst; + ip6->ip6_dst = oip6->ip6_src; + tcp2->th_sum = in6_cksum(m, IPPROTO_TCP, + sizeof(*ip6), sizeof(*tcp2)); + return send_ip(oip, fin, m); + } +# endif + ip->ip_p = IPPROTO_TCP; + ip->ip_len = htons(sizeof(struct tcphdr)); + ip->ip_src.s_addr = oip->ip_dst.s_addr; + ip->ip_dst.s_addr = oip->ip_src.s_addr; + tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2)); + ip->ip_len = hlen + sizeof(*tcp2); + return send_ip(oip, fin, m); +} + + +static int send_ip(oip, fin, m) +ip_t *oip; +fr_info_t *fin; +struct mbuf *m; +{ + ip_t *ip; + + ip = mtod(m, ip_t *); + + ip->ip_v = fin->fin_v; + if (ip->ip_v == 4) { + ip->ip_hl = (sizeof(*oip) >> 2); + ip->ip_v = IPVERSION; + ip->ip_tos = oip->ip_tos; + ip->ip_id = oip->ip_id; + ip->ip_off = 0; +# if (BSD < 199306) || defined(__sgi) + ip->ip_ttl = tcp_ttl; +# else + ip->ip_ttl = ip_defttl; +# endif + ip->ip_sum = 0; + } +# ifdef USE_INET6 + else if (ip->ip_v == 6) { + ip6_t *ip6 = (ip6_t *)ip; + + ip6->ip6_hlim = 127; + + return ip6_output(m, NULL, NULL, 0, NULL, NULL); + } +# endif +# ifdef IPSEC + m->m_pkthdr.rcvif = NULL; +# endif + return ipfr_fastroute(m, fin, NULL); +} + + +int send_icmp_err(oip, type, fin, dst) +ip_t *oip; +int type; +fr_info_t *fin; +int dst; +{ + int err, hlen = 0, xtra = 0, iclen, ohlen = 0, avail, code; + struct in_addr dst4; + struct icmp *icmp; + struct mbuf *m; + void *ifp; +#ifdef USE_INET6 + ip6_t *ip6, *oip6 = (ip6_t *)oip; + struct in6_addr dst6; +#endif + ip_t *ip; + + if ((type < 0) || (type > ICMP_MAXTYPE)) + return -1; + + code = fin->fin_icode; +#ifdef USE_INET6 + if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) + return -1; +#endif + + avail = 0; + m = NULL; + ifp = fin->fin_ifp; + if (fin->fin_v == 4) { +# if (BSD < 199306) || defined(__sgi) + avail = MLEN; + m = m_get(M_DONTWAIT, MT_HEADER); +# else + avail = MHLEN; + m = m_gethdr(M_DONTWAIT, MT_HEADER); +# endif + if (m == NULL) + return ENOBUFS; + + if (dst == 0) { + if (fr_ifpaddr(4, ifp, &dst4) == -1) + return -1; + } else + dst4.s_addr = oip->ip_dst.s_addr; + + hlen = sizeof(ip_t); + ohlen = oip->ip_hl << 2; + xtra = 8; + } + +#ifdef USE_INET6 + else if (fin->fin_v == 6) { + hlen = sizeof(ip6_t); + ohlen = sizeof(ip6_t); + type = icmptoicmp6types[type]; + if (type == ICMP6_DST_UNREACH) + code = icmptoicmp6unreach[code]; + + MGETHDR(m, M_DONTWAIT, MT_HEADER); + if (!m) + return ENOBUFS; + + MCLGET(m, M_DONTWAIT); + if (!m) + return ENOBUFS; + avail = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN; + xtra = MIN(ntohs(oip6->ip6_plen) + sizeof(ip6_t), + avail - hlen - sizeof(*icmp) - max_linkhdr); + if (dst == 0) { + if (fr_ifpaddr(6, ifp, (struct in_addr *)&dst6) == -1) + return -1; + } else + dst6 = oip6->ip6_dst; + } +#endif + + iclen = hlen + sizeof(*icmp); +# if BSD >= 199306 + avail -= (max_linkhdr + iclen); + m->m_data += max_linkhdr; + m->m_pkthdr.rcvif = (struct ifnet *)0; + if (xtra > avail) + xtra = avail; + iclen += xtra; + m->m_pkthdr.len = iclen; +#else + avail -= (m->m_off + iclen); + if (xtra > avail) + xtra = avail; + iclen += xtra; +#endif + m->m_len = iclen; + ip = mtod(m, ip_t *); + icmp = (struct icmp *)((char *)ip + hlen); + bzero((char *)ip, iclen); + + icmp->icmp_type = type; + icmp->icmp_code = fin->fin_icode; + icmp->icmp_cksum = 0; + if (avail) { + bcopy((char *)oip, (char *)&icmp->icmp_ip, MIN(ohlen, avail)); + avail -= MIN(ohlen, avail); + } + +#ifdef USE_INET6 + ip6 = (ip6_t *)ip; + if (fin->fin_v == 6) { + ip6->ip6_flow = 0; + ip6->ip6_plen = htons(iclen - hlen); + ip6->ip6_nxt = IPPROTO_ICMPV6; + ip6->ip6_hlim = 0; + ip6->ip6_src = dst6; + ip6->ip6_dst = oip6->ip6_src; + if (avail) + bcopy((char *)oip + ohlen, + (char *)&icmp->icmp_ip + ohlen, avail); + icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6, + sizeof(*ip6), iclen - hlen); + } else +#endif + { + ip->ip_src.s_addr = dst4.s_addr; + ip->ip_dst.s_addr = oip->ip_src.s_addr; + + if (avail > 8) + avail = 8; + if (avail) + bcopy((char *)oip + ohlen, + (char *)&icmp->icmp_ip + ohlen, avail); + icmp->icmp_cksum = ipf_cksum((u_short *)icmp, + sizeof(*icmp) + 8); + ip->ip_len = iclen; + ip->ip_p = IPPROTO_ICMP; + } + err = send_ip(oip, fin, m); + return err; +} + + +# if !defined(IPFILTER_LKM) && (__FreeBSD_version < 300000) && !defined(__sgi) +# if (BSD < 199306) +int iplinit __P((void)); + +int +# else +void iplinit __P((void)); + +void +# endif +iplinit() +{ + if (iplattach() != 0) + printf("IP Filter failed to attach\n"); + ip_init(); +} +# endif /* ! __NetBSD__ */ + + +size_t mbufchainlen(m0) +register struct mbuf *m0; +{ + register size_t len = 0; + + for (; m0; m0 = m0->m_next) + len += m0->m_len; + return len; +} + + +int ipfr_fastroute(m0, fin, fdp) +struct mbuf *m0; +fr_info_t *fin; +frdest_t *fdp; +{ + register struct ip *ip, *mhip; + register struct mbuf *m = m0; + register struct route *ro; + int len, off, error = 0, hlen, code; + struct ifnet *ifp, *sifp; + struct sockaddr_in *dst; + struct route iproute; + frentry_t *fr; + + hlen = fin->fin_hlen; + ip = mtod(m0, struct ip *); + +#ifdef USE_INET6 + if (ip->ip_v == 6) { + /* + * currently "to " and "to :ip#" are not supported + * for IPv6 + */ + return ip6_output(m0, NULL, NULL, 0, NULL, NULL); + } +#endif + /* + * Route packet. + */ + ro = &iproute; + bzero((caddr_t)ro, sizeof (*ro)); + dst = (struct sockaddr_in *)&ro->ro_dst; + dst->sin_family = AF_INET; + + fr = fin->fin_fr; + if (fdp) + ifp = fdp->fd_ifp; + else { + ifp = fin->fin_ifp; + dst->sin_addr = ip->ip_dst; + } + + /* + * In case we're here due to "to " being used with "keep state", + * check that we're going in the correct direction. + */ + if ((fr != NULL) && (fin->fin_rev != 0)) { + if ((ifp != NULL) && (fdp == &fr->fr_tif)) + return -1; + dst->sin_addr = ip->ip_dst; + } else if (fdp) + dst->sin_addr = fdp->fd_ip.s_addr ? fdp->fd_ip : ip->ip_dst; + +# if BSD >= 199306 + dst->sin_len = sizeof(*dst); +# endif +# if (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \ + !defined(__OpenBSD__) +# ifdef RTF_CLONING + rtalloc_ign(ro, RTF_CLONING); +# else + rtalloc_ign(ro, RTF_PRCLONING); +# endif +# else + rtalloc(ro); +# endif + if (!ifp) { + if (!fr || !(fr->fr_flags & FR_FASTROUTE)) { + error = -2; + goto bad; + } + if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) { + if (in_localaddr(ip->ip_dst)) + error = EHOSTUNREACH; + else + error = ENETUNREACH; + goto bad; + } + if (ro->ro_rt->rt_flags & RTF_GATEWAY) + dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway; + } + if (ro->ro_rt) + ro->ro_rt->rt_use++; + + /* + * For input packets which are being "fastrouted", they won't + * go back through output filtering and miss their chance to get + * NAT'd and counted. + */ + fin->fin_ifp = ifp; + if (fin->fin_out == 0) { + fin->fin_out = 1; + if ((fin->fin_fr = ipacct[1][fr_active]) && + (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { + ATOMIC_INCL(frstats[1].fr_acct); + } + fin->fin_fr = NULL; + if (!fr || !(fr->fr_flags & FR_RETMASK)) { + (void) fr_checkstate(ip, fin); + (void) ip_natout(ip, fin); + } + } else + ip->ip_sum = 0; + /* + * If small enough for interface, can just send directly. + */ + if (ip->ip_len <= ifp->if_mtu) { +# if BSD >= 199306 + int i = 0; + +# ifdef MCLISREFERENCED + if ((m->m_flags & M_EXT) && MCLISREFERENCED(m)) +# else + if (m->m_flags & M_EXT) +# endif + i = 1; +# endif +# ifndef sparc + ip->ip_id = htons(ip->ip_id); + ip->ip_len = htons(ip->ip_len); + ip->ip_off = htons(ip->ip_off); +# endif + if (!ip->ip_sum) + ip->ip_sum = in_cksum(m, hlen); +# if BSD >= 199306 + error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, + ro->ro_rt); + if (i) { + ip->ip_id = ntohs(ip->ip_id); + ip->ip_len = ntohs(ip->ip_len); + ip->ip_off = ntohs(ip->ip_off); + } +# else + error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst); +# endif + goto done; + } + /* + * Too large for interface; fragment if possible. + * Must be able to put at least 8 bytes per fragment. + */ + if (ip->ip_off & IP_DF) { + error = EMSGSIZE; + goto bad; + } + len = (ifp->if_mtu - hlen) &~ 7; + if (len < 8) { + error = EMSGSIZE; + goto bad; + } + + { + int mhlen, firstlen = len; + struct mbuf **mnext = &m->m_act; + + /* + * Loop through length of segment after first fragment, + * make new header and copy data of each part and link onto chain. + */ + m0 = m; + mhlen = sizeof (struct ip); + for (off = hlen + len; off < ip->ip_len; off += len) { +# ifdef MGETHDR + MGETHDR(m, M_DONTWAIT, MT_HEADER); +# else + MGET(m, M_DONTWAIT, MT_HEADER); +# endif + if (m == 0) { + error = ENOBUFS; + goto bad; + } +# if BSD >= 199306 + m->m_data += max_linkhdr; +# else + m->m_off = MMAXOFF - hlen; +# endif + mhip = mtod(m, struct ip *); + bcopy((char *)ip, (char *)mhip, sizeof(*ip)); + if (hlen > sizeof (struct ip)) { + mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); + mhip->ip_hl = mhlen >> 2; + } + m->m_len = mhlen; + mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); + if (ip->ip_off & IP_MF) + mhip->ip_off |= IP_MF; + if (off + len >= ip->ip_len) + len = ip->ip_len - off; + else + mhip->ip_off |= IP_MF; + mhip->ip_len = htons((u_short)(len + mhlen)); + m->m_next = m_copy(m0, off, len); + if (m->m_next == 0) { + error = ENOBUFS; /* ??? */ + goto sendorfree; + } +# if BSD >= 199306 + m->m_pkthdr.len = mhlen + len; + m->m_pkthdr.rcvif = NULL; +# endif +# ifndef sparc + mhip->ip_off = htons((u_short)mhip->ip_off); +# endif + mhip->ip_sum = 0; + mhip->ip_sum = in_cksum(m, mhlen); + *mnext = m; + mnext = &m->m_act; + } + /* + * Update first fragment by trimming what's been copied out + * and updating header, then send each fragment (in order). + */ + m_adj(m0, hlen + firstlen - ip->ip_len); + ip->ip_len = htons((u_short)(hlen + firstlen)); + ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); + ip->ip_sum = 0; + ip->ip_sum = in_cksum(m0, hlen); +sendorfree: + for (m = m0; m; m = m0) { + m0 = m->m_act; + m->m_act = 0; + if (error == 0) +# if BSD >= 199306 + error = (*ifp->if_output)(ifp, m, + (struct sockaddr *)dst, ro->ro_rt); +# else + error = (*ifp->if_output)(ifp, m, + (struct sockaddr *)dst); +# endif + else + m_freem(m); + } + } +done: + if (!error) + ipl_frouteok[0]++; + else + ipl_frouteok[1]++; + + if (ro->ro_rt) + RTFREE(ro->ro_rt); + return 0; +bad: + if (error == EMSGSIZE) { + sifp = fin->fin_ifp; + code = fin->fin_icode; + fin->fin_icode = ICMP_UNREACH_NEEDFRAG; + fin->fin_ifp = ifp; + (void) send_icmp_err(ip, ICMP_UNREACH, fin, 1); + fin->fin_ifp = sifp; + fin->fin_icode = code; + } + m_freem(m); + goto done; +} + + +int fr_verifysrc(ipa, ifp) +struct in_addr ipa; +void *ifp; +{ + struct sockaddr_in *dst; + struct route iproute; + + bzero((char *)&iproute, sizeof(iproute)); + dst = (struct sockaddr_in *)&iproute.ro_dst; + dst->sin_family = AF_INET; + dst->sin_addr = ipa; +# if (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \ + !defined(__OpenBSD__) +# ifdef RTF_CLONING + rtalloc_ign(&iproute, RTF_CLONING); +# else + rtalloc_ign(&iproute, RTF_PRCLONING); +# endif +# else + rtalloc(&iproute); +# endif + if (iproute.ro_rt == NULL) + return 0; + return (ifp == iproute.ro_rt->rt_ifp); +} + +#else /* #ifdef _KERNEL */ + + +# ifdef __sgi +static int no_output __P((struct ifnet *ifp, struct mbuf *m, + struct sockaddr *s)) +# else +static int no_output __P((struct ifnet *ifp, struct mbuf *m, + struct sockaddr *s, struct rtentry *rt)) +# endif +{ + return 0; +} + + +# ifdef __STDC__ +# ifdef __sgi +static int write_output __P((struct ifnet *ifp, struct mbuf *m, + struct sockaddr *s)) +# else +static int write_output __P((struct ifnet *ifp, struct mbuf *m, + struct sockaddr *s, struct rtentry *rt)) +# endif +{ + ip_t *ip = (ip_t *)m; +# else +static int write_output(ifp, ip) +struct ifnet *ifp; +ip_t *ip; +{ +# endif + char fname[32]; + int fd; + +# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) + sprintf(fname, "/tmp/%s", ifp->if_xname); +# else + sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit); +# endif + fd = open(fname, O_WRONLY|O_APPEND); + if (fd == -1) { + perror("open"); + return -1; + } + write(fd, (char *)ip, ntohs(ip->ip_len)); + close(fd); + return 0; +} + + +struct ifnet *get_unit(name, v) +char *name; +int v; +{ + struct ifnet *ifp, **ifa; +# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) + for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { + if (!strcmp(name, ifp->if_xname)) + return ifp; + } +# else + char ifname[32], *s; + + for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { + (void) sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit); + if (!strcmp(name, ifname)) + return ifp; + } +# endif + + if (!ifneta) { + ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2); + ifneta[1] = NULL; + ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp)); + nifs = 1; + } else { + nifs++; + ifneta = (struct ifnet **)realloc(ifneta, + (nifs + 1) * sizeof(*ifa)); + ifneta[nifs] = NULL; + ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp)); + } + ifp = ifneta[nifs - 1]; + +# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) + strncpy(ifp->if_xname, name, sizeof(ifp->if_xname)); +# else + for (s = name; *s && !isdigit(*s); s++) + ; + if (*s && isdigit(*s)) { + ifp->if_unit = atoi(s); + ifp->if_name = (char *)malloc(s - name + 1); + strncpy(ifp->if_name, name, s - name); + ifp->if_name[s - name] = '\0'; + } else { + ifp->if_name = strdup(name); + ifp->if_unit = -1; + } +# endif + ifp->if_output = no_output; + return ifp; +} + + + +void init_ifp() +{ + struct ifnet *ifp, **ifa; + char fname[32]; + int fd; + +# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) + for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { + ifp->if_output = write_output; + sprintf(fname, "/tmp/%s", ifp->if_xname); + fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); + if (fd == -1) + perror("open"); + else + close(fd); + } +# else + + for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { + ifp->if_output = write_output; + sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit); + fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); + if (fd == -1) + perror("open"); + else + close(fd); + } +# endif +} + + +int ipfr_fastroute(ip, fin, fdp) +ip_t *ip; +fr_info_t *fin; +frdest_t *fdp; +{ + struct ifnet *ifp = fdp->fd_ifp; + + if (!ifp) + return 0; /* no routing table out here */ + + ip->ip_len = htons((u_short)ip->ip_len); + ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); + ip->ip_sum = 0; +#ifdef __sgi + (*ifp->if_output)(ifp, (void *)ip, NULL); +#else + (*ifp->if_output)(ifp, (void *)ip, NULL, 0); +#endif + return 0; +} + + +int ipllog __P((void)) +{ + verbose("l"); + return 0; +} + + +int send_reset(ip, ifp) +ip_t *ip; +struct ifnet *ifp; +{ + verbose("- TCP RST sent\n"); + return 0; +} + + +int icmp_error(ip, ifp) +ip_t *ip; +struct ifnet *ifp; +{ + verbose("- TCP RST sent\n"); + return 0; +} + + +void frsync() +{ + return; +} +#endif /* _KERNEL */ Property changes on: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_fil.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_fil.h =================================================================== --- vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_fil.h (nonexistent) +++ vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_fil.h (revision 60849) @@ -0,0 +1,630 @@ +/* + * 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. + * + * @(#)ip_fil.h 1.35 6/5/96 + * $Id: ip_fil.h,v 2.29.2.2 2000/05/22 10:26:13 darrenr Exp $ + */ + +#ifndef __IP_FIL_H__ +#define __IP_FIL_H__ + +/* + * Pathnames for various IP Filter control devices. Used by LKM + * and userland, so defined here. + */ +#define IPNAT_NAME "/dev/ipnat" +#define IPSTATE_NAME "/dev/ipstate" +#define IPAUTH_NAME "/dev/ipauth" + +#ifndef SOLARIS +# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +#endif + +#if defined(KERNEL) && !defined(_KERNEL) +# define _KERNEL +#endif + +#ifndef __P +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif + +#if defined(__STDC__) || defined(__GNUC__) +# define SIOCADAFR _IOW('r', 60, struct frentry *) +# define SIOCRMAFR _IOW('r', 61, struct frentry *) +# define SIOCSETFF _IOW('r', 62, u_int) +# define SIOCGETFF _IOR('r', 63, u_int) +# define SIOCGETFS _IOWR('r', 64, struct friostat *) +# define SIOCIPFFL _IOWR('r', 65, int) +# define SIOCIPFFB _IOR('r', 66, int) +# define SIOCADIFR _IOW('r', 67, struct frentry *) +# define SIOCRMIFR _IOW('r', 68, struct frentry *) +# define SIOCSWAPA _IOR('r', 69, u_int) +# define SIOCINAFR _IOW('r', 70, struct frentry *) +# define SIOCINIFR _IOW('r', 71, struct frentry *) +# define SIOCFRENB _IOW('r', 72, u_int) +# define SIOCFRSYN _IOW('r', 73, u_int) +# define SIOCFRZST _IOWR('r', 74, struct friostat *) +# define SIOCZRLST _IOWR('r', 75, struct frentry *) +# define SIOCAUTHW _IOWR('r', 76, struct fr_info *) +# define SIOCAUTHR _IOWR('r', 77, struct fr_info *) +# define SIOCATHST _IOWR('r', 78, struct fr_authstat *) +# define SIOCSTLCK _IOWR('r', 79, u_int) +# define SIOCSTPUT _IOWR('r', 80, struct ipstate_save *) +# define SIOCSTGET _IOWR('r', 81, struct ipstate_save *) +# define SIOCSTGSZ _IOWR('r', 82, struct natget *) +# define SIOCGFRST _IOWR('r', 83, struct ipfrstat *) +#else +# define SIOCADAFR _IOW(r, 60, struct frentry *) +# define SIOCRMAFR _IOW(r, 61, struct frentry *) +# define SIOCSETFF _IOW(r, 62, u_int) +# define SIOCGETFF _IOR(r, 63, u_int) +# define SIOCGETFS _IOWR(r, 64, struct friostat *) +# define SIOCIPFFL _IOWR(r, 65, int) +# define SIOCIPFFB _IOR(r, 66, int) +# define SIOCADIFR _IOW(r, 67, struct frentry *) +# define SIOCRMIFR _IOW(r, 68, struct frentry *) +# define SIOCSWAPA _IOR(r, 69, u_int) +# define SIOCINAFR _IOW(r, 70, struct frentry *) +# define SIOCINIFR _IOW(r, 71, struct frentry *) +# define SIOCFRENB _IOW(r, 72, u_int) +# define SIOCFRSYN _IOW(r, 73, u_int) +# define SIOCFRZST _IOWR(r, 74, struct friostat *) +# define SIOCZRLST _IOWR(r, 75, struct frentry *) +# define SIOCAUTHW _IOWR(r, 76, struct fr_info *) +# define SIOCAUTHR _IOWR(r, 77, struct fr_info *) +# define SIOCATHST _IOWR(r, 78, struct fr_authstat *) +# define SIOCSTLCK _IOWR(r, 79, u_int) +# define SIOCSTPUT _IOWR(r, 80, struct ipstate_save *) +# define SIOCSTGET _IOWR(r, 81, struct ipstate_save *) +# define SIOCSTGSZ _IOWR(r, 82, struct natget *) +# define SIOCGFRST _IOWR(r, 83, struct ipfrstat *) +#endif +#define SIOCADDFR SIOCADAFR +#define SIOCDELFR SIOCRMAFR +#define SIOCINSFR SIOCINAFR + + +typedef struct fr_ip { + u_32_t fi_v:4; /* IP version */ + u_32_t fi_fl:4; /* packet flags */ + u_32_t fi_tos:8; /* IP packet TOS */ + u_32_t fi_ttl:8; /* IP packet TTL */ + u_32_t fi_p:8; /* IP packet protocol */ + union i6addr fi_src; /* source address from packet */ + union i6addr fi_dst; /* destination address from packet */ + u_32_t fi_optmsk; /* bitmask composed from IP options */ + u_short fi_secmsk; /* bitmask composed from IP security options */ + u_short fi_auth; /* authentication code from IP sec. options */ +} fr_ip_t; + +#define FI_OPTIONS (FF_OPTIONS >> 24) +#define FI_TCPUDP (FF_TCPUDP >> 24) /* TCP/UCP implied comparison*/ +#define FI_FRAG (FF_FRAG >> 24) +#define FI_SHORT (FF_SHORT >> 24) +#define FI_CMP (FI_OPTIONS|FI_TCPUDP|FI_SHORT) + +#define fi_saddr fi_src.in4.s_addr +#define fi_daddr fi_dst.in4.s_addr + + +/* + * These are both used by the state and NAT code to indicate that one port or + * the other should be treated as a wildcard. + */ +#define FI_W_SPORT 0x00000100 +#define FI_W_DPORT 0x00000200 +#define FI_WILDP (FI_W_SPORT|FI_W_DPORT) +#define FI_W_SADDR 0x00000400 +#define FI_W_DADDR 0x00000800 +#define FI_WILDA (FI_W_SADDR|FI_W_DADDR) +#define FI_NEWFR 0x00001000 + +typedef struct fr_info { + void *fin_ifp; /* interface packet is `on' */ + struct fr_ip fin_fi; /* IP Packet summary */ + u_short fin_data[2]; /* TCP/UDP ports, ICMP code/type */ + u_char fin_out; /* in or out ? 1 == out, 0 == in */ + u_char fin_rev; /* state only: 1 = reverse */ + u_short fin_hlen; /* length of IP header in bytes */ + u_char fin_tcpf; /* TCP header flags (SYN, ACK, etc) */ + /* From here on is packet specific */ + u_char fin_icode; /* ICMP error to return */ + u_short fin_rule; /* rule # last matched */ + u_32_t fin_group; /* group number, -1 for none */ + struct frentry *fin_fr; /* last matching rule */ + char *fin_dp; /* start of data past IP header */ + u_short fin_dlen; /* length of data portion of packet */ + u_short fin_id; /* IP packet id field */ + void *fin_mp; /* pointer to pointer to mbuf */ +#if SOLARIS + void *fin_qfm; /* pointer to mblk where pkt starts */ + void *fin_qif; +#endif + u_short fin_plen; + u_short fin_off; +} fr_info_t; + +#define fin_v fin_fi.fi_v + +/* + * Size for compares on fr_info structures + */ +#define FI_CSIZE offsetof(fr_info_t, fin_icode) + +/* + * Size for copying cache fr_info structure + */ +#define FI_COPYSIZE offsetof(fr_info_t, fin_dp) + +typedef struct frdest { + void *fd_ifp; + struct in_addr fd_ip; + char fd_ifname[IFNAMSIZ]; +} frdest_t; + +typedef struct frpcmp { + int frp_cmp; /* data for port comparisons */ + u_short frp_port; /* top port for <> and >< */ + u_short frp_top; /* top port for <> and >< */ +} frpcmp_t; + +typedef struct frtuc { + u_char ftu_tcpfm; /* tcp flags mask */ + u_char ftu_tcpf; /* tcp flags */ + frpcmp_t ftu_src; + frpcmp_t ftu_dst; +} frtuc_t; + +#define ftu_scmp ftu_src.frp_cmp +#define ftu_dcmp ftu_dst.frp_cmp +#define ftu_sport ftu_src.frp_port +#define ftu_dport ftu_dst.frp_port +#define ftu_stop ftu_src.frp_top +#define ftu_dtop ftu_dst.frp_top + +typedef struct frentry { + struct frentry *fr_next; + u_32_t fr_group; /* group to which this rule belongs */ + u_32_t fr_grhead; /* group # which this rule starts */ + struct frentry *fr_grp; + int fr_ref; /* reference count - for grouping */ + void *fr_ifa; +#if BSD >= 199306 + void *fr_oifa; +#endif + /* + * These are only incremented when a packet matches this rule and + * it is the last match + */ + U_QUAD_T fr_hits; + U_QUAD_T fr_bytes; + /* + * Fields after this may not change whilst in the kernel. + */ + struct fr_ip fr_ip; + struct fr_ip fr_mip; /* mask structure */ + + + u_short fr_icmpm; /* data for ICMP packets (mask) */ + u_short fr_icmp; + + frtuc_t fr_tuc; + u_32_t fr_flags; /* per-rule flags && options (see below) */ + u_int fr_skip; /* # of rules to skip */ + u_int fr_loglevel; /* syslog log facility + priority */ + int (*fr_func) __P((int, ip_t *, fr_info_t *)); /* call this function */ + int fr_sap; /* For solaris only */ + u_char fr_icode; /* return ICMP code */ + char fr_ifname[IFNAMSIZ]; +#if BSD >= 199306 + char fr_oifname[IFNAMSIZ]; +#endif + struct frdest fr_tif; /* "to" interface */ + struct frdest fr_dif; /* duplicate packet interfaces */ + u_int fr_cksum; /* checksum on filter rules for performance */ +} frentry_t; + +#define fr_v fr_ip.fi_v +#define fr_proto fr_ip.fi_p +#define fr_ttl fr_ip.fi_ttl +#define fr_tos fr_ip.fi_tos +#define fr_tcpfm fr_tuc.ftu_tcpfm +#define fr_tcpf fr_tuc.ftu_tcpf +#define fr_scmp fr_tuc.ftu_scmp +#define fr_dcmp fr_tuc.ftu_dcmp +#define fr_dport fr_tuc.ftu_dport +#define fr_sport fr_tuc.ftu_sport +#define fr_stop fr_tuc.ftu_stop +#define fr_dtop fr_tuc.ftu_dtop +#define fr_dst fr_ip.fi_dst.in4 +#define fr_src fr_ip.fi_src.in4 +#define fr_dmsk fr_mip.fi_dst.in4 +#define fr_smsk fr_mip.fi_src.in4 + +#ifndef offsetof +#define offsetof(t,m) (int)((&((t *)0L)->m)) +#endif +#define FR_CMPSIZ (sizeof(struct frentry) - offsetof(frentry_t, fr_ip)) + +/* + * fr_flags + */ +#define FR_BLOCK 0x00001 /* do not allow packet to pass */ +#define FR_PASS 0x00002 /* allow packet to pass */ +#define FR_OUTQUE 0x00004 /* outgoing packets */ +#define FR_INQUE 0x00008 /* ingoing packets */ +#define FR_LOG 0x00010 /* Log */ +#define FR_LOGB 0x00011 /* Log-fail */ +#define FR_LOGP 0x00012 /* Log-pass */ +#define FR_LOGBODY 0x00020 /* Log the body */ +#define FR_LOGFIRST 0x00040 /* Log the first byte if state held */ +#define FR_RETRST 0x00080 /* Return TCP RST packet - reset connection */ +#define FR_RETICMP 0x00100 /* Return ICMP unreachable packet */ +#define FR_FAKEICMP 0x00180 /* Return ICMP unreachable with fake source */ +#define FR_NOMATCH 0x00200 /* no match occured */ +#define FR_ACCOUNT 0x00400 /* count packet bytes */ +#define FR_KEEPFRAG 0x00800 /* keep fragment information */ +#define FR_KEEPSTATE 0x01000 /* keep `connection' state information */ +#define FR_INACTIVE 0x02000 +#define FR_QUICK 0x04000 /* match & stop processing list */ +#define FR_FASTROUTE 0x08000 /* bypass normal routing */ +#define FR_CALLNOW 0x10000 /* call another function (fr_func) if matches */ +#define FR_DUP 0x20000 /* duplicate packet */ +#define FR_LOGORBLOCK 0x40000 /* block the packet if it can't be logged */ +#define FR_NOTSRCIP 0x80000 /* not the src IP# */ +#define FR_NOTDSTIP 0x100000 /* not the dst IP# */ +#define FR_AUTH 0x200000 /* use authentication */ +#define FR_PREAUTH 0x400000 /* require preauthentication */ +#define FR_DONTCACHE 0x800000 /* don't cache the result */ + +#define FR_LOGMASK (FR_LOG|FR_LOGP|FR_LOGB) +#define FR_RETMASK (FR_RETICMP|FR_RETRST|FR_FAKEICMP) + +/* + * These correspond to #define's for FI_* and are stored in fr_flags + */ +#define FF_OPTIONS 0x01000000 +#define FF_TCPUDP 0x02000000 +#define FF_FRAG 0x04000000 +#define FF_SHORT 0x08000000 +/* + * recognized flags for SIOCGETFF and SIOCSETFF, and get put in fr_flags + */ +#define FF_LOGPASS 0x10000000 +#define FF_LOGBLOCK 0x20000000 +#define FF_LOGNOMATCH 0x40000000 +#define FF_LOGGING (FF_LOGPASS|FF_LOGBLOCK|FF_LOGNOMATCH) +#define FF_BLOCKNONIP 0x80000000 /* Solaris2 Only */ + +#define FR_NONE 0 +#define FR_EQUAL 1 +#define FR_NEQUAL 2 +#define FR_LESST 3 +#define FR_GREATERT 4 +#define FR_LESSTE 5 +#define FR_GREATERTE 6 +#define FR_OUTRANGE 7 +#define FR_INRANGE 8 + +typedef struct filterstats { + u_long fr_pass; /* packets allowed */ + u_long fr_block; /* packets denied */ + u_long fr_nom; /* packets which don't match any rule */ + u_long fr_short; /* packets which are short */ + u_long fr_ppkl; /* packets allowed and logged */ + u_long fr_bpkl; /* packets denied and logged */ + u_long fr_npkl; /* packets unmatched and logged */ + u_long fr_pkl; /* packets logged */ + u_long fr_skip; /* packets to be logged but buffer full */ + u_long fr_ret; /* packets for which a return is sent */ + u_long fr_acct; /* packets for which counting was performed */ + u_long fr_bnfr; /* bad attempts to allocate fragment state */ + u_long fr_nfr; /* new fragment state kept */ + u_long fr_cfr; /* add new fragment state but complete pkt */ + u_long fr_bads; /* bad attempts to allocate packet state */ + u_long fr_ads; /* new packet state kept */ + u_long fr_chit; /* cached hit */ + u_long fr_tcpbad; /* TCP checksum check failures */ + u_long fr_pull[2]; /* good and bad pullup attempts */ + u_long fr_badsrc; /* source received doesn't match route */ +#if SOLARIS + u_long fr_notdata; /* PROTO/PCPROTO that have no data */ + u_long fr_nodata; /* mblks that have no data */ + u_long fr_bad; /* bad IP packets to the filter */ + u_long fr_notip; /* packets passed through no on ip queue */ + u_long fr_drop; /* packets dropped - no info for them! */ + u_long fr_copy; /* messages copied due to db_ref > 1 */ +#endif + u_long fr_ipv6[2]; /* IPv6 packets in/out */ +} filterstats_t; + +/* + * For SIOCGETFS + */ +typedef struct friostat { + struct filterstats f_st[2]; + struct frentry *f_fin[2]; + struct frentry *f_fout[2]; + struct frentry *f_acctin[2]; + struct frentry *f_acctout[2]; + struct frentry *f_fin6[2]; + struct frentry *f_fout6[2]; + struct frentry *f_acctin6[2]; + struct frentry *f_acctout6[2]; + struct frentry *f_auth; + struct frgroup *f_groups[3][2]; + u_long f_froute[2]; + int f_defpass; /* default pass - from fr_pass */ + char f_active; /* 1 or 0 - active rule set */ + char f_running; /* 1 if running, else 0 */ + char f_logging; /* 1 if enabled, else 0 */ + char f_version[32]; /* version string */ + int f_locks[4]; +} friostat_t; + +typedef struct optlist { + u_short ol_val; + int ol_bit; +} optlist_t; + + +/* + * Group list structure. + */ +typedef struct frgroup { + u_32_t fg_num; + struct frgroup *fg_next; + struct frentry *fg_head; + struct frentry **fg_start; +} frgroup_t; + + +/* + * Log structure. Each packet header logged is prepended by one of these. + * Following this in the log records read from the device will be an ipflog + * structure which is then followed by any packet data. + */ +typedef struct iplog { + u_32_t ipl_magic; + u_int ipl_count; + u_long ipl_sec; + u_long ipl_usec; + size_t ipl_dsize; + struct iplog *ipl_next; +} iplog_t; + +#define IPL_MAGIC 0x49504c4d /* 'IPLM' */ + +typedef struct ipflog { +#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) + u_char fl_ifname[IFNAMSIZ]; +#else + u_int fl_unit; + u_char fl_ifname[4]; +#endif + u_char fl_plen; /* extra data after hlen */ + u_char fl_hlen; /* length of IP headers saved */ + u_short fl_loglevel; /* syslog log level */ + u_32_t fl_rule; + u_32_t fl_group; + u_32_t fl_flags; + u_32_t fl_lflags; +} ipflog_t; + + +#ifndef ICMP_UNREACH_FILTER +# define ICMP_UNREACH_FILTER 13 +#endif + +#ifndef IPF_LOGGING +# define IPF_LOGGING 0 +#endif +#ifndef IPF_DEFAULT_PASS +# define IPF_DEFAULT_PASS FR_PASS +#endif + +#define IPMINLEN(i, h) ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h))) +#define IPLLOGSIZE 8192 + +/* + * Device filenames for reading log information. Use ipf on Solaris2 because + * ipl is already a name used by something else. + */ +#ifndef IPL_NAME +# if SOLARIS +# define IPL_NAME "/dev/ipf" +# else +# define IPL_NAME "/dev/ipl" +# endif +#endif +#define IPL_NAT IPNAT_NAME +#define IPL_STATE IPSTATE_NAME +#define IPL_AUTH IPAUTH_NAME + +#define IPL_LOGIPF 0 /* Minor device #'s for accessing logs */ +#define IPL_LOGNAT 1 +#define IPL_LOGSTATE 2 +#define IPL_LOGAUTH 3 +#define IPL_LOGMAX 3 + +#if !defined(CDEV_MAJOR) && defined (__FreeBSD_version) && \ + (__FreeBSD_version >= 220000) +# define CDEV_MAJOR 79 +#endif + +/* + * Post NetBSD 1.2 has the PFIL interface for packet filters. This turns + * on those hooks. We don't need any special mods in non-IP Filter code + * with this! + */ +#if (defined(NetBSD) && (NetBSD > 199609) && (NetBSD <= 1991011)) || \ + (defined(NetBSD1_2) && NetBSD1_2 > 1) +# if (NetBSD >= 199905) +# define PFIL_HOOKS +# endif +# ifdef PFIL_HOOKS +# define NETBSD_PF +# endif +#endif + + +#ifndef _KERNEL +extern int fr_check __P((ip_t *, int, void *, int, mb_t **)); +extern int (*fr_checkp) __P((ip_t *, int, void *, int, mb_t **)); +extern int send_reset __P((ip_t *, struct ifnet *)); +extern int icmp_error __P((ip_t *, struct ifnet *)); +extern int ipf_log __P((void)); +extern int ipfr_fastroute __P((ip_t *, fr_info_t *, frdest_t *)); +extern struct ifnet *get_unit __P((char *, int)); +# if defined(__NetBSD__) || defined(__OpenBSD__) || \ + (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) +extern int iplioctl __P((dev_t, u_long, caddr_t, int)); +# else +extern int iplioctl __P((dev_t, int, caddr_t, int)); +# endif +extern int iplopen __P((dev_t, int)); +extern int iplclose __P((dev_t, int)); +#else /* #ifndef _KERNEL */ +# if defined(__NetBSD__) && defined(PFIL_HOOKS) +extern void ipfilterattach __P((int)); +# endif +extern int iplattach __P((void)); +extern int ipl_enable __P((void)); +extern int ipl_disable __P((void)); +extern void ipflog_init __P((void)); +extern int ipflog_clear __P((minor_t)); +extern int ipflog_read __P((minor_t, struct uio *)); +extern int ipflog __P((u_int, ip_t *, fr_info_t *, mb_t *)); +extern int ipllog __P((int, fr_info_t *, void **, size_t *, int *, int)); +extern int send_icmp_err __P((ip_t *, int, fr_info_t *, int)); +extern int send_reset __P((ip_t *, fr_info_t *)); +# if SOLARIS +extern int fr_check __P((ip_t *, int, void *, int, qif_t *, mb_t **)); +extern int (*fr_checkp) __P((ip_t *, int, void *, + int, qif_t *, mb_t **)); +# if SOLARIS2 >= 7 +extern int iplioctl __P((dev_t, int, intptr_t, int, cred_t *, int *)); +# else +extern int iplioctl __P((dev_t, int, int *, int, cred_t *, int *)); +# endif +extern int iplopen __P((dev_t *, int, int, cred_t *)); +extern int iplclose __P((dev_t, int, int, cred_t *)); +extern int ipfsync __P((void)); +extern int ipfr_fastroute __P((qif_t *, ip_t *, mblk_t *, mblk_t **, + fr_info_t *, frdest_t *)); +extern void copyin_mblk __P((mblk_t *, size_t, size_t, char *)); +extern void copyout_mblk __P((mblk_t *, size_t, size_t, char *)); +extern int fr_qin __P((queue_t *, mblk_t *)); +extern int fr_qout __P((queue_t *, mblk_t *)); +extern int iplread __P((dev_t, struct uio *, cred_t *)); +# else /* SOLARIS */ +extern int fr_check __P((ip_t *, int, void *, int, mb_t **)); +extern int (*fr_checkp) __P((ip_t *, int, void *, int, mb_t **)); +extern int send_reset __P((struct ip *, fr_info_t *)); +extern int send_icmp_err __P((ip_t *, int, fr_info_t *, int)); +extern int ipfr_fastroute __P((mb_t *, fr_info_t *, frdest_t *)); +extern size_t mbufchainlen __P((mb_t *)); +# ifdef __sgi +# include +extern int iplioctl __P((dev_t, int, caddr_t, int, cred_t *, int *)); +extern int iplopen __P((dev_t *, int, int, cred_t *)); +extern int iplclose __P((dev_t, int, int, cred_t *)); +extern int iplread __P((dev_t, struct uio *, cred_t *)); +extern int ipfsync __P((void)); +extern int ipfilter_sgi_attach __P((void)); +extern void ipfilter_sgi_detach __P((void)); +extern void ipfilter_sgi_intfsync __P((void)); +# else +# ifdef IPFILTER_LKM +extern int iplidentify __P((char *)); +# endif +# if (_BSDI_VERSION >= 199510) || (__FreeBSD_version >= 220000) || \ + (NetBSD >= 199511) || defined(__OpenBSD__) +# if defined(__NetBSD__) || (_BSDI_VERSION >= 199701) || \ + defined(__OpenBSD__) || (__FreeBSD_version >= 300000) +extern int iplioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); +# else +extern int iplioctl __P((dev_t, int, caddr_t, int, struct proc *)); +# endif +extern int iplopen __P((dev_t, int, int, struct proc *)); +extern int iplclose __P((dev_t, int, int, struct proc *)); +# else +# ifndef linux +extern int iplopen __P((dev_t, int)); +extern int iplclose __P((dev_t, int)); +extern int iplioctl __P((dev_t, int, caddr_t, int)); +# else +extern int iplioctl(struct inode *, struct file *, u_int, u_long); +extern int iplopen __P((struct inode *, struct file *)); +extern void iplclose __P((struct inode *, struct file *)); +# endif /* !linux */ +# endif /* (_BSDI_VERSION >= 199510) */ +# if BSD >= 199306 +extern int iplread __P((dev_t, struct uio *, int)); +# else +# ifndef linux +extern int iplread __P((dev_t, struct uio *)); +# else +extern int iplread(struct inode *, struct file *, char *, int); +# endif /* !linux */ +# endif /* BSD >= 199306 */ +# endif /* __ sgi */ +# endif /* SOLARIS */ +#endif /* #ifndef _KERNEL */ + +extern char *memstr __P((char *, char *, int, int)); +extern void fixskip __P((frentry_t **, frentry_t *, int)); +extern int countbits __P((u_32_t)); +extern int ipldetach __P((void)); +extern u_short ipf_cksum __P((u_short *, int)); +extern int ircopyptr __P((void *, void *, size_t)); +extern int iwcopyptr __P((void *, void *, size_t)); + +extern int frflush __P((minor_t, int)); +extern void frsync __P((void)); +extern frgroup_t *fr_addgroup __P((u_32_t, frentry_t *, minor_t, int)); +extern void fr_delgroup __P((u_32_t, u_32_t, minor_t, int)); +extern frgroup_t *fr_findgroup __P((u_32_t, u_32_t, minor_t, int, + frgroup_t ***)); + +extern int fr_copytolog __P((int, char *, int)); +extern void fr_forgetifp __P((void *)); +extern void fr_getstat __P((struct friostat *)); +extern int fr_ifpaddr __P((int, void *, struct in_addr *)); +extern int fr_lock __P((caddr_t, int *)); +extern void fr_makefrip __P((int, ip_t *, fr_info_t *)); +extern u_short fr_tcpsum __P((mb_t *, ip_t *, tcphdr_t *)); +extern int fr_scanlist __P((u_32_t, ip_t *, fr_info_t *, void *)); +extern int fr_tcpudpchk __P((frtuc_t *, fr_info_t *)); +extern int fr_verifysrc __P((struct in_addr, void *)); + +extern int ipl_unreach; +extern int fr_running; +extern u_long ipl_frouteok[2]; +extern int fr_pass; +extern int fr_flags; +extern int fr_active; +extern int fr_chksrc; +extern fr_info_t frcache[2]; +extern char ipfilter_version[]; +extern iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1]; +extern size_t iplused[IPL_LOGMAX + 1]; +extern struct frentry *ipfilter[2][2], *ipacct[2][2]; +#ifdef USE_INET6 +extern struct frentry *ipfilter6[2][2], *ipacct6[2][2]; +extern int icmptoicmp6types[ICMP_MAXTYPE+1]; +extern int icmptoicmp6unreach[ICMP_MAX_UNREACH]; +#endif +extern struct frgroup *ipfgroups[3][2]; +extern struct filterstats frstats[]; + +#endif /* __IP_FIL_H__ */ Property changes on: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_fil.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_frag.c =================================================================== --- vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_frag.c (nonexistent) +++ vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_frag.c (revision 60849) @@ -0,0 +1,550 @@ +/* + * 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. + */ +#if !defined(lint) +static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.10.2.3 2000/05/05 15:10:23 darrenr Exp $"; +#endif + +#if defined(KERNEL) && !defined(_KERNEL) +# define _KERNEL +#endif + +#include +#include +#include +#include +#include +#if !defined(_KERNEL) && !defined(KERNEL) +# include +# include +# include +#endif +#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) +# include +# include +#else +# include +#endif +#include +#ifndef linux +# include +#endif +#include +#if defined(_KERNEL) && !defined(linux) +# include +#endif +#if !defined(__SVR4) && !defined(__svr4__) +# if defined(_KERNEL) && !defined(__sgi) +# include +# endif +# ifndef linux +# include +# endif +#else +# include +# ifdef _KERNEL +# include +# endif +# include +# include +#endif +#include +#ifdef sun +# include +#endif +#include +#include +#include +#include +#ifndef linux +# include +#endif +#include +#include +#include +#include "netinet/ip_compat.h" +#include +#include "netinet/ip_fil.h" +#include "netinet/ip_proxy.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_frag.h" +#include "netinet/ip_state.h" +#include "netinet/ip_auth.h" +#if (__FreeBSD_version >= 300000) +# include +# if (defined(KERNEL) || defined(_KERNEL)) +# ifndef IPFILTER_LKM +# include +# include +# endif +extern struct callout_handle ipfr_slowtimer_ch; +# endif +#endif +#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) +# include +extern struct callout ipfr_slowtimer_ch; +#endif + + +static ipfr_t *ipfr_heads[IPFT_SIZE]; +static ipfr_t *ipfr_nattab[IPFT_SIZE]; +static ipfrstat_t ipfr_stats; +static int ipfr_inuse = 0; + +int fr_ipfrttl = 120; /* 60 seconds */ +int fr_frag_lock = 0; + +#ifdef _KERNEL +# if SOLARIS2 >= 7 +extern timeout_id_t ipfr_timer_id; +# else +extern int ipfr_timer_id; +# endif +#endif +#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) +extern KRWLOCK_T ipf_frag, ipf_natfrag, ipf_nat, ipf_mutex; +# if SOLARIS +extern KRWLOCK_T ipf_solaris; +# else +KRWLOCK_T ipf_solaris; +# endif +extern kmutex_t ipf_rw; +#endif + + +static ipfr_t *ipfr_new __P((ip_t *, fr_info_t *, u_int, ipfr_t **)); +static ipfr_t *ipfr_lookup __P((ip_t *, fr_info_t *, ipfr_t **)); +static void ipfr_delete __P((ipfr_t *)); + + +ipfrstat_t *ipfr_fragstats() +{ + ipfr_stats.ifs_table = ipfr_heads; + ipfr_stats.ifs_nattab = ipfr_nattab; + ipfr_stats.ifs_inuse = ipfr_inuse; + return &ipfr_stats; +} + + +/* + * add a new entry to the fragment cache, registering it as having come + * through this box, with the result of the filter operation. + */ +static ipfr_t *ipfr_new(ip, fin, pass, table) +ip_t *ip; +fr_info_t *fin; +u_int pass; +ipfr_t *table[]; +{ + ipfr_t **fp, *fra, frag; + u_int idx; + + frag.ipfr_p = ip->ip_p; + idx = ip->ip_p; + frag.ipfr_id = ip->ip_id; + idx += ip->ip_id; + frag.ipfr_tos = ip->ip_tos; + frag.ipfr_src.s_addr = ip->ip_src.s_addr; + idx += ip->ip_src.s_addr; + frag.ipfr_dst.s_addr = ip->ip_dst.s_addr; + idx += ip->ip_dst.s_addr; + idx *= 127; + idx %= IPFT_SIZE; + + /* + * first, make sure it isn't already there... + */ + for (fp = &table[idx]; (fra = *fp); fp = &fra->ipfr_next) + if (!bcmp((char *)&frag.ipfr_src, (char *)&fra->ipfr_src, + IPFR_CMPSZ)) { + ATOMIC_INCL(ipfr_stats.ifs_exists); + return NULL; + } + + /* + * allocate some memory, if possible, if not, just record that we + * failed to do so. + */ + KMALLOC(fra, ipfr_t *); + if (fra == NULL) { + ATOMIC_INCL(ipfr_stats.ifs_nomem); + return NULL; + } + + if ((fra->ipfr_rule = fin->fin_fr) != NULL) { + ATOMIC_INC32(fin->fin_fr->fr_ref); + } + + + /* + * Instert the fragment into the fragment table, copy the struct used + * in the search using bcopy rather than reassign each field. + * Set the ttl to the default and mask out logging from "pass" + */ + if ((fra->ipfr_next = table[idx])) + table[idx]->ipfr_prev = fra; + fra->ipfr_prev = NULL; + fra->ipfr_data = NULL; + table[idx] = fra; + bcopy((char *)&frag.ipfr_src, (char *)&fra->ipfr_src, IPFR_CMPSZ); + fra->ipfr_ttl = fr_ipfrttl; + /* + * Compute the offset of the expected start of the next packet. + */ + fra->ipfr_off = (ip->ip_off & IP_OFFMASK) + (fin->fin_dlen >> 3); + ATOMIC_INCL(ipfr_stats.ifs_new); + ATOMIC_INC32(ipfr_inuse); + return fra; +} + + +int ipfr_newfrag(ip, fin, pass) +ip_t *ip; +fr_info_t *fin; +u_int pass; +{ + ipfr_t *ipf; + + if ((ip->ip_v != 4) || (fr_frag_lock)) + return NULL; + WRITE_ENTER(&ipf_frag); + ipf = ipfr_new(ip, fin, pass, ipfr_heads); + RWLOCK_EXIT(&ipf_frag); + return ipf ? 0 : -1; +} + + +int ipfr_nat_newfrag(ip, fin, pass, nat) +ip_t *ip; +fr_info_t *fin; +u_int pass; +nat_t *nat; +{ + ipfr_t *ipf; + + if ((ip->ip_v != 4) || (fr_frag_lock)) + return NULL; + WRITE_ENTER(&ipf_natfrag); + ipf = ipfr_new(ip, fin, pass, ipfr_nattab); + if (ipf != NULL) { + ipf->ipfr_data = nat; + nat->nat_data = ipf; + } + RWLOCK_EXIT(&ipf_natfrag); + return ipf ? 0 : -1; +} + + +/* + * check the fragment cache to see if there is already a record of this packet + * with its filter result known. + */ +static ipfr_t *ipfr_lookup(ip, fin, table) +ip_t *ip; +fr_info_t *fin; +ipfr_t *table[]; +{ + ipfr_t *f, frag; + u_int idx; + + /* + * For fragments, we record protocol, packet id, TOS and both IP#'s + * (these should all be the same for all fragments of a packet). + * + * build up a hash value to index the table with. + */ + frag.ipfr_p = ip->ip_p; + idx = ip->ip_p; + frag.ipfr_id = ip->ip_id; + idx += ip->ip_id; + frag.ipfr_tos = ip->ip_tos; + frag.ipfr_src.s_addr = ip->ip_src.s_addr; + idx += ip->ip_src.s_addr; + frag.ipfr_dst.s_addr = ip->ip_dst.s_addr; + idx += ip->ip_dst.s_addr; + idx *= 127; + idx %= IPFT_SIZE; + + /* + * check the table, careful to only compare the right amount of data + */ + for (f = table[idx]; f; f = f->ipfr_next) + if (!bcmp((char *)&frag.ipfr_src, (char *)&f->ipfr_src, + IPFR_CMPSZ)) { + u_short atoff, off; + + if (f != table[idx]) { + /* + * move fragment info. to the top of the list + * to speed up searches. + */ + if ((f->ipfr_prev->ipfr_next = f->ipfr_next)) + f->ipfr_next->ipfr_prev = f->ipfr_prev; + f->ipfr_next = table[idx]; + table[idx]->ipfr_prev = f; + f->ipfr_prev = NULL; + table[idx] = f; + } + off = ip->ip_off & IP_OFFMASK; + atoff = off + (fin->fin_dlen >> 3); + /* + * If we've follwed the fragments, and this is the + * last (in order), shrink expiration time. + */ + if (off == f->ipfr_off) { + if (!(ip->ip_off & IP_MF)) + f->ipfr_ttl = 1; + else + f->ipfr_off = atoff; + } + ATOMIC_INCL(ipfr_stats.ifs_hits); + return f; + } + return NULL; +} + + +/* + * functional interface for NAT lookups of the NAT fragment cache + */ +nat_t *ipfr_nat_knownfrag(ip, fin) +ip_t *ip; +fr_info_t *fin; +{ + nat_t *nat; + ipfr_t *ipf; + + if ((ip->ip_v != 4) || (fr_frag_lock)) + return NULL; + READ_ENTER(&ipf_natfrag); + ipf = ipfr_lookup(ip, fin, ipfr_nattab); + if (ipf != NULL) { + nat = ipf->ipfr_data; + /* + * This is the last fragment for this packet. + */ + if ((ipf->ipfr_ttl == 1) && (nat != NULL)) { + nat->nat_data = NULL; + ipf->ipfr_data = NULL; + } + } else + nat = NULL; + RWLOCK_EXIT(&ipf_natfrag); + return nat; +} + + +/* + * functional interface for normal lookups of the fragment cache + */ +frentry_t *ipfr_knownfrag(ip, fin) +ip_t *ip; +fr_info_t *fin; +{ + frentry_t *fr = NULL; + ipfr_t *fra; + + if ((ip->ip_v != 4) || (fr_frag_lock)) + return NULL; + READ_ENTER(&ipf_frag); + fra = ipfr_lookup(ip, fin, ipfr_heads); + if (fra != NULL) + fr = fra->ipfr_rule; + RWLOCK_EXIT(&ipf_frag); + return fr; +} + + +/* + * forget any references to this external object. + */ +void ipfr_forget(nat) +void *nat; +{ + ipfr_t *fr; + int idx; + + WRITE_ENTER(&ipf_natfrag); + for (idx = IPFT_SIZE - 1; idx >= 0; idx--) + for (fr = ipfr_heads[idx]; fr; fr = fr->ipfr_next) + if (fr->ipfr_data == nat) + fr->ipfr_data = NULL; + + RWLOCK_EXIT(&ipf_natfrag); +} + + +static void ipfr_delete(fra) +ipfr_t *fra; +{ + frentry_t *fr; + + fr = fra->ipfr_rule; + if (fr != NULL) { + ATOMIC_DEC32(fr->fr_ref); + if (fr->fr_ref == 0) + KFREE(fr); + } + if (fra->ipfr_prev) + fra->ipfr_prev->ipfr_next = fra->ipfr_next; + if (fra->ipfr_next) + fra->ipfr_next->ipfr_prev = fra->ipfr_prev; + KFREE(fra); +} + + +/* + * Free memory in use by fragment state info. kept. + */ +void ipfr_unload() +{ + ipfr_t **fp, *fra; + nat_t *nat; + int idx; + + WRITE_ENTER(&ipf_frag); + for (idx = IPFT_SIZE - 1; idx >= 0; idx--) + for (fp = &ipfr_heads[idx]; (fra = *fp); ) { + *fp = fra->ipfr_next; + ipfr_delete(fra); + } + RWLOCK_EXIT(&ipf_frag); + + WRITE_ENTER(&ipf_nat); + WRITE_ENTER(&ipf_natfrag); + for (idx = IPFT_SIZE - 1; idx >= 0; idx--) + for (fp = &ipfr_nattab[idx]; (fra = *fp); ) { + *fp = fra->ipfr_next; + nat = fra->ipfr_data; + if (nat != NULL) { + if (nat->nat_data == fra) + nat->nat_data = NULL; + } + ipfr_delete(fra); + } + RWLOCK_EXIT(&ipf_natfrag); + RWLOCK_EXIT(&ipf_nat); +} + + +#ifdef _KERNEL +void ipfr_fragexpire() +{ + ipfr_t **fp, *fra; + nat_t *nat; + int idx; +#if defined(_KERNEL) +# if !SOLARIS + int s; +# endif +#endif + + if (fr_frag_lock) + return; + + SPL_NET(s); + WRITE_ENTER(&ipf_frag); + + /* + * Go through the entire table, looking for entries to expire, + * decreasing the ttl by one for each entry. If it reaches 0, + * remove it from the chain and free it. + */ + for (idx = IPFT_SIZE - 1; idx >= 0; idx--) + for (fp = &ipfr_heads[idx]; (fra = *fp); ) { + --fra->ipfr_ttl; + if (fra->ipfr_ttl == 0) { + *fp = fra->ipfr_next; + ipfr_delete(fra); + ATOMIC_INCL(ipfr_stats.ifs_expire); + ATOMIC_DEC32(ipfr_inuse); + } else + fp = &fra->ipfr_next; + } + RWLOCK_EXIT(&ipf_frag); + + /* + * Same again for the NAT table, except that if the structure also + * still points to a NAT structure, and the NAT structure points back + * at the one to be free'd, NULL the reference from the NAT struct. + * NOTE: We need to grab both mutex's early, and in this order so as + * to prevent a deadlock if both try to expire at the same time. + */ + WRITE_ENTER(&ipf_nat); + WRITE_ENTER(&ipf_natfrag); + for (idx = IPFT_SIZE - 1; idx >= 0; idx--) + for (fp = &ipfr_nattab[idx]; (fra = *fp); ) { + --fra->ipfr_ttl; + if (fra->ipfr_ttl == 0) { + ATOMIC_INCL(ipfr_stats.ifs_expire); + ATOMIC_DEC32(ipfr_inuse); + nat = fra->ipfr_data; + if (nat != NULL) { + if (nat->nat_data == fra) + nat->nat_data = NULL; + } + *fp = fra->ipfr_next; + ipfr_delete(fra); + } else + fp = &fra->ipfr_next; + } + RWLOCK_EXIT(&ipf_natfrag); + RWLOCK_EXIT(&ipf_nat); + SPL_X(s); +} + + +/* + * Slowly expire held state for fragments. Timeouts are set * in expectation + * of this being called twice per second. + */ +# if (BSD >= 199306) || SOLARIS || defined(__sgi) +# if defined(SOLARIS2) && (SOLARIS2 < 7) +void ipfr_slowtimer() +# else +void ipfr_slowtimer __P((void *ptr)) +# endif +# else +int ipfr_slowtimer() +# endif +{ +#if defined(_KERNEL) && SOLARIS + extern int fr_running; + + if (fr_running <= 0) + return; +#endif + + READ_ENTER(&ipf_solaris); +#ifdef __sgi + ipfilter_sgi_intfsync(); +#endif + + ipfr_fragexpire(); + fr_timeoutstate(); + ip_natexpire(); + fr_authexpire(); +# if SOLARIS + ipfr_timer_id = timeout(ipfr_slowtimer, NULL, drv_usectohz(500000)); + RWLOCK_EXIT(&ipf_solaris); +# else +# if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000) + callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL); +# else +# if (__FreeBSD_version >= 300000) + ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); +# else + timeout(ipfr_slowtimer, NULL, hz/2); +# endif +# if (BSD < 199306) && !defined(__sgi) + return 0; +# endif /* FreeBSD */ +# endif /* NetBSD */ +# endif /* SOLARIS */ +} +#endif /* defined(_KERNEL) */ Property changes on: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_frag.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_frag.h =================================================================== --- vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_frag.h (nonexistent) +++ vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_frag.h (revision 60849) @@ -0,0 +1,65 @@ +/* + * 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. + * + * @(#)ip_frag.h 1.5 3/24/96 + * $Id: ip_frag.h,v 2.4 2000/03/13 22:10:21 darrenr Exp $ + */ + +#ifndef __IP_FRAG_H__ +#define __IP_FRAG_H__ + +#define IPFT_SIZE 257 + +typedef struct ipfr { + struct ipfr *ipfr_next, *ipfr_prev; + void *ipfr_data; + struct in_addr ipfr_src; + struct in_addr ipfr_dst; + u_short ipfr_id; + u_char ipfr_p; + u_char ipfr_tos; + u_short ipfr_off; + u_short ipfr_ttl; + frentry_t *ipfr_rule; +} ipfr_t; + + +typedef struct ipfrstat { + u_long ifs_exists; /* add & already exists */ + u_long ifs_nomem; + u_long ifs_new; + u_long ifs_hits; + u_long ifs_expire; + u_long ifs_inuse; + struct ipfr **ifs_table; + struct ipfr **ifs_nattab; +} ipfrstat_t; + +#define IPFR_CMPSZ (4 + 4 + 2 + 1 + 1) + +extern int fr_ipfrttl; +extern int fr_frag_lock; +extern ipfrstat_t *ipfr_fragstats __P((void)); +extern int ipfr_newfrag __P((ip_t *, fr_info_t *, u_int)); +extern int ipfr_nat_newfrag __P((ip_t *, fr_info_t *, u_int, struct nat *)); +extern nat_t *ipfr_nat_knownfrag __P((ip_t *, fr_info_t *)); +extern frentry_t *ipfr_knownfrag __P((ip_t *, fr_info_t *)); +extern void ipfr_forget __P((void *)); +extern void ipfr_unload __P((void)); +extern void ipfr_fragexpire __P((void)); + +#if (BSD >= 199306) || SOLARIS || defined(__sgi) +# if defined(SOLARIS2) && (SOLARIS2 < 7) +extern void ipfr_slowtimer __P((void)); +# else +extern void ipfr_slowtimer __P((void *)); +# endif +#else +extern int ipfr_slowtimer __P((void)); +#endif + +#endif /* __IP_FIL_H__ */ Property changes on: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_frag.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_ftp_pxy.c =================================================================== --- vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_ftp_pxy.c (nonexistent) +++ vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_ftp_pxy.c (revision 60849) @@ -0,0 +1,756 @@ +/* + * Simple FTP transparent proxy for in-kernel use. For use with the NAT + * code. + * + * $Id: ip_ftp_pxy.c,v 2.7.2.7 2000/05/13 14:28:14 darrenr Exp $ + */ +#if SOLARIS && defined(_KERNEL) +extern kmutex_t ipf_rw; +#endif + +#define isdigit(x) ((x) >= '0' && (x) <= '9') +#define isupper(x) ((unsigned)((x) - 'A') <= 'Z' - 'A') + +#define IPF_FTP_PROXY + +#define IPF_MINPORTLEN 18 +#define IPF_MAXPORTLEN 30 +#define IPF_MIN227LEN 39 +#define IPF_MAX227LEN 51 +#define IPF_FTPBUFSZ 96 /* This *MUST* be >= 53! */ + + +int ippr_ftp_client __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); +int ippr_ftp_complete __P((char *, size_t)); +int ippr_ftp_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_ftp_init __P((void)); +int ippr_ftp_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_ftp_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_ftp_pasv __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int)); +int ippr_ftp_port __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int)); +int ippr_ftp_process __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); +int ippr_ftp_server __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); +int ippr_ftp_valid __P((char *, size_t)); +u_short ippr_ftp_atoi __P((char **)); + +static frentry_t natfr; +int ippr_ftp_pasvonly = 0; + + +/* + * Initialize local structures. + */ +int ippr_ftp_init() +{ + bzero((char *)&natfr, sizeof(natfr)); + natfr.fr_ref = 1; + natfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + return 0; +} + + +int ippr_ftp_new(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + ftpinfo_t *ftp; + ftpside_t *f; + + KMALLOC(ftp, ftpinfo_t *); + if (ftp == NULL) + return -1; + aps->aps_data = ftp; + aps->aps_psiz = sizeof(ftpinfo_t); + + bzero((char *)ftp, sizeof(*ftp)); + f = &ftp->ftp_side[0]; + f->ftps_rptr = f->ftps_buf; + f->ftps_wptr = f->ftps_buf; + f = &ftp->ftp_side[1]; + f->ftps_rptr = f->ftps_buf; + f->ftps_wptr = f->ftps_buf; + return 0; +} + + +int ippr_ftp_port(fin, ip, nat, f, dlen) +fr_info_t *fin; +ip_t *ip; +nat_t *nat; +ftpside_t *f; +int dlen; +{ + tcphdr_t *tcp, tcph, *tcp2 = &tcph; + char newbuf[IPF_FTPBUFSZ], *s; + u_short a5, a6, sp, dp; + u_int a1, a2, a3, a4; + struct in_addr swip; + size_t nlen, olen; + fr_info_t fi; + int inc, off; + nat_t *ipn; + mb_t *m; +#if SOLARIS + mb_t *m1; +#endif + + tcp = (tcphdr_t *)fin->fin_dp; + off = f->ftps_seq - ntohl(tcp->th_seq); + if (off < 0) + return 0; + /* + * Check for client sending out PORT message. + */ + if (dlen < IPF_MINPORTLEN) + return 0; + /* + * Count the number of bytes in the PORT message is. + */ + if (off < 0) + return 0; + + off += fin->fin_hlen + (tcp->th_off << 2); + /* + * Skip the PORT command + space + */ + s = f->ftps_rptr + 5; + /* + * Pick out the address components, two at a time. + */ + a1 = ippr_ftp_atoi(&s); + if (!s) + return 0; + a2 = ippr_ftp_atoi(&s); + if (!s) + 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. + */ + a1 <<= 16; + a1 |= a2; + if (a1 != ntohl(nat->nat_inip.s_addr)) + return 0; + + a5 = ippr_ftp_atoi(&s); + if (!s) + return 0; + if (*s == ')') + s++; + + /* + * check for CR-LF at the end. + */ + if (*s == '\n') + s--; + if ((*s == '\r') && (*(s + 1) == '\n')) { + s += 2; + a6 = a5 & 0xff; + } else + return 0; + a5 >>= 8; + /* + * Calculate new address parts for PORT command + */ + a1 = ntohl(ip->ip_src.s_addr); + a2 = (a1 >> 16) & 0xff; + a3 = (a1 >> 8) & 0xff; + a4 = a1 & 0xff; + a1 >>= 24; + olen = s - f->ftps_rptr; + /* DO NOT change this to sprintf! */ + (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", + "PORT", a1, a2, a3, a4, a5, a6); + + nlen = strlen(newbuf); + inc = nlen - olen; + if ((inc + ip->ip_len) > 65535) + return 0; + +#if SOLARIS + m = fin->fin_qfm; + 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_ftp_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_ftp_out: cannot handle fragmented data block")); + + linkb(m1, nm); + } else { + if (m1->b_datap->db_struiolim == m1->b_wptr) + m1->b_datap->db_struiolim += inc; + m1->b_datap->db_struioflag &= ~STRUIO_IP; + m1->b_wptr += inc; + } + copyin_mblk(m, off, nlen, newbuf); +#else + m = *((mb_t **)fin->fin_mp); + if (inc < 0) + m_adj(m, inc); + /* the mbuf chain will be extended if necessary by m_copyback() */ + m_copyback(m, off, nlen, newbuf); +#endif + if (inc != 0) { +#if SOLARIS || 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(&ip->ip_sum, sum2, 0); +#endif + ip->ip_len += inc; + } + + /* + * Add skeleton NAT entry for connection which will come back the + * other way. + */ + sp = htons(a5 << 8 | a6); + /* + * 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. + */ + dp = htons(fin->fin_data[1] - 1); + ipn = nat_outlookup(fin->fin_ifp, IPN_TCP, nat->nat_p, nat->nat_inip, + ip->ip_dst, (dp << 16) | sp); + if (ipn == NULL) { + int slen; + + slen = ip->ip_len; + ip->ip_len = fin->fin_hlen + sizeof(*tcp2); + bcopy((char *)fin, (char *)&fi, sizeof(fi)); + bzero((char *)tcp2, sizeof(*tcp2)); + tcp2->th_win = htons(8192); + tcp2->th_sport = sp; + tcp2->th_off = 5; + tcp2->th_dport = 0; /* XXX - don't specify remote port */ + fi.fin_data[0] = ntohs(sp); + fi.fin_data[1] = 0; + fi.fin_dp = (char *)tcp2; + swip = ip->ip_src; + ip->ip_src = nat->nat_inip; + ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_TCP|FI_W_DPORT, + NAT_OUTBOUND); + if (ipn != NULL) { + ipn->nat_age = fr_defnatage; + (void) fr_addstate(ip, &fi, FI_W_DPORT); + } + ip->ip_len = slen; + ip->ip_src = swip; + } + return inc; +} + + +int ippr_ftp_client(fin, ip, nat, ftp, dlen) +fr_info_t *fin; +nat_t *nat; +ftpinfo_t *ftp; +ip_t *ip; +int dlen; +{ + char *rptr, *wptr; + ftpside_t *f; + int inc; + + inc = 0; + f = &ftp->ftp_side[0]; + rptr = f->ftps_rptr; + wptr = f->ftps_wptr; + + if ((ftp->ftp_passok == 0) && !strncmp(rptr, "USER ", 5)) + ftp->ftp_passok = 1; + else if ((ftp->ftp_passok == 2) && !strncmp(rptr, "PASS ", 5)) + ftp->ftp_passok = 3; + else if ((ftp->ftp_passok == 4) && !ippr_ftp_pasvonly && + !strncmp(rptr, "PORT ", 5)) { + inc = ippr_ftp_port(fin, ip, nat, f, dlen); + } + + while ((*rptr++ != '\n') && (rptr < wptr)) + ; + f->ftps_seq += rptr - f->ftps_rptr; + f->ftps_rptr = rptr; + return inc; +} + + +int ippr_ftp_pasv(fin, ip, nat, f, dlen) +fr_info_t *fin; +ip_t *ip; +nat_t *nat; +ftpside_t *f; +int dlen; +{ + tcphdr_t *tcp, tcph, *tcp2 = &tcph; + struct in_addr swip, swip2; + u_short a5, a6, sp, dp; + u_int a1, a2, a3, a4; + fr_info_t fi; + int inc, off; + nat_t *ipn; + char *s; + + /* + * Check for PASV reply message. + */ + if (dlen < IPF_MIN227LEN) + return 0; + else if (strncmp(f->ftps_rptr, "227 Entering Passive Mode", 25)) + return 0; + + /* + * Count the number of bytes in the 227 reply is. + */ + tcp = (tcphdr_t *)fin->fin_dp; + off = f->ftps_seq - ntohl(tcp->th_seq); + if (off < 0) + return 0; + + off += fin->fin_hlen + (tcp->th_off << 2); + /* + * Skip the PORT command + space + */ + s = f->ftps_rptr + 25; + while (*s && !isdigit(*s)) + s++; + /* + * Pick out the address components, two at a time. + */ + a1 = ippr_ftp_atoi(&s); + if (!s) + return 0; + a2 = ippr_ftp_atoi(&s); + if (!s) + 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. + */ + a1 <<= 16; + a1 |= a2; + if (a1 != ntohl(nat->nat_oip.s_addr)) + return 0; + + a5 = ippr_ftp_atoi(&s); + if (!s) + return 0; + + if (*s == ')') + s++; + if (*s == '\n') + s--; + /* + * check for CR-LF at the end. + */ + if ((*s == '\r') && (*(s + 1) == '\n')) { + s += 2; + a6 = a5 & 0xff; + } else + return 0; + a5 >>= 8; + /* + * Calculate new address parts for 227 reply + */ + a1 = ntohl(ip->ip_src.s_addr); + a2 = (a1 >> 16) & 0xff; + a3 = (a1 >> 8) & 0xff; + a4 = a1 & 0xff; + a1 >>= 24; + inc = 0; +#if 0 + olen = s - f->ftps_rptr; + (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", + "227 Entering Passive Mode", a1, a2, a3, a4, a5, a6); + nlen = strlen(newbuf); + inc = nlen - olen; + if ((inc + ip->ip_len) > 65535) + return 0; + +#if SOLARIS + m = fin->fin_qfm; + 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_ftp_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_ftp_out: cannot handle fragmented data block")); + + linkb(m1, nm); + } else { + m1->b_wptr += inc; + } + /*copyin_mblk(m, off, nlen, newbuf);*/ +#else + m = *((mb_t **)fin->fin_mp); + if (inc < 0) + m_adj(m, inc); + /* the mbuf chain will be extended if necessary by m_copyback() */ + /*m_copyback(m, off, nlen, newbuf);*/ +#endif + if (inc != 0) { +#if SOLARIS || 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(&ip->ip_sum, sum2, 0); +#endif + ip->ip_len += inc; + } +#endif + + /* + * Add skeleton NAT entry for connection which will come back the + * other way. + */ + sp = 0; + dp = htons(fin->fin_data[1] - 1); + ipn = nat_outlookup(fin->fin_ifp, IPN_TCP, nat->nat_p, nat->nat_inip, + ip->ip_dst, (dp << 16) | sp); + if (ipn == NULL) { + int slen; + + slen = ip->ip_len; + ip->ip_len = fin->fin_hlen + sizeof(*tcp2); + bcopy((char *)fin, (char *)&fi, sizeof(fi)); + bzero((char *)tcp2, sizeof(*tcp2)); + tcp2->th_win = htons(8192); + tcp2->th_sport = 0; /* XXX - fake it for nat_new */ + tcp2->th_off = 5; + fi.fin_data[0] = a5 << 8 | a6; + tcp2->th_dport = htons(fi.fin_data[0]); + fi.fin_data[1] = 0; + fi.fin_dp = (char *)tcp2; + swip = ip->ip_src; + swip2 = ip->ip_dst; + ip->ip_dst = ip->ip_src; + ip->ip_src = nat->nat_inip; + ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_TCP|FI_W_SPORT, + NAT_OUTBOUND); + if (ipn != NULL) { + ipn->nat_age = fr_defnatage; + (void) fr_addstate(ip, &fi, FI_W_SPORT); + } + ip->ip_len = slen; + ip->ip_src = swip; + ip->ip_dst = swip2; + } + return inc; +} + + +int ippr_ftp_server(fin, ip, nat, ftp, dlen) +fr_info_t *fin; +ip_t *ip; +nat_t *nat; +ftpinfo_t *ftp; +int dlen; +{ + char *rptr, *wptr; + ftpside_t *f; + int inc; + + inc = 0; + f = &ftp->ftp_side[1]; + rptr = f->ftps_rptr; + wptr = f->ftps_wptr; + + if ((ftp->ftp_passok == 1) && !strncmp(rptr, "331", 3)) + ftp->ftp_passok = 2; + else if ((ftp->ftp_passok == 3) && !strncmp(rptr, "230", 3)) + ftp->ftp_passok = 4; + else if ((ftp->ftp_passok == 3) && !strncmp(rptr, "530", 3)) + ftp->ftp_passok = 0; + else if ((ftp->ftp_passok == 4) && !strncmp(rptr, "227 ", 4)) { + inc = ippr_ftp_pasv(fin, ip, nat, f, dlen); + } + while ((*rptr++ != '\n') && (rptr < wptr)) + ; + f->ftps_seq += rptr - f->ftps_rptr; + f->ftps_rptr = rptr; + return inc; +} + + +/* + * Look to see if the buffer starts with something which we recognise as + * being the correct syntax for the FTP protocol. + */ +int ippr_ftp_valid(buf, len) +char *buf; +size_t len; +{ + register char *s, c; + register size_t i = len; + + if (i < 5) + return 2; + s = buf; + c = *s++; + i--; + + if (isdigit(c)) { + c = *s++; + i--; + if (isdigit(c)) { + c = *s++; + i--; + if (isdigit(c)) { + c = *s++; + i--; + if ((c != '-') && (c != ' ')) + return 1; + } else + return 1; + } else + return 1; + } else if (isupper(c)) { + c = *s++; + i--; + if (isupper(c)) { + c = *s++; + i--; + if (isupper(c)) { + c = *s++; + i--; + if (isupper(c)) { + c = *s++; + i--; + if ((c != ' ') && (c != '\r')) + return 1; + } else if ((c != ' ') && (c != '\r')) + return 1; + } else + return 1; + } else + return 1; + } else + return 1; + for (; i; i--) { + c = *s++; + if (c == '\n') + return 0; + } + return 2; +} + + +int ippr_ftp_process(fin, ip, nat, ftp, rv) +fr_info_t *fin; +ip_t *ip; +nat_t *nat; +ftpinfo_t *ftp; +int rv; +{ + int mlen, len, off, inc, i; + char *rptr, *wptr; + tcphdr_t *tcp; + ftpside_t *f; + mb_t *m; + + tcp = (tcphdr_t *)fin->fin_dp; + off = fin->fin_hlen + (tcp->th_off << 2); + +#if SOLARIS + m = fin->fin_qfm; +#else + m = *((mb_t **)fin->fin_mp); +#endif + +#if SOLARIS + mlen = msgdsize(m) - off; +#else + mlen = mbufchainlen(m) - off; +#endif + if (!mlen) + return 0; + + inc = 0; + f = &ftp->ftp_side[rv]; + rptr = f->ftps_rptr; + wptr = f->ftps_wptr; + if ((wptr == f->ftps_buf) && (f->ftps_seq <= ntohl(tcp->th_seq))) + f->ftps_seq = ntohl(tcp->th_seq); + + /* + * XXX - Ideally, this packet should get dropped because we now know + * that it is out of order (and there is no real danger in doing so + * apart from causing packets to go through here ordered). + */ + if (ntohl(tcp->th_seq) != f->ftps_seq + (wptr - rptr)) { + return APR_ERR(0); + } + + while (mlen > 0) { + len = MIN(mlen, FTP_BUFSZ / 2); + +#if SOLARIS + copyout_mblk(m, off, len, wptr); +#else + m_copydata(m, off, len, wptr); +#endif + mlen -= len; + off += len; + wptr += len; + f->ftps_wptr = wptr; + if (f->ftps_junk == 2) + f->ftps_junk = ippr_ftp_valid(rptr, wptr - rptr); + + while ((f->ftps_junk == 0) && (wptr > rptr)) { + f->ftps_junk = ippr_ftp_valid(rptr, wptr - rptr); + if (f->ftps_junk == 0) { + len = wptr - rptr; + f->ftps_rptr = rptr; + if (rv) + inc += ippr_ftp_server(fin, ip, nat, + ftp, len); + else + inc += ippr_ftp_client(fin, ip, nat, + ftp, len); + rptr = f->ftps_rptr; + } + } + + while ((f->ftps_junk == 1) && (rptr < wptr)) { + while ((rptr < wptr) && (*rptr != '\r')) + rptr++; + + if ((*rptr == '\r') && (rptr + 1 < wptr)) { + if (*(rptr + 1) == '\n') { + rptr += 2; + f->ftps_junk = 0; + } else + rptr++; + } + f->ftps_seq += rptr - f->ftps_rptr; + f->ftps_rptr = rptr; + } + + if (rptr == wptr) { + rptr = wptr = f->ftps_buf; + } else { + if ((wptr > f->ftps_buf + FTP_BUFSZ / 2)) { + i = wptr - rptr; + if ((rptr == f->ftps_buf) || + (wptr - rptr > FTP_BUFSZ / 2)) { + f->ftps_seq += i; + f->ftps_junk = 1; + rptr = wptr = f->ftps_buf; + } else { + bcopy(rptr, f->ftps_buf, i); + wptr = f->ftps_buf + i; + rptr = f->ftps_buf; + } + } + f->ftps_rptr = rptr; + f->ftps_wptr = wptr; + } + } + + f->ftps_rptr = rptr; + f->ftps_wptr = wptr; + return inc; +} + + +int ippr_ftp_out(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + ftpinfo_t *ftp; + + ftp = aps->aps_data; + if (ftp == NULL) + return 0; + return ippr_ftp_process(fin, ip, nat, ftp, 0); +} + + +int ippr_ftp_in(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + ftpinfo_t *ftp; + + ftp = aps->aps_data; + if (ftp == NULL) + return 0; + return ippr_ftp_process(fin, ip, nat, ftp, 1); +} + + +/* + * ippr_ftp_atoi - implement a version of atoi which processes numbers in + * pairs separated by commas (which are expected to be in the range 0 - 255), + * returning a 16 bit number combining either side of the , as the MSB and + * LSB. + */ +u_short ippr_ftp_atoi(ptr) +char **ptr; +{ + register char *s = *ptr, c; + register u_char i = 0, j = 0; + + while ((c = *s++) && isdigit(c)) { + i *= 10; + i += c - '0'; + } + if (c != ',') { + *ptr = NULL; + return 0; + } + while ((c = *s++) && isdigit(c)) { + j *= 10; + j += c - '0'; + } + *ptr = s; + return (i << 8) | j; +} Property changes on: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_ftp_pxy.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_log.c =================================================================== --- vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_log.c (nonexistent) +++ vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_log.c (revision 60849) @@ -0,0 +1,499 @@ +/* + * Copyright (C) 1997-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. + * + * $Id: ip_log.c,v 2.5 2000/03/13 22:10:21 darrenr Exp $ + */ +#include +#if defined(KERNEL) && !defined(_KERNEL) +# define _KERNEL +#endif +#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) +# include "opt_ipfilter_log.h" +#endif +#ifdef __FreeBSD__ +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) +# include "opt_ipfilter.h" +# endif +# else +# include +# endif +#endif +#ifdef IPFILTER_LOG +# ifndef SOLARIS +# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +# endif +# ifndef _KERNEL +# include +# include +# include +# include +# endif +# include +# include +# include +# if __FreeBSD_version >= 220000 && defined(_KERNEL) +# include +# include +# else +# include +# endif +# include +# if defined(_KERNEL) && !defined(linux) +# include +# endif +# include +# if !SOLARIS +# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000) +# include +# else +# include +# endif +# ifndef linux +# include +# endif +# else +# include +# include +# include +# include +# include +# include +# include +# include +# include +# endif +# ifndef linux +# include +# endif +# include + +# include +# ifdef sun +# include +# endif +# if __FreeBSD_version >= 300000 +# include +# endif +# include +# include +# ifdef __sgi +# include +# ifdef IFF_DRVRLOCK /* IRIX6 */ +# include +# endif +# endif +# if !defined(linux) && !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /*IRIX<6*/ +# include +# endif +# include +# include +# include +# include +# include +# ifndef linux +# include +# endif +# ifndef _KERNEL +# include +# endif +# include "netinet/ip_compat.h" +# include +# include "netinet/ip_fil.h" +# include "netinet/ip_proxy.h" +# include "netinet/ip_nat.h" +# include "netinet/ip_frag.h" +# include "netinet/ip_state.h" +# include "netinet/ip_auth.h" +# if (__FreeBSD_version >= 300000) +# include +# endif + +# ifndef MIN +# define MIN(a,b) (((a)<(b))?(a):(b)) +# endif + + +# if SOLARIS || defined(__sgi) +extern kmutex_t ipl_mutex; +# if SOLARIS +extern kcondvar_t iplwait; +# endif +# endif + +iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1], *ipll[IPL_LOGMAX+1]; +size_t iplused[IPL_LOGMAX+1]; +static fr_info_t iplcrc[IPL_LOGMAX+1]; +# ifdef linux +static struct wait_queue *iplwait[IPL_LOGMAX+1]; +# endif + + +/* + * Initialise log buffers & pointers. Also iniialised the CRC to a local + * secret for use in calculating the "last log checksum". + */ +void ipflog_init() +{ + int i; + + for (i = IPL_LOGMAX; i >= 0; i--) { + iplt[i] = NULL; + ipll[i] = NULL; + iplh[i] = &iplt[i]; + iplused[i] = 0; + bzero((char *)&iplcrc[i], sizeof(iplcrc[i])); + } +} + + +/* + * ipflog + * Create a log record for a packet given that it has been triggered by a + * rule (or the default setting). Calculate the transport protocol header + * size using predetermined size of a couple of popular protocols and thus + * how much data to copy into the log, including part of the data body if + * requested. + */ +int ipflog(flags, ip, fin, m) +u_int flags; +ip_t *ip; +fr_info_t *fin; +mb_t *m; +{ + ipflog_t ipfl; + register size_t mlen, hlen; + size_t sizes[2]; + void *ptrs[2]; + int types[2]; + u_char p; +# if SOLARIS + ill_t *ifp = fin->fin_ifp; +# else + struct ifnet *ifp = fin->fin_ifp; +# endif + + /* + * calculate header size. + */ + hlen = fin->fin_hlen; + if (fin->fin_off == 0) { + p = fin->fin_fi.fi_p; + if (p == IPPROTO_TCP) + hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen); + else if (p == IPPROTO_UDP) + hlen += MIN(sizeof(udphdr_t), fin->fin_dlen); + else if (p == IPPROTO_ICMP) { + struct icmp *icmp; + + icmp = (struct icmp *)fin->fin_dp; + + /* + * For ICMP, if the packet is an error packet, also + * include the information about the packet which + * caused the error. + */ + switch (icmp->icmp_type) + { + case ICMP_UNREACH : + case ICMP_SOURCEQUENCH : + case ICMP_REDIRECT : + case ICMP_TIMXCEED : + case ICMP_PARAMPROB : + hlen += MIN(sizeof(struct icmp) + 8, + fin->fin_dlen); + break; + default : + hlen += MIN(sizeof(struct icmp), + fin->fin_dlen); + break; + } + } + } + /* + * Get the interface number and name to which this packet is + * currently associated. + */ +# if SOLARIS + ipfl.fl_unit = (u_char)ifp->ill_ppa; + bcopy(ifp->ill_name, ipfl.fl_ifname, MIN(ifp->ill_name_length, 4)); + mlen = (flags & FR_LOGBODY) ? MIN(msgdsize(m) - hlen, 128) : 0; +# else +# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) + strncpy(ipfl.fl_ifname, ifp->if_xname, IFNAMSIZ); +# else +# ifndef linux + ipfl.fl_unit = (u_char)ifp->if_unit; +# endif + if ((ipfl.fl_ifname[0] = ifp->if_name[0])) + if ((ipfl.fl_ifname[1] = ifp->if_name[1])) + if ((ipfl.fl_ifname[2] = ifp->if_name[2])) + ipfl.fl_ifname[3] = ifp->if_name[3]; +# endif + mlen = (flags & FR_LOGBODY) ? MIN(fin->fin_plen - hlen, 128) : 0; +# endif + ipfl.fl_plen = (u_char)mlen; + ipfl.fl_hlen = (u_char)hlen; + ipfl.fl_rule = fin->fin_rule; + ipfl.fl_group = fin->fin_group; + if (fin->fin_fr != NULL) + ipfl.fl_loglevel = fin->fin_fr->fr_loglevel; + else + ipfl.fl_loglevel = 0xffff; + ipfl.fl_flags = flags; + ptrs[0] = (void *)&ipfl; + sizes[0] = sizeof(ipfl); + types[0] = 0; +# if SOLARIS + /* + * Are we copied from the mblk or an aligned array ? + */ + if (ip == (ip_t *)m->b_rptr) { + ptrs[1] = m; + sizes[1] = hlen + mlen; + types[1] = 1; + } else { + ptrs[1] = ip; + sizes[1] = hlen + mlen; + types[1] = 0; + } +# else + ptrs[1] = m; + sizes[1] = hlen + mlen; + types[1] = 1; +# endif + return ipllog(IPL_LOGIPF, fin, ptrs, sizes, types, 2); +} + + +/* + * ipllog + */ +int ipllog(dev, fin, items, itemsz, types, cnt) +int dev; +fr_info_t *fin; +void **items; +size_t *itemsz; +int *types, cnt; +{ + caddr_t buf, s; + iplog_t *ipl; + size_t len; + int i; + + /* + * Check to see if this log record has a CRC which matches the last + * record logged. If it does, just up the count on the previous one + * rather than create a new one. + */ + MUTEX_ENTER(&ipl_mutex); + if (fin != NULL) { + if ((ipll[dev] != NULL) && + bcmp((char *)fin, (char *)&iplcrc[dev], FI_CSIZE) == 0) { + ipll[dev]->ipl_count++; + MUTEX_EXIT(&ipl_mutex); + return 1; + } + bcopy((char *)fin, (char *)&iplcrc[dev], FI_CSIZE); + } else + bzero((char *)&iplcrc[dev], FI_CSIZE); + MUTEX_EXIT(&ipl_mutex); + + /* + * Get the total amount of data to be logged. + */ + for (i = 0, len = sizeof(iplog_t); i < cnt; i++) + len += itemsz[i]; + + /* + * check that we have space to record this information and can + * allocate that much. + */ + KMALLOCS(buf, caddr_t, len); + if (!buf) + return 0; + MUTEX_ENTER(&ipl_mutex); + if ((iplused[dev] + len) > IPLLOGSIZE) { + MUTEX_EXIT(&ipl_mutex); + KFREES(buf, len); + return 0; + } + iplused[dev] += len; + MUTEX_EXIT(&ipl_mutex); + + /* + * advance the log pointer to the next empty record and deduct the + * amount of space we're going to use. + */ + ipl = (iplog_t *)buf; + ipl->ipl_magic = IPL_MAGIC; + ipl->ipl_count = 1; + ipl->ipl_next = NULL; + ipl->ipl_dsize = len; +# if SOLARIS || defined(sun) || defined(linux) + uniqtime((struct timeval *)&ipl->ipl_sec); +# else +# if BSD >= 199306 || defined(__FreeBSD__) || defined(__sgi) + microtime((struct timeval *)&ipl->ipl_sec); +# endif +# endif + + /* + * Loop through all the items to be logged, copying each one to the + * buffer. Use bcopy for normal data or the mb_t copyout routine. + */ + for (i = 0, s = buf + sizeof(*ipl); i < cnt; i++) { + if (types[i] == 0) + bcopy(items[i], s, itemsz[i]); + else if (types[i] == 1) { +# if SOLARIS + copyout_mblk(items[i], 0, itemsz[i], s); +# else + m_copydata(items[i], 0, itemsz[i], s); +# endif + } + s += itemsz[i]; + } + MUTEX_ENTER(&ipl_mutex); + ipll[dev] = ipl; + *iplh[dev] = ipl; + iplh[dev] = &ipl->ipl_next; +# if SOLARIS + cv_signal(&iplwait); + mutex_exit(&ipl_mutex); +# else + MUTEX_EXIT(&ipl_mutex); +# ifdef linux + wake_up_interruptible(&iplwait[dev]); +# else + wakeup(&iplh[dev]); +# endif +# endif + return 1; +} + + +int ipflog_read(unit, uio) +minor_t unit; +struct uio *uio; +{ + size_t dlen, copied; + int error = 0; + iplog_t *ipl; +# if defined(_KERNEL) && !SOLARIS + int s; +# endif + + /* + * Sanity checks. Make sure the minor # is valid and we're copying + * a valid chunk of data. + */ + if (IPL_LOGMAX < unit) + return ENXIO; + if (!uio->uio_resid) + return 0; + if ((uio->uio_resid < sizeof(iplog_t)) || + (uio->uio_resid > IPLLOGSIZE)) + return EINVAL; + + /* + * Lock the log so we can snapshot the variables. Wait for a signal + * if the log is empty. + */ + SPL_NET(s); + MUTEX_ENTER(&ipl_mutex); + + while (!iplused[unit] || !iplt[unit]) { +# if SOLARIS && defined(_KERNEL) + if (!cv_wait_sig(&iplwait, &ipl_mutex)) { + MUTEX_EXIT(&ipl_mutex); + return EINTR; + } +# else +# ifdef linux + interruptible_sleep_on(&iplwait[unit]); + if (current->signal & ~current->blocked) + return -EINTR; +# else + MUTEX_EXIT(&ipl_mutex); + SPL_X(s); + error = SLEEP(&iplh[unit], "ipl sleep"); + if (error) + return error; + SPL_NET(s); + MUTEX_ENTER(&ipl_mutex); +# endif /* linux */ +# endif /* SOLARIS */ + } + +# if BSD >= 199306 || defined(__FreeBSD__) + uio->uio_rw = UIO_READ; +# endif + + for (copied = 0; (ipl = iplt[unit]); copied += dlen) { + dlen = ipl->ipl_dsize; + if (dlen > uio->uio_resid) + break; + /* + * Don't hold the mutex over the uiomove call. + */ + iplt[unit] = ipl->ipl_next; + iplused[unit] -= dlen; + MUTEX_EXIT(&ipl_mutex); + SPL_X(s); + error = UIOMOVE((caddr_t)ipl, dlen, UIO_READ, uio); + if (error) { + SPL_NET(s); + MUTEX_ENTER(&ipl_mutex); + ipl->ipl_next = iplt[unit]; + iplt[unit] = ipl; + iplused[unit] += dlen; + break; + } + KFREES((caddr_t)ipl, dlen); + SPL_NET(s); + MUTEX_ENTER(&ipl_mutex); + } + if (!iplt[unit]) { + iplused[unit] = 0; + iplh[unit] = &iplt[unit]; + ipll[unit] = NULL; + } + + MUTEX_EXIT(&ipl_mutex); + SPL_X(s); +# ifdef linux + if (!error) + return (int)copied; + return -error; +# else + return error; +# endif +} + + +int ipflog_clear(unit) +minor_t unit; +{ + iplog_t *ipl; + int used; + + MUTEX_ENTER(&ipl_mutex); + while ((ipl = iplt[unit])) { + iplt[unit] = ipl->ipl_next; + KFREES((caddr_t)ipl, ipl->ipl_dsize); + } + iplh[unit] = &iplt[unit]; + ipll[unit] = NULL; + used = iplused[unit]; + iplused[unit] = 0; + bzero((char *)&iplcrc[unit], FI_CSIZE); + MUTEX_EXIT(&ipl_mutex); + return used; +} +#endif /* IPFILTER_LOG */ Property changes on: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_log.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_nat.c =================================================================== --- vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_nat.c (nonexistent) +++ vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_nat.c (revision 60849) @@ -0,0 +1,2301 @@ +/* + * Copyright (C) 1995-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. + * + * Added redirect stuff and a LOT of bug fixes. (mcn@EnGarde.com) + */ +#if !defined(lint) +static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.10 2000/05/19 15:54:44 darrenr Exp $"; +#endif + +#if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) +#define _KERNEL +#endif + +#include +#include +#include +#include +#include +#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ + defined(_KERNEL) +# include "opt_ipfilter_log.h" +#endif +#if !defined(_KERNEL) && !defined(KERNEL) +# include +# include +# include +#endif +#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) +# include +# include +#else +# include +#endif +#include +#include +#ifndef linux +# include +#endif +#include +#if defined(_KERNEL) && !defined(linux) +# include +#endif +#if !defined(__SVR4) && !defined(__svr4__) +# ifndef linux +# include +# endif +#else +# include +# include +# ifdef _KERNEL +# include +# endif +# include +# include +#endif +#if __FreeBSD_version >= 300000 +# include +#endif +#include +#if __FreeBSD_version >= 300000 +# include +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# include "opt_ipfilter.h" +# endif +#endif +#ifdef sun +# include +#endif +#include +#include +#include +#include + +#ifdef __sgi +# ifdef IFF_DRVRLOCK /* IRIX6 */ +#include +#include +# endif +#endif + +#ifdef RFC1825 +# include +# include +extern struct ifnet vpnif; +#endif + +#ifndef linux +# include +#endif +#include +#include +#include +#include "netinet/ip_compat.h" +#include +#include "netinet/ip_fil.h" +#include "netinet/ip_proxy.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_frag.h" +#include "netinet/ip_state.h" +#if (__FreeBSD_version >= 300000) +# include +#endif +#ifndef MIN +# define MIN(a,b) (((a)<(b))?(a):(b)) +#endif +#undef SOCKADDR_IN +#define SOCKADDR_IN struct sockaddr_in + +nat_t **nat_table[2] = { NULL, NULL }, + *nat_instances = NULL; +ipnat_t *nat_list = NULL; +u_int ipf_nattable_sz = NAT_TABLE_SZ; +u_int ipf_natrules_sz = NAT_SIZE; +u_int ipf_rdrrules_sz = RDR_SIZE; +u_int ipf_hostmap_sz = HOSTMAP_SIZE; +u_32_t nat_masks = 0; +u_32_t rdr_masks = 0; +ipnat_t **nat_rules = NULL; +ipnat_t **rdr_rules = NULL; +hostmap_t **maptable = NULL; + +u_long fr_defnatage = DEF_NAT_AGE, + fr_defnaticmpage = 6; /* 3 seconds */ +static natstat_t nat_stats; +int fr_nat_lock = 0; +#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) +extern kmutex_t ipf_rw, ipf_hostmap; +extern KRWLOCK_T ipf_nat; +#endif + +static int nat_flushtable __P((void)); +static int nat_clearlist __P((void)); +static void nat_addnat __P((struct ipnat *)); +static void nat_addrdr __P((struct ipnat *)); +static void nat_delete __P((struct nat *)); +static void nat_delrdr __P((struct ipnat *)); +static void nat_delnat __P((struct ipnat *)); +static int fr_natgetent __P((caddr_t)); +static int fr_natgetsz __P((caddr_t)); +static int fr_natputent __P((caddr_t)); +static int nat_match __P((fr_info_t *, ipnat_t *, ip_t *)); +static hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr, + struct in_addr)); +static void nat_hostmapdel __P((struct hostmap *)); + + +int nat_init() +{ + KMALLOCS(nat_table[0], nat_t **, sizeof(nat_t *) * ipf_nattable_sz); + if (nat_table[0] != NULL) + bzero((char *)nat_table[0], ipf_nattable_sz * sizeof(nat_t *)); + else + return -1; + + KMALLOCS(nat_table[1], nat_t **, sizeof(nat_t *) * ipf_nattable_sz); + if (nat_table[1] != NULL) + bzero((char *)nat_table[1], ipf_nattable_sz * sizeof(nat_t *)); + else + return -1; + + KMALLOCS(nat_rules, ipnat_t **, sizeof(ipnat_t *) * ipf_natrules_sz); + if (nat_rules != NULL) + bzero((char *)nat_rules, ipf_natrules_sz * sizeof(ipnat_t *)); + else + return -1; + + KMALLOCS(rdr_rules, ipnat_t **, sizeof(ipnat_t *) * ipf_rdrrules_sz); + if (rdr_rules != NULL) + bzero((char *)rdr_rules, ipf_rdrrules_sz * sizeof(ipnat_t *)); + else + return -1; + + KMALLOCS(maptable, hostmap_t **, sizeof(hostmap_t *) * ipf_hostmap_sz); + if (maptable != NULL) + bzero((char *)maptable, sizeof(hostmap_t *) * ipf_hostmap_sz); + else + return -1; + return 0; +} + + +static void nat_addrdr(n) +ipnat_t *n; +{ + ipnat_t **np; + u_32_t j; + u_int hv; + int k; + + k = countbits(n->in_outmsk); + if ((k >= 0) && (k != 32)) + rdr_masks |= 1 << k; + j = (n->in_outip & n->in_outmsk); + hv = NAT_HASH_FN(j, 0, ipf_rdrrules_sz); + np = rdr_rules + hv; + while (*np != NULL) + np = &(*np)->in_rnext; + n->in_rnext = NULL; + n->in_prnext = np; + *np = n; +} + + +static void nat_addnat(n) +ipnat_t *n; +{ + ipnat_t **np; + u_32_t j; + u_int hv; + int k; + + k = countbits(n->in_inmsk); + if ((k >= 0) && (k != 32)) + nat_masks |= 1 << k; + j = (n->in_inip & n->in_inmsk); + hv = NAT_HASH_FN(j, 0, ipf_natrules_sz); + np = nat_rules + hv; + while (*np != NULL) + np = &(*np)->in_mnext; + n->in_mnext = NULL; + n->in_pmnext = np; + *np = n; +} + + +static void nat_delrdr(n) +ipnat_t *n; +{ + if (n->in_rnext) + n->in_rnext->in_prnext = n->in_prnext; + *n->in_prnext = n->in_rnext; +} + + +static void nat_delnat(n) +ipnat_t *n; +{ + if (n->in_mnext) + n->in_mnext->in_pmnext = n->in_pmnext; + *n->in_pmnext = n->in_mnext; +} + + +/* + * check if an ip address has already been allocated for a given mapping that + * is not doing port based translation. + */ +static struct hostmap *nat_hostmap(np, real, map) +ipnat_t *np; +struct in_addr real; +struct in_addr map; +{ + hostmap_t *hm; + u_int hv; + + MUTEX_ENTER(&ipf_hostmap); + hv = real.s_addr % HOSTMAP_SIZE; + for (hm = maptable[hv]; hm; hm = hm->hm_next) + if ((hm->hm_realip.s_addr == real.s_addr) && + (np == hm->hm_ipnat)) { + hm->hm_ref++; + MUTEX_EXIT(&ipf_hostmap); + return hm; + } + + KMALLOC(hm, hostmap_t *); + if (hm) { + hm->hm_next = maptable[hv]; + hm->hm_pnext = maptable + hv; + if (maptable[hv]) + maptable[hv]->hm_pnext = &hm->hm_next; + maptable[hv] = hm; + hm->hm_ipnat = np; + hm->hm_realip = real; + hm->hm_mapip = map; + hm->hm_ref = 1; + } + MUTEX_EXIT(&ipf_hostmap); + return hm; +} + + +static void nat_hostmapdel(hm) +struct hostmap *hm; +{ + MUTEX_ENTER(&ipf_hostmap); + ATOMIC_DEC32(hm->hm_ref); + if (hm->hm_ref == 0) { + if (hm->hm_next) + hm->hm_next->hm_pnext = hm->hm_pnext; + *hm->hm_pnext = hm->hm_next; + KFREE(hm); + } + MUTEX_EXIT(&ipf_hostmap); +} + + +void fix_outcksum(sp, n , len) +u_short *sp; +u_32_t n; +int len; +{ + register u_short sumshort; + register u_32_t sum1; + + if (!n) + return; +#if SOLARIS2 >= 6 + else if (n & NAT_HW_CKSUM) { + *sp = n & 0xffff; + return; + } +#endif + sum1 = (~ntohs(*sp)) & 0xffff; + sum1 += (n); + sum1 = (sum1 >> 16) + (sum1 & 0xffff); + /* Again */ + sum1 = (sum1 >> 16) + (sum1 & 0xffff); + sumshort = ~(u_short)sum1; + *(sp) = htons(sumshort); +} + + +void fix_incksum(sp, n , len) +u_short *sp; +u_32_t n; +int len; +{ + register u_short sumshort; + register u_32_t sum1; + + if (!n) + return; +#if SOLARIS2 >= 6 + else if (n & NAT_HW_CKSUM) { + *sp = n & 0xffff; + return; + } +#endif +#ifdef sparc + sum1 = (~(*sp)) & 0xffff; +#else + sum1 = (~ntohs(*sp)) & 0xffff; +#endif + sum1 += ~(n) & 0xffff; + sum1 = (sum1 >> 16) + (sum1 & 0xffff); + /* Again */ + sum1 = (sum1 >> 16) + (sum1 & 0xffff); + sumshort = ~(u_short)sum1; + *(sp) = htons(sumshort); +} + + +/* + * How the NAT is organised and works. + * + * Inside (interface y) NAT Outside (interface x) + * -------------------- -+- ------------------------------------- + * Packet going | out, processsed by ip_natout() for x + * ------------> | ------------> + * src=10.1.1.1 | src=192.1.1.1 + * | + * | in, processed by ip_natin() for x + * <------------ | <------------ + * dst=10.1.1.1 | dst=192.1.1.1 + * -------------------- -+- ------------------------------------- + * ip_natout() - changes ip_src and if required, sport + * - creates a new mapping, if required. + * ip_natin() - changes ip_dst and if required, dport + * + * In the NAT table, internal source is recorded as "in" and externally + * seen as "out". + */ + +/* + * Handle ioctls which manipulate the NAT. + */ +int nat_ioctl(data, cmd, mode) +#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) +u_long cmd; +#else +int cmd; +#endif +caddr_t data; +int mode; +{ + register ipnat_t *nat, *nt, *n = NULL, **np = NULL; + int error = 0, ret, arg; + ipnat_t natd; + u_32_t i, j; + +#if (BSD >= 199306) && defined(_KERNEL) + if ((securelevel >= 2) && (mode & FWRITE)) + return EPERM; +#endif + + nat = NULL; /* XXX gcc -Wuninitialized */ + KMALLOC(nt, ipnat_t *); + if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) + error = IRCOPYPTR(data, (char *)&natd, sizeof(natd)); + else if (cmd == SIOCIPFFL) /* SIOCFLNAT & SIOCCNATL */ + error = IRCOPY(data, (char *)&arg, sizeof(arg)); + + if (error) + goto done; + + /* + * For add/delete, look to see if the NAT entry is already present + */ + WRITE_ENTER(&ipf_nat); + if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) { + nat = &natd; + nat->in_flags &= IPN_USERFLAGS; + if ((nat->in_redir & NAT_MAPBLK) == 0) { + if ((nat->in_flags & IPN_SPLIT) == 0) + nat->in_inip &= nat->in_inmsk; + if ((nat->in_flags & IPN_IPRANGE) == 0) + nat->in_outip &= nat->in_outmsk; + } + for (np = &nat_list; (n = *np); np = &n->in_next) + if (!bcmp((char *)&nat->in_flags, (char *)&n->in_flags, + IPN_CMPSIZ)) + break; + } + + switch (cmd) + { +#ifdef IPFILTER_LOG + case SIOCIPFFB : + { + int tmp; + + if (!(mode & FWRITE)) + error = EPERM; + else { + tmp = ipflog_clear(IPL_LOGNAT); + IWCOPY((char *)&tmp, (char *)data, sizeof(tmp)); + } + break; + } +#endif + case SIOCADNAT : + if (!(mode & FWRITE)) { + error = EPERM; + break; + } + if (n) { + error = EEXIST; + break; + } + if (nt == NULL) { + error = ENOMEM; + break; + } + n = nt; + nt = NULL; + bcopy((char *)nat, (char *)n, sizeof(*n)); + n->in_ifp = (void *)GETUNIT(n->in_ifname, 4); + if (!n->in_ifp) + n->in_ifp = (void *)-1; + if (n->in_plabel[0] != '\0') { + n->in_apr = appr_match(n->in_p, n->in_plabel); + if (!n->in_apr) { + error = ENOENT; + break; + } + } + n->in_next = NULL; + *np = n; + + if (n->in_redir & NAT_REDIRECT) + nat_addrdr(n); + if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) + nat_addnat(n); + + n->in_use = 0; + if (n->in_redir & NAT_MAPBLK) + n->in_space = USABLE_PORTS * ~ntohl(n->in_outmsk); + else if (n->in_flags & IPN_AUTOPORTMAP) + n->in_space = USABLE_PORTS * ~ntohl(n->in_inmsk); + else if (n->in_flags & IPN_IPRANGE) + n->in_space = ntohl(n->in_outmsk) - ntohl(n->in_outip); + else if (n->in_flags & IPN_SPLIT) + n->in_space = 2; + else + n->in_space = ~ntohl(n->in_outmsk); + /* + * Calculate the number of valid IP addresses in the output + * mapping range. In all cases, the range is inclusive of + * the start and ending IP addresses. + * If to a CIDR address, lose 2: broadcast + network address + * (so subtract 1) + * If to a range, add one. + * If to a single IP address, set to 1. + */ + if (n->in_space) { + if ((n->in_flags & IPN_IPRANGE) != 0) + n->in_space += 1; + else + n->in_space -= 1; + } else + n->in_space = 1; + if ((n->in_outmsk != 0xffffffff) && (n->in_outmsk != 0) && + ((n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0)) + n->in_nip = ntohl(n->in_outip) + 1; + else if ((n->in_flags & IPN_SPLIT) && + (n->in_redir & NAT_REDIRECT)) + n->in_nip = ntohl(n->in_inip); + else + n->in_nip = ntohl(n->in_outip); + if (n->in_redir & NAT_MAP) { + n->in_pnext = ntohs(n->in_pmin); + /* + * Multiply by the number of ports made available. + */ + if (ntohs(n->in_pmax) >= ntohs(n->in_pmin)) { + n->in_space *= (ntohs(n->in_pmax) - + ntohs(n->in_pmin) + 1); + /* + * Because two different sources can map to + * different destinations but use the same + * local IP#/port #. + * If the result is smaller than in_space, then + * we may have wrapped around 32bits. + */ + i = n->in_inmsk; + if ((i != 0) && (i != 0xffffffff)) { + j = n->in_space * (~ntohl(i) + 1); + if (j >= n->in_space) + n->in_space = j; + else + n->in_space = 0xffffffff; + } + } + /* + * If no protocol is specified, multiple by 256. + */ + if ((n->in_flags & IPN_TCPUDP) == 0) { + j = n->in_space * 256; + if (j >= n->in_space) + n->in_space = j; + else + n->in_space = 0xffffffff; + } + } + /* Otherwise, these fields are preset */ + n = NULL; + nat_stats.ns_rules++; + break; + case SIOCRMNAT : + if (!(mode & FWRITE)) { + error = EPERM; + n = NULL; + break; + } + if (!n) { + error = ESRCH; + break; + } + if (n->in_redir & NAT_REDIRECT) + nat_delrdr(n); + if (n->in_redir & (NAT_MAPBLK|NAT_MAP)) + nat_delnat(n); + if (nat_list == NULL) { + nat_masks = 0; + rdr_masks = 0; + } + *np = n->in_next; + if (!n->in_use) { + if (n->in_apr) + appr_free(n->in_apr); + KFREE(n); + nat_stats.ns_rules--; + } else { + n->in_flags |= IPN_DELETE; + n->in_next = NULL; + } + n = NULL; + break; + case SIOCGNATS : + MUTEX_DOWNGRADE(&ipf_nat); + nat_stats.ns_table[0] = nat_table[0]; + nat_stats.ns_table[1] = nat_table[1]; + nat_stats.ns_list = nat_list; + nat_stats.ns_nattab_sz = ipf_nattable_sz; + nat_stats.ns_rultab_sz = ipf_natrules_sz; + nat_stats.ns_rdrtab_sz = ipf_rdrrules_sz; + nat_stats.ns_instances = nat_instances; + nat_stats.ns_apslist = ap_sess_list; + error = IWCOPYPTR((char *)&nat_stats, (char *)data, + sizeof(nat_stats)); + break; + case SIOCGNATL : + { + natlookup_t nl; + + MUTEX_DOWNGRADE(&ipf_nat); + error = IRCOPYPTR((char *)data, (char *)&nl, sizeof(nl)); + if (error) + break; + + if (nat_lookupredir(&nl)) { + error = IWCOPYPTR((char *)&nl, (char *)data, + sizeof(nl)); + } else + error = ESRCH; + break; + } + case SIOCIPFFL : /* old SIOCFLNAT & SIOCCNATL */ + if (!(mode & FWRITE)) { + error = EPERM; + break; + } + error = 0; + if (arg == 0) + ret = nat_flushtable(); + else if (arg == 1) + ret = nat_clearlist(); + else + error = EINVAL; + MUTEX_DOWNGRADE(&ipf_nat); + if (!error) { + error = IWCOPY((caddr_t)&ret, data, sizeof(ret)); + if (error) + error = EFAULT; + } + break; + case SIOCSTLCK : + error = IRCOPY(data, (caddr_t)&arg, sizeof(arg)); + if (!error) { + error = IWCOPY((caddr_t)&fr_nat_lock, data, + sizeof(fr_nat_lock)); + if (!error) + fr_nat_lock = arg; + } + break; + case SIOCSTPUT : + if (fr_nat_lock) + error = fr_natputent(data); + else + error = EACCES; + break; + case SIOCSTGSZ : + if (fr_nat_lock) + error = fr_natgetsz(data); + else + error = EACCES; + break; + case SIOCSTGET : + if (fr_nat_lock) + error = fr_natgetent(data); + else + error = EACCES; + break; + case FIONREAD : +#ifdef IPFILTER_LOG + MUTEX_DOWNGRADE(&ipf_nat); + error = IWCOPY((caddr_t)&iplused[IPL_LOGNAT], (caddr_t)data, + sizeof(iplused[IPL_LOGNAT])); +#endif + break; + default : + error = EINVAL; + break; + } + RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ +done: + if (nt) + KFREE(nt); + return error; +} + + +static int fr_natgetsz(data) +caddr_t data; +{ + ap_session_t *aps; + nat_t *nat, *n; + int error = 0; + natget_t ng; + + error = IRCOPY(data, (caddr_t)&ng, sizeof(ng)); + if (error) + return EFAULT; + + nat = ng.ng_ptr; + if (!nat) { + nat = nat_instances; + ng.ng_sz = 0; + if (nat == NULL) { + error = IWCOPY((caddr_t)&ng, data, sizeof(ng)); + if (error) + error = EFAULT; + return error; + } + } else { + /* + * Make sure the pointer we're copying from exists in the + * current list of entries. Security precaution to prevent + * copying of random kernel data. + */ + for (n = nat_instances; n; n = n->nat_next) + if (n == nat) + break; + if (!n) + return ESRCH; + } + + ng.ng_sz = sizeof(nat_save_t); + aps = nat->nat_aps; + if ((aps != NULL) && (aps->aps_data != 0)) { + ng.ng_sz += sizeof(ap_session_t); + ng.ng_sz += aps->aps_psiz; + } + + error = IWCOPY((caddr_t)&ng, data, sizeof(ng)); + if (error) + error = EFAULT; + return error; +} + + +static int fr_natgetent(data) +caddr_t data; +{ + nat_save_t ipn, *ipnp, *ipnn; + register nat_t *n, *nat; + ap_session_t *aps; + int error; + + error = IRCOPY(data, (caddr_t)&ipnp, sizeof(ipnp)); + if (error) + return EFAULT; + error = IRCOPY((caddr_t)ipnp, (caddr_t)&ipn, sizeof(ipn)); + if (error) + return EFAULT; + + nat = ipn.ipn_next; + if (!nat) { + nat = nat_instances; + if (nat == NULL) { + if (nat_instances == NULL) + return ENOENT; + return 0; + } + } else { + /* + * Make sure the pointer we're copying from exists in the + * current list of entries. Security precaution to prevent + * copying of random kernel data. + */ + for (n = nat_instances; n; n = n->nat_next) + if (n == nat) + break; + if (!n) + return ESRCH; + } + + ipn.ipn_next = nat->nat_next; + ipn.ipn_dsize = 0; + bcopy((char *)nat, (char *)&ipn.ipn_nat, sizeof(ipn.ipn_nat)); + ipn.ipn_nat.nat_data = NULL; + + if (nat->nat_ptr) { + bcopy((char *)nat->nat_ptr, (char *)&ipn.ipn_ipnat, + sizeof(ipn.ipn_ipnat)); + } + + if (nat->nat_fr) + bcopy((char *)nat->nat_fr, (char *)&ipn.ipn_rule, + sizeof(ipn.ipn_rule)); + + if ((aps = nat->nat_aps)) { + ipn.ipn_dsize = sizeof(*aps); + if (aps->aps_data) + ipn.ipn_dsize += aps->aps_psiz; + KMALLOCS(ipnn, nat_save_t *, sizeof(*ipnn) + ipn.ipn_dsize); + if (ipnn == NULL) + return NULL; + bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn)); + + bcopy((char *)aps, ipn.ipn_data, sizeof(*aps)); + if (aps->aps_data) { + bcopy(aps->aps_data, ipn.ipn_data + sizeof(*aps), + aps->aps_psiz); + ipn.ipn_dsize += aps->aps_psiz; + } + error = IWCOPY((caddr_t)ipnn, ipnp, + sizeof(ipn) + ipn.ipn_dsize); + if (error) + return EFAULT; + KFREES(ipnn, sizeof(*ipnn) + ipn.ipn_dsize); + } else { + error = IWCOPY((caddr_t)&ipn, ipnp, sizeof(ipn)); + if (error) + return EFAULT; + } + return 0; +} + + +static int fr_natputent(data) +caddr_t data; +{ + nat_save_t ipn, *ipnp, *ipnn; + register nat_t *n, *nat; + ap_session_t *aps; + frentry_t *fr; + ipnat_t *in; + + int error; + + error = IRCOPY(data, (caddr_t)&ipnp, sizeof(ipnp)); + if (error) + return EFAULT; + error = IRCOPY((caddr_t)ipnp, (caddr_t)&ipn, sizeof(ipn)); + if (error) + return EFAULT; + if (ipn.ipn_dsize) { + KMALLOCS(ipnn, nat_save_t *, sizeof(ipn) + ipn.ipn_dsize); + if (ipnn == NULL) + return ENOMEM; + bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn)); + error = IRCOPY((caddr_t)ipnp, (caddr_t)ipn.ipn_data, + ipn.ipn_dsize); + if (error) + return EFAULT; + } else + ipnn = NULL; + + KMALLOC(nat, nat_t *); + if (nat == NULL) + return ENOMEM; + + bcopy((char *)&ipn.ipn_nat, (char *)nat, sizeof(*nat)); + /* + * Initialize all these so that nat_delete() doesn't cause a crash. + */ + nat->nat_hstart[0] = NULL; + nat->nat_hstart[1] = NULL; + fr = nat->nat_fr; + nat->nat_fr = NULL; + aps = nat->nat_aps; + nat->nat_aps = NULL; + in = nat->nat_ptr; + nat->nat_ptr = NULL; + nat->nat_data = NULL; + + /* + * Restore the rule associated with this nat session + */ + if (in) { + KMALLOC(in, ipnat_t *); + if (in == NULL) { + error = ENOMEM; + goto junkput; + } + nat->nat_ptr = in; + bcopy((char *)&ipn.ipn_ipnat, (char *)in, sizeof(*in)); + in->in_use = 1; + in->in_flags |= IPN_DELETE; + in->in_next = NULL; + in->in_rnext = NULL; + in->in_prnext = NULL; + in->in_mnext = NULL; + in->in_pmnext = NULL; + in->in_ifp = GETUNIT(in->in_ifname, 4); + if (in->in_plabel[0] != '\0') { + in->in_apr = appr_match(in->in_p, in->in_plabel); + } + } + + /* + * Restore ap_session_t structure. Include the private data allocated + * if it was there. + */ + if (aps) { + KMALLOC(aps, ap_session_t *); + if (aps == NULL) { + error = ENOMEM; + goto junkput; + } + nat->nat_aps = aps; + aps->aps_next = ap_sess_list; + ap_sess_list = aps; + bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps)); + if (in) + aps->aps_apr = in->in_apr; + if (aps->aps_psiz) { + KMALLOCS(aps->aps_data, void *, aps->aps_psiz); + if (aps->aps_data == NULL) { + error = ENOMEM; + goto junkput; + } + bcopy(ipnn->ipn_data + sizeof(*aps), aps->aps_data, + aps->aps_psiz); + } else { + aps->aps_psiz = 0; + aps->aps_data = NULL; + } + } + + /* + * If there was a filtering rule associated with this entry then + * build up a new one. + */ + if (fr != NULL) { + if (nat->nat_flags & FI_NEWFR) { + KMALLOC(fr, frentry_t *); + nat->nat_fr = fr; + if (fr == NULL) { + error = ENOMEM; + goto junkput; + } + bcopy((char *)&ipn.ipn_fr, (char *)fr, sizeof(*fr)); + ipn.ipn_nat.nat_fr = fr; + error = IWCOPY((caddr_t)&ipn, ipnp, sizeof(ipn)); + if (error) { + error = EFAULT; + goto junkput; + } + } else { + for (n = nat_instances; n; n = n->nat_next) + if (n->nat_fr == fr) + break; + if (!n) { + error = ESRCH; + goto junkput; + } + } + } + + if (ipnn) + KFREES(ipnn, sizeof(ipn) + ipn.ipn_dsize); + nat_insert(nat); + return 0; +junkput: + if (ipnn) + KFREES(ipnn, sizeof(ipn) + ipn.ipn_dsize); + if (nat) + nat_delete(nat); + return error; +} + + +/* + * Delete a nat entry from the various lists and table. + */ +static void nat_delete(natd) +struct nat *natd; +{ + register struct nat **natp, *nat; + struct ipnat *ipn; + + for (natp = natd->nat_hstart[0]; natp && (nat = *natp); + natp = &nat->nat_hnext[0]) + if (nat == natd) { + *natp = nat->nat_hnext[0]; + break; + } + + for (natp = natd->nat_hstart[1]; natp && (nat = *natp); + natp = &nat->nat_hnext[1]) + if (nat == natd) { + *natp = nat->nat_hnext[1]; + break; + } + + if (natd->nat_fr != NULL) { + ATOMIC_DEC32(natd->nat_fr->fr_ref); + } + + if (natd->nat_hm != NULL) + nat_hostmapdel(natd->nat_hm); + + /* + * If there is an active reference from the nat entry to its parent + * rule, decrement the rule's reference count and free it too if no + * longer being used. + */ + ipn = natd->nat_ptr; + if (ipn != NULL) { + ipn->in_space++; + ipn->in_use--; + if (!ipn->in_use && (ipn->in_flags & IPN_DELETE)) { + if (ipn->in_apr) + appr_free(ipn->in_apr); + KFREE(ipn); + nat_stats.ns_rules--; + } + } + + MUTEX_DESTROY(&natd->nat_lock); + /* + * If there's a fragment table entry too for this nat entry, then + * dereference that as well. + */ + ipfr_forget((void *)natd); + aps_free(natd->nat_aps); + nat_stats.ns_inuse--; + KFREE(natd); +} + + +/* + * nat_flushtable - clear the NAT table of all mapping entries. + */ +static int nat_flushtable() +{ + register nat_t *nat, **natp; + register int j = 0; + + /* + * ALL NAT mappings deleted, so lets just make the deletions + * quicker. + */ + if (nat_table[0] != NULL) + bzero((char *)nat_table[0], + sizeof(nat_table[0]) * ipf_nattable_sz); + if (nat_table[1] != NULL) + bzero((char *)nat_table[1], + sizeof(nat_table[1]) * ipf_nattable_sz); + + for (natp = &nat_instances; (nat = *natp); ) { + *natp = nat->nat_next; + nat_delete(nat); + j++; + } + nat_stats.ns_inuse = 0; + return j; +} + + +/* + * nat_clearlist - delete all rules in the active NAT mapping list. + */ +static int nat_clearlist() +{ + register ipnat_t *n, **np = &nat_list; + int i = 0; + + if (nat_rules != NULL) + bzero((char *)nat_rules, sizeof(*nat_rules) * ipf_natrules_sz); + if (rdr_rules != NULL) + bzero((char *)rdr_rules, sizeof(*rdr_rules) * ipf_rdrrules_sz); + + while ((n = *np)) { + *np = n->in_next; + if (!n->in_use) { + if (n->in_apr) + appr_free(n->in_apr); + KFREE(n); + nat_stats.ns_rules--; + } else { + n->in_flags |= IPN_DELETE; + n->in_next = NULL; + } + i++; + } + nat_masks = 0; + rdr_masks = 0; + return i; +} + + +/* + * Create a new NAT table entry. + * NOTE: assumes write lock on ipf_nat has been obtained already. + */ +nat_t *nat_new(np, ip, fin, flags, direction) +ipnat_t *np; +ip_t *ip; +fr_info_t *fin; +u_int flags; +int direction; +{ + register u_32_t sum1, sum2, sumd, l; + u_short port = 0, sport = 0, dport = 0, nport = 0; + struct in_addr in, inb; + tcphdr_t *tcp = NULL; + hostmap_t *hm = NULL; + nat_t *nat, *natl; + u_short nflags; +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) + qif_t *qf = fin->fin_qif; +#endif + + nflags = flags & np->in_flags; + if (flags & IPN_TCPUDP) { + tcp = (tcphdr_t *)fin->fin_dp; + sport = tcp->th_sport; + dport = tcp->th_dport; + } + + /* Give me a new nat */ + KMALLOC(nat, nat_t *); + if (nat == NULL) { + nat_stats.ns_memfail++; + return NULL; + } + + bzero((char *)nat, sizeof(*nat)); + nat->nat_flags = flags; + /* + * Search the current table for a match. + */ + if (direction == NAT_OUTBOUND) { + /* + * Values at which the search for a free resouce starts. + */ + u_32_t st_ip; + u_short st_port; + + /* + * If it's an outbound packet which doesn't match any existing + * record, then create a new port + */ + l = 0; + st_ip = np->in_nip; + st_port = np->in_pnext; + + do { + port = 0; + in.s_addr = htonl(np->in_nip); + if (l == 0) { + /* + * Check to see if there is an existing NAT + * setup for this IP address pair. + */ + hm = nat_hostmap(np, ip->ip_src, in); + if (hm != NULL) + in.s_addr = hm->hm_mapip.s_addr; + } else if ((l == 1) && (hm != NULL)) { + nat_hostmapdel(hm); + hm = NULL; + } + in.s_addr = ntohl(in.s_addr); + + nat->nat_hm = hm; + + if ((np->in_outmsk == 0xffffffff) && + (np->in_pnext == 0)) { + if (l > 0) + goto badnat; + } + + if (np->in_redir & NAT_MAPBLK) { + if ((l >= np->in_ppip) || ((l > 0) && + !(flags & IPN_TCPUDP))) + goto badnat; + /* + * map-block - Calculate destination address. + */ + in.s_addr = ntohl(ip->ip_src.s_addr); + in.s_addr &= ntohl(~np->in_inmsk); + inb.s_addr = in.s_addr; + in.s_addr /= np->in_ippip; + in.s_addr &= ntohl(~np->in_outmsk); + in.s_addr += ntohl(np->in_outip); + /* + * Calculate destination port. + */ + if ((flags & IPN_TCPUDP) && + (np->in_ppip != 0)) { + port = ntohs(sport) + l; + port %= np->in_ppip; + port += np->in_ppip * + (inb.s_addr % np->in_ippip); + port += MAPBLK_MINPORT; + port = htons(port); + } + } else if (!np->in_outip && + (np->in_outmsk == 0xffffffff)) { + /* + * 0/32 - use the interface's IP address. + */ + if ((l > 0) || + fr_ifpaddr(4, fin->fin_ifp, &in) == -1) + goto badnat; + in.s_addr = ntohl(in.s_addr); + } else if (!np->in_outip && !np->in_outmsk) { + /* + * 0/0 - use the original source address/port. + */ + if (l > 0) + goto badnat; + in.s_addr = ntohl(ip->ip_src.s_addr); + } else if ((np->in_outmsk != 0xffffffff) && + (np->in_pnext == 0) && + ((l > 0) || (hm == NULL))) + np->in_nip++; + natl = NULL; + + if ((nflags & IPN_TCPUDP) && + ((np->in_redir & NAT_MAPBLK) == 0) && + (np->in_flags & IPN_AUTOPORTMAP)) { + if ((l > 0) && (l % np->in_ppip == 0)) { + if (l > np->in_space) { + goto badnat; + } else if ((l > np->in_ppip) && + np->in_outmsk != 0xffffffff) + np->in_nip++; + } + if (np->in_ppip != 0) { + port = ntohs(sport); + port += (l % np->in_ppip); + port %= np->in_ppip; + port += np->in_ppip * + (ntohl(ip->ip_src.s_addr) % + np->in_ippip); + port += MAPBLK_MINPORT; + port = htons(port); + } + } else if (((np->in_redir & NAT_MAPBLK) == 0) && + (nflags & IPN_TCPUDP) && + (np->in_pnext != 0)) { + port = htons(np->in_pnext++); + if (np->in_pnext > ntohs(np->in_pmax)) { + np->in_pnext = ntohs(np->in_pmin); + if (np->in_outmsk != 0xffffffff) + np->in_nip++; + } + } + + if (np->in_flags & IPN_IPRANGE) { + if (np->in_nip > ntohl(np->in_outmsk)) + np->in_nip = ntohl(np->in_outip); + } else { + if ((np->in_outmsk != 0xffffffff) && + ((np->in_nip + 1) & ntohl(np->in_outmsk)) > + ntohl(np->in_outip)) + np->in_nip = ntohl(np->in_outip) + 1; + } + + if (!port && (flags & IPN_TCPUDP)) + port = sport; + + /* + * Here we do a lookup of the connection as seen from + * the outside. If an IP# pair already exists, try + * again. So if you have A->B becomes C->B, you can + * also have D->E become C->E but not D->B causing + * another C->B. Also take protocol and ports into + * account when determining whether a pre-existing + * NAT setup will cause an external conflict where + * this is appropriate. + */ + inb.s_addr = htonl(in.s_addr); + natl = nat_inlookup(fin->fin_ifp, flags & ~FI_WILDP, + (u_int)ip->ip_p, ip->ip_dst, inb, + (port << 16) | dport); + + /* + * Has the search wrapped around and come back to the + * start ? + */ + if ((natl != NULL) && + (np->in_pnext != 0) && (st_port == np->in_pnext) && + (np->in_nip != 0) && (st_ip == np->in_nip)) + goto badnat; + l++; + } while (natl != NULL); + + if (np->in_space > 0) + np->in_space--; + + /* Setup the NAT table */ + nat->nat_inip = ip->ip_src; + nat->nat_outip.s_addr = htonl(in.s_addr); + nat->nat_oip = ip->ip_dst; + if (nat->nat_hm == NULL) + nat->nat_hm = nat_hostmap(np, ip->ip_src, + nat->nat_outip); + + sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr)) + ntohs(sport); + sum2 = LONG_SUM(in.s_addr) + ntohs(port); + + if (flags & IPN_TCPUDP) { + nat->nat_inport = sport; + nat->nat_outport = port; /* sport */ + nat->nat_oport = dport; + } + } else { + /* + * Otherwise, it's an inbound packet. Most likely, we don't + * want to rewrite source ports and source addresses. Instead, + * we want to rewrite to a fixed internal address and fixed + * internal port. + */ + if (np->in_flags & IPN_SPLIT) { + in.s_addr = np->in_nip; + if (np->in_inip == htonl(in.s_addr)) + np->in_nip = ntohl(np->in_inmsk); + else { + np->in_nip = ntohl(np->in_inip); + if (np->in_flags & IPN_ROUNDR) { + nat_delrdr(np); + nat_addrdr(np); + } + } + } else { + in.s_addr = ntohl(np->in_inip); + if (np->in_flags & IPN_ROUNDR) { + nat_delrdr(np); + nat_addrdr(np); + } + } + if (!np->in_pnext) + nport = dport; + else { + /* + * Whilst not optimized for the case where + * pmin == pmax, the gain is not significant. + */ + nport = ntohs(dport) - ntohs(np->in_pmin) + + ntohs(np->in_pnext); + nport = htons(nport); + } + + /* + * When the redirect-to address is set to 0.0.0.0, just + * assume a blank `forwarding' of the packet. We don't + * setup any translation for this either. + */ + if (in.s_addr == 0) { + if (nport == dport) + goto badnat; + in.s_addr = ntohl(ip->ip_dst.s_addr); + } + + nat->nat_inip.s_addr = htonl(in.s_addr); + nat->nat_outip = ip->ip_dst; + nat->nat_oip = ip->ip_src; + + sum1 = LONG_SUM(ntohl(ip->ip_dst.s_addr)) + ntohs(dport); + sum2 = LONG_SUM(in.s_addr) + ntohs(nport); + + if (flags & IPN_TCPUDP) { + nat->nat_inport = nport; + nat->nat_outport = dport; + nat->nat_oport = sport; + } + } + + CALC_SUMD(sum1, sum2, sumd); + nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) + if ((flags == IPN_TCP) && dohwcksum && + (qf->qf_ill->ill_ick.ick_magic == ICK_M_CTL_MAGIC)) { + if (direction == NAT_OUTBOUND) + sum1 = LONG_SUM(ntohl(in.s_addr)); + else + sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr)); + sum1 += LONG_SUM(ntohl(ip->ip_dst.s_addr)); + sum1 += 30; + sum1 = (sum1 & 0xffff) + (sum1 >> 16); + nat->nat_sumd[1] = NAT_HW_CKSUM|(sum1 & 0xffff); + } else +#endif + nat->nat_sumd[1] = nat->nat_sumd[0]; + + if ((flags & IPN_TCPUDP) && ((sport != port) || (dport != nport))) { + if (direction == NAT_OUTBOUND) + sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr)); + else + sum1 = LONG_SUM(ntohl(ip->ip_dst.s_addr)); + + sum2 = LONG_SUM(in.s_addr); + + CALC_SUMD(sum1, sum2, sumd); + nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16); + } else + nat->nat_ipsumd = nat->nat_sumd[0]; + + in.s_addr = htonl(in.s_addr); + +#ifdef _KERNEL + strncpy(nat->nat_ifname, IFNAME(fin->fin_ifp), IFNAMSIZ); +#endif + nat_insert(nat); + + nat->nat_dir = direction; + nat->nat_ifp = fin->fin_ifp; + nat->nat_ptr = np; + nat->nat_p = ip->ip_p; + nat->nat_bytes = 0; + nat->nat_pkts = 0; + nat->nat_fr = fin->fin_fr; + if (nat->nat_fr != NULL) { + ATOMIC_INC32(nat->nat_fr->fr_ref); + } + if (direction == NAT_OUTBOUND) { + if (flags & IPN_TCPUDP) + tcp->th_sport = port; + } else { + if (flags & IPN_TCPUDP) + tcp->th_dport = nport; + } + np->in_use++; + return nat; +badnat: + nat_stats.ns_badnat++; + if ((hm = nat->nat_hm) != NULL) + nat_hostmapdel(hm); + KFREE(nat); + return NULL; +} + + +void nat_insert(nat) +nat_t *nat; +{ + nat_t **natp; + u_int hv; + + MUTEX_INIT(&nat->nat_lock, "nat entry lock", NULL); + + nat->nat_age = fr_defnatage; + nat->nat_ifname[sizeof(nat->nat_ifname) - 1] = '\0'; + if (nat->nat_ifname[0] !='\0') { + nat->nat_ifp = GETUNIT(nat->nat_ifname, 4); + } + + nat->nat_next = nat_instances; + nat_instances = nat; + hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, + ipf_nattable_sz); + natp = &nat_table[0][hv]; + nat->nat_hstart[0] = natp; + nat->nat_hnext[0] = *natp; + *natp = nat; + hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, + ipf_nattable_sz); + natp = &nat_table[1][hv]; + nat->nat_hstart[1] = natp; + nat->nat_hnext[1] = *natp; + *natp = nat; + + nat_stats.ns_added++; + nat_stats.ns_inuse++; +} + + +nat_t *nat_icmplookup(ip, fin, dir) +ip_t *ip; +fr_info_t *fin; +int dir; +{ + icmphdr_t *icmp; + tcphdr_t *tcp = NULL; + ip_t *oip; + int flags = 0, type; + + icmp = (icmphdr_t *)fin->fin_dp; + /* + * Does it at least have the return (basic) IP header ? + * Only a basic IP header (no options) should be with an ICMP error + * header. + */ + if ((ip->ip_hl != 5) || (ip->ip_len < ICMPERR_MINPKTLEN)) + return NULL; + type = icmp->icmp_type; + /* + * If it's not an error type, then return. + */ + if ((type != ICMP_UNREACH) && (type != ICMP_SOURCEQUENCH) && + (type != ICMP_REDIRECT) && (type != ICMP_TIMXCEED) && + (type != ICMP_PARAMPROB)) + return NULL; + + oip = (ip_t *)((char *)fin->fin_dp + 8); + if (ip->ip_len < ICMPERR_MAXPKTLEN + ((oip->ip_hl - 5) << 2)) + return NULL; + if (oip->ip_p == IPPROTO_TCP) + flags = IPN_TCP; + else if (oip->ip_p == IPPROTO_UDP) + flags = IPN_UDP; + if (flags & IPN_TCPUDP) { + tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2)); + if (dir == NAT_INBOUND) + return nat_inlookup(fin->fin_ifp, flags, + (u_int)oip->ip_p, oip->ip_dst, oip->ip_src, + (tcp->th_sport << 16) | tcp->th_dport); + else + return nat_outlookup(fin->fin_ifp, flags, + (u_int)oip->ip_p, oip->ip_dst, oip->ip_src, + (tcp->th_sport << 16) | tcp->th_dport); + } + if (dir == NAT_INBOUND) + return nat_inlookup(fin->fin_ifp, 0, (u_int)oip->ip_p, + oip->ip_dst, oip->ip_src, 0); + else + return nat_outlookup(fin->fin_ifp, 0, (u_int)oip->ip_p, + oip->ip_dst, oip->ip_src, 0); +} + + +/* + * This should *ONLY* be used for incoming packets to make sure a NAT'd ICMP + * packet gets correctly recognised. + */ +nat_t *nat_icmp(ip, fin, nflags, dir) +ip_t *ip; +fr_info_t *fin; +u_int *nflags; +int dir; +{ + u_32_t sum1, sum2, sumd; + struct in_addr in; + icmphdr_t *icmp; + nat_t *nat; + ip_t *oip; + int flags = 0; + + if ((ip->ip_v != 4) || !(nat = nat_icmplookup(ip, fin, dir))) + return NULL; + *nflags = IPN_ICMPERR; + icmp = (icmphdr_t *)fin->fin_dp; + oip = (ip_t *)&icmp->icmp_ip; + if (oip->ip_p == IPPROTO_TCP) + flags = IPN_TCP; + else if (oip->ip_p == IPPROTO_UDP) + flags = IPN_UDP; + /* + * Need to adjust ICMP header to include the real IP#'s and + * port #'s. Only apply a checksum change relative to the + * IP address change is it will be modified again in ip_natout + * for both address and port. Two checksum changes are + * necessary for the two header address changes. Be careful + * to only modify the checksum once for the port # and twice + * for the IP#. + */ + + if (nat->nat_dir == NAT_OUTBOUND) { + sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr)); + in = nat->nat_inip; + oip->ip_src = in; + } else { + sum1 = LONG_SUM(ntohl(oip->ip_dst.s_addr)); + in = nat->nat_outip; + oip->ip_dst = in; + } + + sum2 = LONG_SUM(ntohl(in.s_addr)); + + CALC_SUMD(sum1, sum2, sumd); + + if (nat->nat_dir == NAT_OUTBOUND) { + fix_incksum(&oip->ip_sum, sumd, 0); + + sumd += (sumd & 0xffff); + while (sumd > 0xffff) + sumd = (sumd & 0xffff) + (sumd >> 16); + fix_outcksum(&icmp->icmp_cksum, sumd, 0); + } else { + fix_outcksum(&oip->ip_sum, sumd, 0); + + sumd += (sumd & 0xffff); + while (sumd > 0xffff) + sumd = (sumd & 0xffff) + (sumd >> 16); +/* fix_incksum(&icmp->icmp_cksum, sumd, 0); */ + } + + + if ((flags & IPN_TCPUDP) != 0) { + tcphdr_t *tcp; + + /* XXX - what if this is bogus hl and we go off the end ? */ + tcp = (tcphdr_t *)((((char *)oip) + (oip->ip_hl << 2))); + + if (nat->nat_dir == NAT_OUTBOUND) { + if (tcp->th_sport != nat->nat_inport) { + sum1 = ntohs(tcp->th_sport); + sum2 = ntohs(nat->nat_inport); + CALC_SUMD(sum1, sum2, sumd); + tcp->th_sport = nat->nat_inport; + fix_outcksum(&icmp->icmp_cksum, sumd, 0); + } + } else { + if (tcp->th_dport != nat->nat_outport) { + sum1 = ntohs(tcp->th_dport); + sum2 = ntohs(nat->nat_outport); + CALC_SUMD(sum1, sum2, sumd); + tcp->th_dport = nat->nat_outport; + fix_incksum(&icmp->icmp_cksum, sumd, 0); + } + } + } + nat->nat_age = fr_defnaticmpage; + return nat; +} + + +/* + * NB: these lookups don't lock access to the list, it assume it has already + * been done! + */ +/* + * Lookup a nat entry based on the mapped destination ip address/port and + * real source address/port. We use this lookup when receiving a packet, + * we're looking for a table entry, based on the destination address. + * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. + */ +nat_t *nat_inlookup(ifp, flags, p, src, mapdst, ports) +void *ifp; +register u_int flags, p; +struct in_addr src , mapdst; +u_32_t ports; +{ + register u_short sport, mapdport; + register nat_t *nat; + register int nflags; + u_int hv; + + mapdport = ports >> 16; + sport = ports & 0xffff; + flags &= IPN_TCPUDP; + + hv = NAT_HASH_FN(mapdst.s_addr, mapdport, ipf_nattable_sz); + nat = nat_table[1][hv]; + for (; nat; nat = nat->nat_hnext[1]) { + nflags = nat->nat_flags; + if ((!ifp || ifp == nat->nat_ifp) && + nat->nat_oip.s_addr == src.s_addr && + nat->nat_outip.s_addr == mapdst.s_addr && + (((p == 0) && (flags == (nat->nat_flags & IPN_TCPUDP))) + || (p == nat->nat_p)) && (!flags || + (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) && + ((nat->nat_outport == mapdport) || + (nflags & FI_W_SPORT))))) + return nat; + } + return NULL; +} + + +/* + * Lookup a nat entry based on the source 'real' ip address/port and + * destination address/port. We use this lookup when sending a packet out, + * we're looking for a table entry, based on the source address. + * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. + */ +nat_t *nat_outlookup(ifp, flags, p, src, dst, ports) +void *ifp; +register u_int flags, p; +struct in_addr src , dst; +u_32_t ports; +{ + register u_short sport, dport; + register nat_t *nat; + register int nflags; + u_int hv; + + sport = ports & 0xffff; + dport = ports >> 16; + flags &= IPN_TCPUDP; + + hv = NAT_HASH_FN(src.s_addr, sport, ipf_nattable_sz); + nat = nat_table[0][hv]; + for (; nat; nat = nat->nat_hnext[0]) { + nflags = nat->nat_flags; + + if ((!ifp || ifp == nat->nat_ifp) && + nat->nat_inip.s_addr == src.s_addr && + nat->nat_oip.s_addr == dst.s_addr && + (((p == 0) && (flags == (nat->nat_flags & IPN_TCPUDP))) + || (p == nat->nat_p)) && (!flags || + ((nat->nat_inport == sport || nflags & FI_W_SPORT) && + (nat->nat_oport == dport || nflags & FI_W_DPORT)))) + return nat; + } + return NULL; +} + + +/* + * Lookup the NAT tables to search for a matching redirect + */ +nat_t *nat_lookupredir(np) +register natlookup_t *np; +{ + u_32_t ports; + nat_t *nat; + + ports = (np->nl_outport << 16) | np->nl_inport; + /* + * If nl_inip is non null, this is a lookup based on the real + * ip address. Else, we use the fake. + */ + if ((nat = nat_outlookup(NULL, np->nl_flags, 0, np->nl_inip, + np->nl_outip, ports))) { + np->nl_realip = nat->nat_outip; + np->nl_realport = nat->nat_outport; + } + return nat; +} + + +static int nat_match(fin, np, ip) +fr_info_t *fin; +ipnat_t *np; +ip_t *ip; +{ + frtuc_t *ft; + + if (ip->ip_v != 4) + return 0; + + if (np->in_p && ip->ip_p != np->in_p) + return 0; + if (fin->fin_out) { + if (!(np->in_redir && (NAT_MAP|NAT_MAPBLK))) + return 0; + if ((fin->fin_fi.fi_saddr & np->in_inmsk) != np->in_inip) + return 0; + if ((fin->fin_fi.fi_daddr & np->in_srcmsk) != np->in_srcip) + return 0; + } else { + if (!(np->in_redir && NAT_REDIRECT)) + return 0; + } + + ft = &np->in_tuc; + if (!(fin->fin_fi.fi_fl & FI_TCPUDP)) { + if (ft->ftu_scmp || ft->ftu_dcmp) + return 0; + return 1; + } + + return fr_tcpudpchk(ft, fin); +} + + +/* + * Packets going out on the external interface go through this. + * Here, the source address requires alteration, if anything. + */ +int ip_natout(ip, fin) +ip_t *ip; +fr_info_t *fin; +{ + register ipnat_t *np = NULL; + register u_32_t ipa; + tcphdr_t *tcp = NULL; + u_short sport = 0, dport = 0, *csump = NULL; + struct ifnet *ifp; + int natadd = 1; + frentry_t *fr; + u_int nflags = 0, hv, msk; + u_32_t iph; + nat_t *nat; + int i; + + if (nat_list == NULL || (fr_nat_lock)) + return 0; + + if ((fr = fin->fin_fr) && !(fr->fr_flags & FR_DUP) && + fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1) + ifp = fr->fr_tif.fd_ifp; + else + ifp = fin->fin_ifp; + + if (!(ip->ip_off & IP_OFFMASK) && !(fin->fin_fi.fi_fl & FI_SHORT)) { + if (ip->ip_p == IPPROTO_TCP) + nflags = IPN_TCP; + else if (ip->ip_p == IPPROTO_UDP) + nflags = IPN_UDP; + if ((nflags & IPN_TCPUDP)) { + tcp = (tcphdr_t *)fin->fin_dp; + sport = tcp->th_sport; + dport = tcp->th_dport; + } + } + + ipa = ip->ip_src.s_addr; + + READ_ENTER(&ipf_nat); + + if ((ip->ip_p == IPPROTO_ICMP) && + (nat = nat_icmp(ip, fin, &nflags, NAT_OUTBOUND))) + ; + else if ((ip->ip_off & (IP_OFFMASK|IP_MF)) && + (nat = ipfr_nat_knownfrag(ip, fin))) + natadd = 0; + else if ((nat = nat_outlookup(ifp, nflags, (u_int)ip->ip_p, ip->ip_src, + ip->ip_dst, (dport << 16) | sport))) { + nflags = nat->nat_flags; + if ((nflags & (FI_W_SPORT|FI_W_DPORT)) != 0) { + if ((nflags & FI_W_SPORT) && + (nat->nat_inport != sport)) + nat->nat_inport = sport; + else if ((nflags & FI_W_DPORT) && + (nat->nat_oport != dport)) + nat->nat_oport = dport; + if (nat->nat_outport == 0) + nat->nat_outport = sport; + nat->nat_flags &= ~(FI_W_DPORT|FI_W_SPORT); + nflags = nat->nat_flags; + } + } else { + RWLOCK_EXIT(&ipf_nat); + WRITE_ENTER(&ipf_nat); + /* + * If there is no current entry in the nat table for this IP#, + * create one for it (if there is a matching rule). + */ + msk = 0xffffffff; + i = 32; +maskloop: + iph = ipa & htonl(msk); + hv = NAT_HASH_FN(iph, 0, ipf_natrules_sz); + for (np = nat_rules[hv]; np; np = np->in_mnext) + { + if ((np->in_ifp && (np->in_ifp != ifp)) || + !np->in_space) + continue; + if ((np->in_flags & IPN_RF) && + !(np->in_flags & nflags)) + continue; + if (np->in_flags & IPN_FILTER) { + if (!nat_match(fin, np, ip)) + continue; + } else if ((ipa & np->in_inmsk) != np->in_inip) + continue; + if (np->in_redir & (NAT_MAP|NAT_MAPBLK)) { + if (*np->in_plabel && !appr_ok(ip, tcp, np)) + continue; + /* + * If it's a redirection, then we don't want to + * create new outgoing port stuff. + * Redirections are only for incoming + * connections. + */ + if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK))) + continue; + if ((nat = nat_new(np, ip, fin, (u_int)nflags, + NAT_OUTBOUND))) { + np->in_hits++; +#ifdef IPFILTER_LOG + nat_log(nat, (u_int)np->in_redir); +#endif + break; + } + } + } + if ((np == NULL) && (i > 0)) { + do { + i--; + msk <<= 1; + } while ((i >= 0) && ((nat_masks & (1 << i)) == 0)); + if (i >= 0) + goto maskloop; + } + MUTEX_DOWNGRADE(&ipf_nat); + } + + if (nat) { + np = nat->nat_ptr; + if (natadd && fin->fin_fi.fi_fl & FI_FRAG) + ipfr_nat_newfrag(ip, fin, 0, nat); + ip->ip_src = nat->nat_outip; + MUTEX_ENTER(&nat->nat_lock); + nat->nat_age = fr_defnatage; + nat->nat_bytes += ip->ip_len; + nat->nat_pkts++; + MUTEX_EXIT(&nat->nat_lock); + + /* + * Fix up checksums, not by recalculating them, but + * simply computing adjustments. + */ +#if SOLARIS || defined(__sgi) + if (nat->nat_dir == NAT_OUTBOUND) + fix_outcksum(&ip->ip_sum, nat->nat_ipsumd, 0); + else + fix_incksum(&ip->ip_sum, nat->nat_ipsumd, 0); +#endif + + if (!(ip->ip_off & IP_OFFMASK) && + !(fin->fin_fi.fi_fl & FI_SHORT)) { + + if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) { + tcp->th_sport = nat->nat_outport; + fin->fin_data[0] = ntohs(tcp->th_sport); + } + + if (ip->ip_p == IPPROTO_TCP) { + csump = &tcp->th_sum; + MUTEX_ENTER(&nat->nat_lock); + fr_tcp_age(&nat->nat_age, + nat->nat_tcpstate, fin, 1); + if (nat->nat_age < fr_defnaticmpage) + nat->nat_age = fr_defnaticmpage; +#ifdef LARGE_NAT + else if (nat->nat_age > fr_defnatage) + nat->nat_age = fr_defnatage; +#endif + /* + * Increase this because we may have + * "keep state" following this too and + * packet storms can occur if this is + * removed too quickly. + */ + if (nat->nat_age == fr_tcpclosed) + nat->nat_age = fr_tcplastack; + MUTEX_EXIT(&nat->nat_lock); + } else if (ip->ip_p == IPPROTO_UDP) { + udphdr_t *udp = (udphdr_t *)tcp; + + if (udp->uh_sum) + csump = &udp->uh_sum; + } else if (ip->ip_p == IPPROTO_ICMP) { + nat->nat_age = fr_defnaticmpage; + } + if (csump) { + if (nat->nat_dir == NAT_OUTBOUND) + fix_outcksum(csump, nat->nat_sumd[1], + ip->ip_len); + else + fix_incksum(csump, nat->nat_sumd[1], + ip->ip_len); + } + } + + if ((np->in_apr != NULL) && (np->in_dport == 0 || + (tcp != NULL && dport == np->in_dport))) { + i = appr_check(ip, fin, nat); + if (i == 0) + i = 1; + } else + i = 1; + ATOMIC_INCL(nat_stats.ns_mapped[1]); + RWLOCK_EXIT(&ipf_nat); /* READ */ + return i; + } + RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ + return 0; +} + + +/* + * Packets coming in from the external interface go through this. + * Here, the destination address requires alteration, if anything. + */ +int ip_natin(ip, fin) +ip_t *ip; +fr_info_t *fin; +{ + register struct in_addr src; + register struct in_addr in; + register ipnat_t *np; + u_int nflags = 0, natadd = 1, hv, msk; + struct ifnet *ifp = fin->fin_ifp; + tcphdr_t *tcp = NULL; + u_short sport = 0, dport = 0, *csump = NULL; + nat_t *nat; + u_32_t iph; + int i; + + if ((nat_list == NULL) || (ip->ip_v != 4) || (fr_nat_lock)) + return 0; + + if (!(ip->ip_off & IP_OFFMASK) && !(fin->fin_fi.fi_fl & FI_SHORT)) { + if (ip->ip_p == IPPROTO_TCP) + nflags = IPN_TCP; + else if (ip->ip_p == IPPROTO_UDP) + nflags = IPN_UDP; + if ((nflags & IPN_TCPUDP)) { + tcp = (tcphdr_t *)fin->fin_dp; + dport = tcp->th_dport; + sport = tcp->th_sport; + } + } + + in = ip->ip_dst; + /* make sure the source address is to be redirected */ + src = ip->ip_src; + + READ_ENTER(&ipf_nat); + + if ((ip->ip_p == IPPROTO_ICMP) && + (nat = nat_icmp(ip, fin, &nflags, NAT_INBOUND))) + ; + else if ((ip->ip_off & IP_OFFMASK) && + (nat = ipfr_nat_knownfrag(ip, fin))) + natadd = 0; + else if ((nat = nat_inlookup(fin->fin_ifp, nflags, (u_int)ip->ip_p, + ip->ip_src, in, (dport << 16) | sport))) { + nflags = nat->nat_flags; + if ((nflags & (FI_W_SPORT|FI_W_DPORT)) != 0) { + if ((nat->nat_oport != sport) && (nflags & FI_W_DPORT)) + nat->nat_oport = sport; + else if ((nat->nat_outport != dport) && + (nflags & FI_W_SPORT)) + nat->nat_outport = dport; + nat->nat_flags &= ~(FI_W_SPORT|FI_W_DPORT); + nflags = nat->nat_flags; + } + } else { + RWLOCK_EXIT(&ipf_nat); + WRITE_ENTER(&ipf_nat); + /* + * If there is no current entry in the nat table for this IP#, + * create one for it (if there is a matching rule). + */ + msk = 0xffffffff; + i = 32; +maskloop: + iph = in.s_addr & htonl(msk); + hv = NAT_HASH_FN(iph, 0, ipf_rdrrules_sz); + for (np = rdr_rules[hv]; np; np = np->in_rnext) { + if ((np->in_ifp && (np->in_ifp != ifp)) || + (np->in_p && (np->in_p != ip->ip_p)) || + (np->in_flags && !(nflags & np->in_flags))) + continue; + if (np->in_flags & IPN_FILTER) { + if (!nat_match(fin, np, ip)) + continue; + } else if ((in.s_addr & np->in_outmsk) != np->in_outip) + continue; + if ((np->in_redir & NAT_REDIRECT) && + (!np->in_pmin || + ((ntohs(np->in_pmax) >= ntohs(dport)) && + (ntohs(dport) >= ntohs(np->in_pmin))))) + if ((nat = nat_new(np, ip, fin, nflags, + NAT_INBOUND))) { + np->in_hits++; +#ifdef IPFILTER_LOG + nat_log(nat, (u_int)np->in_redir); +#endif + break; + } + } + + if ((np == NULL) && (i > 0)) { + do { + i--; + msk <<= 1; + } while ((i >= 0) && ((rdr_masks & (1 << i)) == 0)); + if (i >= 0) + goto maskloop; + } + MUTEX_DOWNGRADE(&ipf_nat); + } + if (nat) { + np = nat->nat_ptr; + fin->fin_fr = nat->nat_fr; + if (natadd && fin->fin_fi.fi_fl & FI_FRAG) + ipfr_nat_newfrag(ip, fin, 0, nat); + if ((np->in_apr != NULL) && (np->in_dport == 0 || + (tcp != NULL && sport == np->in_dport))) { + i = appr_check(ip, fin, nat); + if (i == -1) { + RWLOCK_EXIT(&ipf_nat); + return i; + } + } + + MUTEX_ENTER(&nat->nat_lock); + if (nflags != IPN_ICMPERR) + nat->nat_age = fr_defnatage; + + nat->nat_bytes += ip->ip_len; + nat->nat_pkts++; + MUTEX_EXIT(&nat->nat_lock); + ip->ip_dst = nat->nat_inip; + fin->fin_fi.fi_daddr = nat->nat_inip.s_addr; + + /* + * Fix up checksums, not by recalculating them, but + * simply computing adjustments. + */ +#if SOLARIS || defined(__sgi) + if (nat->nat_dir == NAT_OUTBOUND) + fix_incksum(&ip->ip_sum, nat->nat_ipsumd, 0); + else + fix_outcksum(&ip->ip_sum, nat->nat_ipsumd, 0); +#endif + if (!(ip->ip_off & IP_OFFMASK) && + !(fin->fin_fi.fi_fl & FI_SHORT)) { + + if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) { + tcp->th_dport = nat->nat_inport; + fin->fin_data[1] = ntohs(tcp->th_dport); + } + + if (ip->ip_p == IPPROTO_TCP) { + csump = &tcp->th_sum; + MUTEX_ENTER(&nat->nat_lock); + fr_tcp_age(&nat->nat_age, + nat->nat_tcpstate, fin, 0); + if (nat->nat_age < fr_defnaticmpage) + nat->nat_age = fr_defnaticmpage; +#ifdef LARGE_NAT + else if (nat->nat_age > fr_defnatage) + nat->nat_age = fr_defnatage; +#endif + /* + * Increase this because we may have + * "keep state" following this too and + * packet storms can occur if this is + * removed too quickly. + */ + if (nat->nat_age == fr_tcpclosed) + nat->nat_age = fr_tcplastack; + MUTEX_EXIT(&nat->nat_lock); + } else if (ip->ip_p == IPPROTO_UDP) { + udphdr_t *udp = (udphdr_t *)tcp; + + if (udp->uh_sum) + csump = &udp->uh_sum; + } else if (ip->ip_p == IPPROTO_ICMP) { + nat->nat_age = fr_defnaticmpage; + } + + if (csump) { + if (nat->nat_dir == NAT_OUTBOUND) + fix_incksum(csump, nat->nat_sumd[0], + 0); + else + fix_outcksum(csump, nat->nat_sumd[0], + 0); + } + } + ATOMIC_INCL(nat_stats.ns_mapped[0]); + RWLOCK_EXIT(&ipf_nat); /* READ */ + return 1; + } + RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ + return 0; +} + + +/* + * Free all memory used by NAT structures allocated at runtime. + */ +void ip_natunload() +{ + WRITE_ENTER(&ipf_nat); + (void) nat_clearlist(); + (void) nat_flushtable(); + RWLOCK_EXIT(&ipf_nat); + + if (nat_table[0] != NULL) { + KFREES(nat_table[0], sizeof(nat_t *) * ipf_nattable_sz); + nat_table[0] = NULL; + } + if (nat_table[1] != NULL) { + KFREES(nat_table[1], sizeof(nat_t *) * ipf_nattable_sz); + nat_table[1] = NULL; + } + if (nat_rules != NULL) { + KFREES(nat_rules, sizeof(ipnat_t *) * ipf_natrules_sz); + nat_rules = NULL; + } + if (rdr_rules != NULL) { + KFREES(rdr_rules, sizeof(ipnat_t *) * ipf_rdrrules_sz); + rdr_rules = NULL; + } + if (maptable != NULL) { + KFREES(maptable, sizeof(hostmap_t *) * ipf_hostmap_sz); + maptable = NULL; + } +} + + +/* + * Slowly expire held state for NAT entries. Timeouts are set in + * expectation of this being called twice per second. + */ +void ip_natexpire() +{ + register struct nat *nat, **natp; +#if defined(_KERNEL) && !SOLARIS + int s; +#endif + + SPL_NET(s); + WRITE_ENTER(&ipf_nat); + for (natp = &nat_instances; (nat = *natp); ) { + nat->nat_age--; + if (nat->nat_age) { + natp = &nat->nat_next; + continue; + } + *natp = nat->nat_next; +#ifdef IPFILTER_LOG + nat_log(nat, NL_EXPIRE); +#endif + nat_delete(nat); + nat_stats.ns_expire++; + } + RWLOCK_EXIT(&ipf_nat); + SPL_X(s); +} + + +/* + */ +void ip_natsync(ifp) +void *ifp; +{ + register ipnat_t *n; + register nat_t *nat; + register u_32_t sum1, sum2, sumd; + struct in_addr in; + ipnat_t *np; + void *ifp2; +#if defined(_KERNEL) && !SOLARIS + int s; +#endif + + /* + * Change IP addresses for NAT sessions for any protocol except TCP + * since it will break the TCP connection anyway. + */ + SPL_NET(s); + WRITE_ENTER(&ipf_nat); + for (nat = nat_instances; nat; nat = nat->nat_next) + if (((ifp == NULL) || (ifp == nat->nat_ifp)) && + !(nat->nat_flags & IPN_TCP) && (np = nat->nat_ptr) && + (np->in_outmsk == 0xffffffff) && !np->in_nip) { + ifp2 = nat->nat_ifp; + /* + * Change the map-to address to be the same as the + * new one. + */ + sum1 = nat->nat_outip.s_addr; + if (fr_ifpaddr(4, ifp2, &in) != -1) + nat->nat_outip = in; + sum2 = nat->nat_outip.s_addr; + + if (sum1 == sum2) + continue; + /* + * Readjust the checksum adjustment to take into + * account the new IP#. + */ + CALC_SUMD(sum1, sum2, sumd); + /* XXX - dont change for TCP when solaris does + * hardware checksumming. + */ + sumd += nat->nat_sumd[0]; + nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); + nat->nat_sumd[1] = nat->nat_sumd[0]; + } + + for (n = nat_list; (n != NULL); n = n->in_next) + if (n->in_ifp == ifp) { + n->in_ifp = (void *)GETUNIT(n->in_ifname, 4); + if (!n->in_ifp) + n->in_ifp = (void *)-1; + } + RWLOCK_EXIT(&ipf_nat); + SPL_X(s); +} + + +#ifdef IPFILTER_LOG +void nat_log(nat, type) +struct nat *nat; +u_int type; +{ + struct ipnat *np; + struct natlog natl; + void *items[1]; + size_t sizes[1]; + int rulen, types[1]; + + natl.nl_inip = nat->nat_inip; + natl.nl_outip = nat->nat_outip; + natl.nl_origip = nat->nat_oip; + natl.nl_bytes = nat->nat_bytes; + natl.nl_pkts = nat->nat_pkts; + natl.nl_origport = nat->nat_oport; + natl.nl_inport = nat->nat_inport; + natl.nl_outport = nat->nat_outport; + natl.nl_p = nat->nat_p; + natl.nl_type = type; + natl.nl_rule = -1; +#ifndef LARGE_NAT + if (nat->nat_ptr != NULL) { + for (rulen = 0, np = nat_list; np; np = np->in_next, rulen++) + if (np == nat->nat_ptr) { + natl.nl_rule = rulen; + break; + } + } +#endif + items[0] = &natl; + sizes[0] = sizeof(natl); + types[0] = 0; + + (void) ipllog(IPL_LOGNAT, NULL, items, sizes, types, 1); +} +#endif Property changes on: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_nat.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_nat.h =================================================================== --- vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_nat.h (nonexistent) +++ vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_nat.h (revision 60849) @@ -0,0 +1,294 @@ +/* + * Copyright (C) 1995-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. + * + * @(#)ip_nat.h 1.5 2/4/96 + * $Id: ip_nat.h,v 2.17.2.1 2000/05/15 06:50:14 darrenr Exp $ + */ + +#ifndef __IP_NAT_H__ +#define __IP_NAT_H__ + +#ifndef SOLARIS +#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +#endif + +#if defined(__STDC__) || defined(__GNUC__) +#define SIOCADNAT _IOW('r', 60, struct ipnat *) +#define SIOCRMNAT _IOW('r', 61, struct ipnat *) +#define SIOCGNATS _IOWR('r', 62, struct natstat *) +#define SIOCGNATL _IOWR('r', 63, struct natlookup *) +#else +#define SIOCADNAT _IOW(r, 60, struct ipnat *) +#define SIOCRMNAT _IOW(r, 61, struct ipnat *) +#define SIOCGNATS _IOWR(r, 62, struct natstat *) +#define SIOCGNATL _IOWR(r, 63, struct natlookup *) +#endif + +#undef LARGE_NAT /* define this if you're setting up a system to NAT + * LARGE numbers of networks/hosts - i.e. in the + * hundreds or thousands. In such a case, you should + * also change the RDR_SIZE and NAT_SIZE below to more + * appropriate sizes. The figures below were used for + * a setup with 1000-2000 networks to NAT. + */ +#define NAT_SIZE 127 +#define RDR_SIZE 127 +#define HOSTMAP_SIZE 127 +#define NAT_TABLE_SZ 127 +#ifdef LARGE_NAT +#undef NAT_SIZE +#undef RDR_SIZE +#undef NAT_TABLE_SZ +#undef HOSTMAP_SIZE 127 +#define NAT_SIZE 2047 +#define RDR_SIZE 2047 +#define NAT_TABLE_SZ 16383 +#define HOSTMAP_SIZE 8191 +#endif +#ifndef APR_LABELLEN +#define APR_LABELLEN 16 +#endif +#define NAT_HW_CKSUM 0x80000000 + +#define DEF_NAT_AGE 1200 /* 10 minutes (600 seconds) */ + +struct ap_session; + +typedef struct nat { + u_long nat_age; + int nat_flags; + u_32_t nat_sumd[2]; + u_32_t nat_ipsumd; + void *nat_data; + struct ap_session *nat_aps; /* proxy session */ + struct frentry *nat_fr; /* filter rule ptr if appropriate */ + struct in_addr nat_inip; + struct in_addr nat_outip; + struct in_addr nat_oip; /* other ip */ + U_QUAD_T nat_pkts; + U_QUAD_T nat_bytes; + u_short nat_oport; /* other port */ + u_short nat_inport; + u_short nat_outport; + u_short nat_use; + u_char nat_tcpstate[2]; + u_char nat_p; /* protocol for NAT */ + struct ipnat *nat_ptr; /* pointer back to the rule */ + struct hostmap *nat_hm; + struct nat *nat_next; + struct nat *nat_hnext[2]; + struct nat **nat_hstart[2]; + void *nat_ifp; + int nat_dir; + char nat_ifname[IFNAMSIZ]; +#if SOLARIS || defined(_sgi) + kmutex_t nat_lock; +#endif +} nat_t; + +typedef struct ipnat { + struct ipnat *in_next; + struct ipnat *in_rnext; + struct ipnat **in_prnext; + struct ipnat *in_mnext; + struct ipnat **in_pmnext; + void *in_ifp; + void *in_apr; + u_long in_space; + u_int in_use; + u_int in_hits; + struct in_addr in_nextip; + u_short in_pnext; + u_short in_ppip; /* ports per IP */ + u_short in_ippip; /* IP #'s per IP# */ + u_short in_flags; /* From here to in_dport must be reflected */ + u_short in_port[2]; /* correctly in IPN_CMPSIZ */ + struct in_addr in_in[2]; + struct in_addr in_out[2]; + struct in_addr in_src[2]; + struct frtuc in_tuc; + int in_redir; /* 0 if it's a mapping, 1 if it's a hard redir */ + char in_ifname[IFNAMSIZ]; + char in_plabel[APR_LABELLEN]; /* proxy label */ + char in_p; /* protocol */ +} ipnat_t; + +#define in_pmin in_port[0] /* Also holds static redir port */ +#define in_pmax in_port[1] +#define in_nip in_nextip.s_addr +#define in_inip in_in[0].s_addr +#define in_inmsk in_in[1].s_addr +#define in_outip in_out[0].s_addr +#define in_outmsk in_out[1].s_addr +#define in_srcip in_src[0].s_addr +#define in_srcmsk in_src[1].s_addr +#define in_scmp in_tuc.ftu_scmp +#define in_dcmp in_tuc.ftu_dcmp +#define in_stop in_tuc.ftu_stop +#define in_dtop in_tuc.ftu_dtop +#define in_sport in_tuc.ftu_sport +#define in_dport in_tuc.ftu_dport + +#define NAT_OUTBOUND 0 +#define NAT_INBOUND 1 + +#define NAT_MAP 0x01 +#define NAT_REDIRECT 0x02 +#define NAT_BIMAP (NAT_MAP|NAT_REDIRECT) +#define NAT_MAPBLK 0x04 + +#define MAPBLK_MINPORT 1024 /* don't use reserved ports for src port */ +#define USABLE_PORTS (65536 - MAPBLK_MINPORT) + +#define IPN_CMPSIZ (sizeof(ipnat_t) - offsetof(ipnat_t, in_flags)) + +typedef struct natlookup { + struct in_addr nl_inip; + struct in_addr nl_outip; + struct in_addr nl_realip; + int nl_flags; + u_short nl_inport; + u_short nl_outport; + u_short nl_realport; +} natlookup_t; + + +typedef struct nat_save { + void *ipn_next; + struct nat ipn_nat; + struct ipnat ipn_ipnat; + struct frentry ipn_fr; + int ipn_dsize; + char ipn_data[4]; +} nat_save_t; + +#define ipn_rule ipn_nat.nat_fr + +typedef struct natget { + void *ng_ptr; + int ng_sz; +} natget_t; + + +typedef struct hostmap { + struct hostmap *hm_next; + struct hostmap **hm_pnext; + struct ipnat *hm_ipnat; + struct in_addr hm_realip; + struct in_addr hm_mapip; + int hm_ref; +} hostmap_t; + + +typedef struct natstat { + u_long ns_mapped[2]; + u_long ns_rules; + u_long ns_added; + u_long ns_expire; + u_long ns_inuse; + u_long ns_logged; + u_long ns_logfail; + u_long ns_memfail; + u_long ns_badnat; + nat_t **ns_table[2]; + ipnat_t *ns_list; + void *ns_apslist; + u_int ns_nattab_sz; + u_int ns_rultab_sz; + u_int ns_rdrtab_sz; + nat_t *ns_instances; +} natstat_t; + +#define IPN_ANY 0x000 +#define IPN_TCP 0x001 +#define IPN_UDP 0x002 +#define IPN_TCPUDP (IPN_TCP|IPN_UDP) +#define IPN_DELETE 0x004 +#define IPN_ICMPERR 0x008 +#define IPN_RF (IPN_TCPUDP|IPN_DELETE|IPN_ICMPERR) +#define IPN_AUTOPORTMAP 0x010 +#define IPN_IPRANGE 0x020 +#define IPN_USERFLAGS (IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_IPRANGE|\ + IPN_SPLIT|IPN_ROUNDR|IPN_FILTER) +#define IPN_FILTER 0x040 +#define IPN_SPLIT 0x080 +#define IPN_ROUNDR 0x100 + + +typedef struct natlog { + struct in_addr nl_origip; + struct in_addr nl_outip; + struct in_addr nl_inip; + u_short nl_origport; + u_short nl_outport; + u_short nl_inport; + u_short nl_type; + int nl_rule; + U_QUAD_T nl_pkts; + U_QUAD_T nl_bytes; + u_char nl_p; +} natlog_t; + + +#define NL_NEWMAP NAT_MAP +#define NL_NEWRDR NAT_REDIRECT +#define NL_EXPIRE 0xffff + +#define NAT_HASH_FN(k,l,m) (((k) + ((k) >> 12) + l) % (m)) + +#define LONG_SUM(in) (((in) & 0xffff) + ((in) >> 16)) + +#define CALC_SUMD(s1, s2, sd) { \ + (s1) = ((s1) & 0xffff) + ((s1) >> 16); \ + (s2) = ((s2) & 0xffff) + ((s2) >> 16); \ + /* Do it twice */ \ + (s1) = ((s1) & 0xffff) + ((s1) >> 16); \ + (s2) = ((s2) & 0xffff) + ((s2) >> 16); \ + /* Because ~1 == -2, We really need ~1 == -1 */ \ + if ((s1) > (s2)) (s2)--; \ + (sd) = (s2) - (s1); \ + (sd) = ((sd) & 0xffff) + ((sd) >> 16); } + + +extern u_int ipf_nattable_sz; +extern u_int ipf_natrules_sz; +extern u_int ipf_rdrrules_sz; +extern int fr_nat_lock; +extern void ip_natsync __P((void *)); +extern u_long fr_defnatage; +extern u_long fr_defnaticmpage; +extern nat_t **nat_table[2]; +extern nat_t *nat_instances; +extern ipnat_t **nat_rules; +extern ipnat_t **rdr_rules; +extern natstat_t nat_stats; +#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) +extern int nat_ioctl __P((caddr_t, u_long, int)); +#else +extern int nat_ioctl __P((caddr_t, int, int)); +#endif +extern int nat_init __P((void)); +extern nat_t *nat_new __P((ipnat_t *, ip_t *, fr_info_t *, u_int, int)); +extern nat_t *nat_outlookup __P((void *, u_int, u_int, struct in_addr, + struct in_addr, u_32_t)); +extern nat_t *nat_inlookup __P((void *, u_int, u_int, struct in_addr, + struct in_addr, u_32_t)); +extern nat_t *nat_maplookup __P((void *, u_int, struct in_addr, + struct in_addr)); +extern nat_t *nat_lookupredir __P((natlookup_t *)); +extern nat_t *nat_icmplookup __P((ip_t *, fr_info_t *, int)); +extern nat_t *nat_icmp __P((ip_t *, fr_info_t *, u_int *, int)); +extern void nat_insert __P((nat_t *)); + +extern int ip_natout __P((ip_t *, fr_info_t *)); +extern int ip_natin __P((ip_t *, fr_info_t *)); +extern void ip_natunload __P((void)), ip_natexpire __P((void)); +extern void nat_log __P((struct nat *, u_int)); +extern void fix_incksum __P((u_short *, u_32_t, int)); +extern void fix_outcksum __P((u_short *, u_32_t, int)); + +#endif /* __IP_NAT_H__ */ Property changes on: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_nat.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_proxy.c =================================================================== --- vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_proxy.c (nonexistent) +++ vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_proxy.c (revision 60849) @@ -0,0 +1,451 @@ +/* + * Copyright (C) 1997-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. + */ +#if !defined(lint) +static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 2.9.2.1 2000/05/06 12:30:50 darrenr Exp $"; +#endif + +#if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) +# define _KERNEL +#endif + +#include +#include +#include +#include +#include +#if !defined(__FreeBSD_version) +# include +#endif +#include +#include +#if !defined(_KERNEL) && !defined(KERNEL) +# include +# include +# include +#endif +#ifndef linux +# include +#endif +#include +#if defined(_KERNEL) +# if !defined(linux) +# include +# else +# include +# endif +#endif +#if !defined(__SVR4) && !defined(__svr4__) +# ifndef linux +# include +# endif +#else +# include +# ifdef _KERNEL +# include +# endif +# include +# include +#endif +#if __FreeBSD__ > 2 +# include +#endif +#include +#ifdef sun +# include +#endif +#include +#include +#include +#include +#ifndef linux +# include +#endif +#include +#include +#include +#include "netinet/ip_compat.h" +#include +#include "netinet/ip_fil.h" +#include "netinet/ip_proxy.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_state.h" +#if (__FreeBSD_version >= 300000) +# include +#endif + + +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +static ap_session_t *appr_new_session __P((aproxy_t *, ip_t *, + fr_info_t *, nat_t *)); +static int appr_fixseqack __P((fr_info_t *, ip_t *, ap_session_t *, int )); + + +#define AP_SESS_SIZE 53 + +#if defined(_KERNEL) && !defined(linux) +#include "netinet/ip_ftp_pxy.c" +#include "netinet/ip_rcmd_pxy.c" +#include "netinet/ip_raudio_pxy.c" +#endif + +ap_session_t *ap_sess_tab[AP_SESS_SIZE]; +ap_session_t *ap_sess_list = NULL; +aproxy_t *ap_proxylist = NULL; +aproxy_t ap_proxies[] = { +#ifdef IPF_FTP_PROXY + { NULL, "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, NULL, + ippr_ftp_new, ippr_ftp_in, ippr_ftp_out }, +#endif +#ifdef IPF_RCMD_PROXY + { NULL, "rcmd", (char)IPPROTO_TCP, 0, 0, ippr_rcmd_init, NULL, + ippr_rcmd_new, NULL, ippr_rcmd_out }, +#endif +#ifdef IPF_RAUDIO_PROXY + { NULL, "raudio", (char)IPPROTO_TCP, 0, 0, ippr_raudio_init, NULL, + ippr_raudio_new, ippr_raudio_in, ippr_raudio_out }, +#endif + { NULL, "", '\0', 0, 0, NULL, NULL } +}; + + +int appr_add(ap) +aproxy_t *ap; +{ + aproxy_t *a; + + for (a = ap_proxies; a->apr_p; a++) + if ((a->apr_p == ap->apr_p) && + !strncmp(a->apr_label, ap->apr_label, + sizeof(ap->apr_label))) + return -1; + + for (a = ap_proxylist; a->apr_p; a = a->apr_next) + if ((a->apr_p == ap->apr_p) && + !strncmp(a->apr_label, ap->apr_label, + sizeof(ap->apr_label))) + return -1; + ap->apr_next = ap_proxylist; + ap_proxylist = ap; + return (*ap->apr_init)(); +} + + +int appr_del(ap) +aproxy_t *ap; +{ + aproxy_t *a, **app; + + for (app = &ap_proxylist; (a = *app); app = &a->apr_next) + if (a == ap) { + if (ap->apr_ref != 0) + return 1; + *app = a->apr_next; + return 0; + } + return -1; +} + + +int appr_ok(ip, tcp, nat) +ip_t *ip; +tcphdr_t *tcp; +ipnat_t *nat; +{ + aproxy_t *apr = nat->in_apr; + u_short dport = nat->in_dport; + + if (!apr || (apr->apr_flags & APR_DELETE) || + (ip->ip_p != apr->apr_p)) + return 0; + if ((tcp && (tcp->th_dport != dport)) || (!tcp && dport)) + return 0; + return 1; +} + + +/* + * Allocate a new application proxy structure and fill it in with the + * relevant details. call the init function once complete, prior to + * returning. + */ +static ap_session_t *appr_new_session(apr, ip, fin, nat) +aproxy_t *apr; +ip_t *ip; +fr_info_t *fin; +nat_t *nat; +{ + register ap_session_t *aps; + + if (!apr || (apr->apr_flags & APR_DELETE) || (ip->ip_p != apr->apr_p)) + return NULL; + + KMALLOC(aps, ap_session_t *); + if (!aps) + return NULL; + bzero((char *)aps, sizeof(*aps)); + aps->aps_p = ip->ip_p; + aps->aps_data = NULL; + aps->aps_apr = apr; + aps->aps_psiz = 0; + if (apr->apr_new != NULL) + if ((*apr->apr_new)(fin, ip, aps, nat) == -1) { + KFREE(aps); + return NULL; + } + aps->aps_nat = nat; + aps->aps_next = ap_sess_list; + ap_sess_list = aps; + return aps; +} + + +/* + * check to see if a packet should be passed through an active proxy routine + * if one has been setup for it. + */ +int appr_check(ip, fin, nat) +ip_t *ip; +fr_info_t *fin; +nat_t *nat; +{ + ap_session_t *aps; + aproxy_t *apr; + tcphdr_t *tcp = NULL; + u_32_t sum; + short rv; + int err; + + if (nat->nat_aps == NULL) + nat->nat_aps = appr_new_session(nat->nat_ptr->in_apr, ip, + fin, nat); + aps = nat->nat_aps; + if ((aps != NULL) && (aps->aps_p == ip->ip_p)) { + if (ip->ip_p == IPPROTO_TCP) { + tcp = (tcphdr_t *)fin->fin_dp; + /* + * verify that the checksum is correct. If not, then + * don't do anything with this packet. + */ +#if SOLARIS && defined(_KERNEL) + sum = fr_tcpsum(fin->fin_qfm, ip, tcp); +#else + sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, tcp); +#endif + if (sum != tcp->th_sum) { + frstats[fin->fin_out].fr_tcpbad++; + return -1; + } + } + + apr = aps->aps_apr; + err = 0; + if (fin->fin_out != 0) { + if (apr->apr_outpkt != NULL) + err = (*apr->apr_outpkt)(fin, ip, aps, nat); + } else { + if (apr->apr_inpkt != NULL) + err = (*apr->apr_inpkt)(fin, ip, aps, nat); + } + + rv = APR_EXIT(err); + if (rv == -1) + return rv; + + if (tcp != NULL) { + err = appr_fixseqack(fin, ip, aps, APR_INC(err)); +#if SOLARIS && defined(_KERNEL) + tcp->th_sum = fr_tcpsum(fin->fin_qfm, ip, tcp); +#else + tcp->th_sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, tcp); +#endif + } + aps->aps_bytes += ip->ip_len; + aps->aps_pkts++; + return 1; + } + return 0; +} + + +aproxy_t *appr_match(pr, name) +u_int pr; +char *name; +{ + aproxy_t *ap; + + for (ap = ap_proxies; ap->apr_p; ap++) + if ((ap->apr_p == pr) && + !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) { + ap->apr_ref++; + return ap; + } + + for (ap = ap_proxylist; ap; ap = ap->apr_next) + if ((ap->apr_p == pr) && + !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) { + ap->apr_ref++; + return ap; + } + return NULL; +} + + +void appr_free(ap) +aproxy_t *ap; +{ + ap->apr_ref--; +} + + +void aps_free(aps) +ap_session_t *aps; +{ + ap_session_t *a, **ap; + + if (!aps) + return; + + for (ap = &ap_sess_list; (a = *ap); ap = &a->aps_next) + if (a == aps) { + *ap = a->aps_next; + break; + } + + if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) + KFREES(aps->aps_data, aps->aps_psiz); + KFREE(aps); +} + + +static int appr_fixseqack(fin, ip, aps, inc) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +int inc; +{ + int sel, ch = 0, out, nlen; + u_32_t seq1, seq2; + tcphdr_t *tcp; + + tcp = (tcphdr_t *)fin->fin_dp; + out = fin->fin_out; + nlen = ip->ip_len; + nlen -= (ip->ip_hl << 2) + (tcp->th_off << 2); + + if (out != 0) { + seq1 = (u_32_t)ntohl(tcp->th_seq); + sel = aps->aps_sel[out]; + + /* switch to other set ? */ + if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) && + (seq1 > aps->aps_seqmin[!sel])) + sel = aps->aps_sel[out] = !sel; + + if (aps->aps_seqoff[sel]) { + seq2 = aps->aps_seqmin[sel] - aps->aps_seqoff[sel]; + if (seq1 > seq2) { + seq2 = aps->aps_seqoff[sel]; + seq1 += seq2; + tcp->th_seq = htonl(seq1); + ch = 1; + } + } + + if (inc && (seq1 > aps->aps_seqmin[!sel])) { + aps->aps_seqmin[!sel] = seq1 + nlen - 1; + aps->aps_seqoff[!sel] = aps->aps_seqoff[sel] + inc; + } + + /***/ + + seq1 = ntohl(tcp->th_ack); + sel = aps->aps_sel[1 - out]; + + /* switch to other set ? */ + if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) && + (seq1 > aps->aps_ackmin[!sel])) + sel = aps->aps_sel[1 - out] = !sel; + + if (aps->aps_ackoff[sel] && (seq1 > aps->aps_ackmin[sel])) { + seq2 = aps->aps_ackoff[sel]; + tcp->th_ack = htonl(seq1 - seq2); + ch = 1; + } + } else { + seq1 = ntohl(tcp->th_seq); + sel = aps->aps_sel[out]; + + /* switch to other set ? */ + if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) && + (seq1 > aps->aps_ackmin[!sel])) + sel = aps->aps_sel[out] = !sel; + + if (aps->aps_ackoff[sel]) { + seq2 = aps->aps_ackmin[sel] - + aps->aps_ackoff[sel]; + if (seq1 > seq2) { + seq2 = aps->aps_ackoff[sel]; + seq1 += seq2; + tcp->th_seq = htonl(seq1); + ch = 1; + } + } + + if (inc && (seq1 > aps->aps_ackmin[!sel])) { + aps->aps_ackmin[!sel] = seq1 + nlen - 1; + aps->aps_ackoff[!sel] = aps->aps_ackoff[sel] + inc; + } + + /***/ + + seq1 = ntohl(tcp->th_ack); + sel = aps->aps_sel[1 - out]; + + /* switch to other set ? */ + if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) && + (seq1 > aps->aps_seqmin[!sel])) + sel = aps->aps_sel[1 - out] = !sel; + + if (aps->aps_seqoff[sel] && (seq1 > aps->aps_seqmin[sel])) { + seq2 = aps->aps_seqoff[sel]; + tcp->th_ack = htonl(seq1 - seq2); + ch = 1; + } + } + return ch ? 2 : 0; +} + + +int appr_init() +{ + aproxy_t *ap; + int err = 0; + + for (ap = ap_proxies; ap->apr_p; ap++) { + err = (*ap->apr_init)(); + if (err != 0) + break; + } + return err; +} + + +void appr_unload() +{ + aproxy_t *ap; + + for (ap = ap_proxies; ap->apr_p; ap++) + if (ap->apr_fini) + (*ap->apr_fini)(); + for (ap = ap_proxylist; ap; ap = ap->apr_next) + if (ap->apr_fini) + (*ap->apr_fini)(); +} Property changes on: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_proxy.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_proxy.h =================================================================== --- vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_proxy.h (nonexistent) +++ vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_proxy.h (revision 60849) @@ -0,0 +1,155 @@ +/* + * Copyright (C) 1997-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. + * + * $Id: ip_proxy.h,v 2.8.2.3 2000/05/06 12:32:43 darrenr Exp $ + */ + +#ifndef __IP_PROXY_H__ +#define __IP_PROXY_H__ + +#ifndef SOLARIS +#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +#endif + +#ifndef APR_LABELLEN +#define APR_LABELLEN 16 +#endif +#define AP_SESS_SIZE 53 + +struct nat; +struct ipnat; + +typedef struct ap_tcp { + u_short apt_sport; /* source port */ + u_short apt_dport; /* destination port */ + short apt_sel[2]; /* {seq,ack}{off,min} set selector */ + short apt_seqoff[2]; /* sequence # difference */ + tcp_seq apt_seqmin[2]; /* don't change seq-off until after this */ + short apt_ackoff[2]; /* sequence # difference */ + tcp_seq apt_ackmin[2]; /* don't change seq-off until after this */ + u_char apt_state[2]; /* connection state */ +} ap_tcp_t; + +typedef struct ap_udp { + u_short apu_sport; /* source port */ + u_short apu_dport; /* destination port */ +} ap_udp_t; + +typedef struct ap_session { + struct aproxy *aps_apr; + union { + struct ap_tcp apu_tcp; + struct ap_udp apu_udp; + } aps_un; + u_int aps_flags; + U_QUAD_T aps_bytes; /* bytes sent */ + U_QUAD_T aps_pkts; /* packets sent */ + void *aps_nat; /* pointer back to nat struct */ + void *aps_data; /* private data */ + int aps_p; /* protocol */ + int aps_psiz; /* size of private data */ + struct ap_session *aps_hnext; + struct ap_session *aps_next; +} ap_session_t; + +#define aps_sport aps_un.apu_tcp.apt_sport +#define aps_dport aps_un.apu_tcp.apt_dport +#define aps_sel aps_un.apu_tcp.apt_sel +#define aps_seqoff aps_un.apu_tcp.apt_seqoff +#define aps_seqmin aps_un.apu_tcp.apt_seqmin +#define aps_state aps_un.apu_tcp.apt_state +#define aps_ackoff aps_un.apu_tcp.apt_ackoff +#define aps_ackmin aps_un.apu_tcp.apt_ackmin + + +typedef struct aproxy { + struct aproxy *apr_next; + char apr_label[APR_LABELLEN]; /* Proxy label # */ + u_char apr_p; /* protocol */ + int apr_ref; /* +1 per rule referencing it */ + int apr_flags; + int (* apr_init) __P((void)); + void (* apr_fini) __P((void)); + int (* apr_new) __P((fr_info_t *, ip_t *, + ap_session_t *, struct nat *)); + int (* apr_inpkt) __P((fr_info_t *, ip_t *, + ap_session_t *, struct nat *)); + int (* apr_outpkt) __P((fr_info_t *, ip_t *, + ap_session_t *, struct nat *)); +} aproxy_t; + +#define APR_DELETE 1 + +#define APR_ERR(x) (((x) & 0xffff) << 16) +#define APR_EXIT(x) (((x) >> 16) & 0xffff) +#define APR_INC(x) ((x) & 0xffff) + +#define FTP_BUFSZ 160 +/* + * For the ftp proxy. + */ +typedef struct ftpside { + char *ftps_rptr; + char *ftps_wptr; + u_32_t ftps_seq; + int ftps_junk; + char ftps_buf[FTP_BUFSZ]; +} ftpside_t; + +typedef struct ftpinfo { + u_int ftp_passok; + ftpside_t ftp_side[2]; +} ftpinfo_t; + +/* + * Real audio proxy structure and #defines + */ +typedef struct { + int rap_seenpna; + int rap_seenver; + int rap_version; + int rap_eos; /* End Of Startup */ + int rap_gotid; + int rap_gotlen; + int rap_mode; + int rap_sdone; + u_short rap_plport; + u_short rap_prport; + u_short rap_srport; + char rap_svr[19]; + u_32_t rap_sbf; /* flag to indicate which of the 19 bytes have + * been filled + */ + tcp_seq rap_sseq; +} raudio_t; + +#define RA_ID_END 0 +#define RA_ID_UDP 1 +#define RA_ID_ROBUST 7 + +#define RAP_M_UDP 1 +#define RAP_M_ROBUST 2 +#define RAP_M_TCP 4 +#define RAP_M_UDP_ROBUST (RAP_M_UDP|RAP_M_ROBUST) + + +extern ap_session_t *ap_sess_tab[AP_SESS_SIZE]; +extern ap_session_t *ap_sess_list; +extern aproxy_t ap_proxies[]; +extern int ippr_ftp_pasvonly; + +extern int appr_add __P((aproxy_t *)); +extern int appr_del __P((aproxy_t *)); +extern int appr_init __P((void)); +extern void appr_unload __P((void)); +extern int appr_ok __P((ip_t *, tcphdr_t *, struct ipnat *)); +extern void appr_free __P((aproxy_t *)); +extern void aps_free __P((ap_session_t *)); +extern int appr_check __P((ip_t *, fr_info_t *, struct nat *)); +extern aproxy_t *appr_match __P((u_int, char *)); + +#endif /* __IP_PROXY_H__ */ Property changes on: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_proxy.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_raudio_pxy.c =================================================================== --- vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_raudio_pxy.c (nonexistent) +++ vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_raudio_pxy.c (revision 60849) @@ -0,0 +1,307 @@ +/* + * $Id: ip_raudio_pxy.c,v 1.7.2.1 2000/05/06 11:19:33 darrenr Exp $ + */ +#if SOLARIS && defined(_KERNEL) +extern kmutex_t ipf_rw; +#endif + +#define IPF_RAUDIO_PROXY + + +int ippr_raudio_init __P((void)); +int ippr_raudio_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_raudio_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_raudio_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); + +static frentry_t raudiofr; + + +/* + * Real Audio application proxy initialization. + */ +int ippr_raudio_init() +{ + bzero((char *)&raudiofr, sizeof(raudiofr)); + raudiofr.fr_ref = 1; + raudiofr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + return 0; +} + + +/* + * Setup for a new proxy to handle Real Audio. + */ +int ippr_raudio_new(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + raudio_t *rap; + + + KMALLOCS(aps->aps_data, void *, sizeof(raudio_t)); + if (aps->aps_data == NULL) + return -1; + + bzero(aps->aps_data, sizeof(raudio_t)); + rap = aps->aps_data; + aps->aps_psiz = sizeof(raudio_t); + rap->rap_mode = RAP_M_TCP; /* default is for TCP */ + return 0; +} + + + +int ippr_raudio_out(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + raudio_t *rap = aps->aps_data; + unsigned char membuf[512 + 1], *s; + u_short id = 0; + tcphdr_t *tcp; + int off, dlen; + int len = 0; + mb_t *m; +#if SOLARIS + mb_t *m1; +#endif + + /* + * If we've already processed the start messages, then nothing left + * for the proxy to do. + */ + if (rap->rap_eos == 1) + return 0; + + tcp = (tcphdr_t *)fin->fin_dp; + off = (ip->ip_hl << 2) + (tcp->th_off << 2); + bzero(membuf, sizeof(membuf)); +#if SOLARIS + m = fin->fin_qfm; + + dlen = msgdsize(m) - off; + if (dlen <= 0) + return 0; + copyout_mblk(m, off, MIN(sizeof(membuf), dlen), (char *)membuf); +#else + m = *(mb_t **)fin->fin_mp; + + dlen = mbufchainlen(m) - off; + if (dlen <= 0) + return 0; + m_copydata(m, off, MIN(sizeof(membuf), dlen), (char *)membuf); +#endif + /* + * In all the startup parsing, ensure that we don't go outside + * the packet buffer boundary. + */ + /* + * Look for the start of connection "PNA" string if not seen yet. + */ + if (rap->rap_seenpna == 0) { + s = (u_char *)memstr("PNA", (char *)membuf, 3, dlen); + if (s == NULL) + return 0; + s += 3; + rap->rap_seenpna = 1; + } else + s = membuf; + + /* + * Directly after the PNA will be the version number of this + * connection. + */ + if (rap->rap_seenpna == 1 && rap->rap_seenver == 0) { + if ((s + 1) - membuf < dlen) { + rap->rap_version = (*s << 8) | *(s + 1); + s += 2; + rap->rap_seenver = 1; + } else + return 0; + } + + /* + * Now that we've been past the PNA and version number, we're into the + * startup messages block. This ends when a message with an ID of 0. + */ + while ((rap->rap_eos == 0) && ((s + 1) - membuf < dlen)) { + if (rap->rap_gotid == 0) { + id = (*s << 8) | *(s + 1); + s += 2; + rap->rap_gotid = 1; + if (id == RA_ID_END) { + rap->rap_eos = 1; + break; + } + } else if (rap->rap_gotlen == 0) { + len = (*s << 8) | *(s + 1); + s += 2; + rap->rap_gotlen = 1; + } + + if (rap->rap_gotid == 1 && rap->rap_gotlen == 1) { + if (id == RA_ID_UDP) { + rap->rap_mode &= ~RAP_M_TCP; + rap->rap_mode |= RAP_M_UDP; + rap->rap_plport = (*s << 8) | *(s + 1); + } else if (id == RA_ID_ROBUST) { + rap->rap_mode |= RAP_M_ROBUST; + rap->rap_prport = (*s << 8) | *(s + 1); + } + s += len; + rap->rap_gotlen = 0; + rap->rap_gotid = 0; + } + } + return 0; +} + + +int ippr_raudio_in(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + unsigned char membuf[IPF_MAXPORTLEN + 1], *s; + tcphdr_t *tcp, tcph, *tcp2 = &tcph; + raudio_t *rap = aps->aps_data; + struct in_addr swa, swb; + u_int a1, a2, a3, a4; + int off, dlen, slen; + u_short sp, dp; + fr_info_t fi; + tcp_seq seq; + nat_t *ipn; + u_char swp; + mb_t *m; +#if SOLARIS + mb_t *m1; +#endif + + /* + * Wait until we've seen the end of the start messages and even then + * only proceed further if we're using UDP. If they want to use TCP + * then data is sent back on the same channel that is already open. + */ + if (rap->rap_sdone != 0) + return 0; + + tcp = (tcphdr_t *)fin->fin_dp; + off = (ip->ip_hl << 2) + (tcp->th_off << 2); + m = *(mb_t **)fin->fin_mp; + +#if SOLARIS + m = fin->fin_qfm; + + dlen = msgdsize(m) - off; + if (dlen <= 0) + return 0; + bzero(membuf, sizeof(membuf)); + copyout_mblk(m, off, MIN(sizeof(membuf), dlen), (char *)membuf); +#else + dlen = mbufchainlen(m) - off; + if (dlen <= 0) + return 0; + bzero(membuf, sizeof(membuf)); + m_copydata(m, off, MIN(sizeof(membuf), dlen), (char *)membuf); +#endif + + seq = ntohl(tcp->th_seq); + /* + * Check to see if the data in this packet is of interest to us. + * We only care for the first 19 bytes coming back from the server. + */ + if (rap->rap_sseq == 0) { + s = (u_char *)memstr("PNA", (char *)membuf, 3, dlen); + if (s == NULL) + return 0; + a1 = s - membuf; + dlen -= a1; + a1 = 0; + rap->rap_sseq = seq; + a2 = MIN(dlen, sizeof(rap->rap_svr)); + } else if (seq <= rap->rap_sseq + sizeof(rap->rap_svr)) { + /* + * seq # which is the start of data and from that the offset + * into the buffer array. + */ + a1 = seq - rap->rap_sseq; + a2 = MIN(dlen, sizeof(rap->rap_svr)); + a2 -= a1; + s = membuf; + } else + return 0; + + for (a3 = a1, a4 = a2; (a4 > 0) && (a3 < 19) && (a3 >= 0); a4--,a3++) { + rap->rap_sbf |= (1 << a3); + rap->rap_svr[a3] = *s++; + } + + if ((rap->rap_sbf != 0x7ffff) || (!rap->rap_eos)) /* 19 bits */ + return 0; + rap->rap_sdone = 1; + + s = (u_char *)rap->rap_svr + 11; + if (((*s << 8) | *(s + 1)) == RA_ID_ROBUST) { + s += 2; + rap->rap_srport = (*s << 8) | *(s + 1); + } + + swp = ip->ip_p; + swa = ip->ip_src; + swb = ip->ip_dst; + + ip->ip_p = IPPROTO_UDP; + ip->ip_src = nat->nat_inip; + ip->ip_dst = nat->nat_oip; + + bcopy((char *)fin, (char *)&fi, sizeof(fi)); + bzero((char *)tcp2, sizeof(*tcp2)); + tcp2->th_off = 5; + fi.fin_dp = (char *)tcp2; + fi.fin_fr = &raudiofr; + tcp2->th_win = htons(8192); + slen = ip->ip_len; + ip->ip_len = fin->fin_hlen + sizeof(*tcp); + + if (((rap->rap_mode & RAP_M_UDP_ROBUST) == RAP_M_UDP_ROBUST) && + (rap->rap_srport != 0)) { + dp = rap->rap_srport; + sp = rap->rap_prport; + tcp2->th_sport = htons(sp); + tcp2->th_dport = htons(dp); + fi.fin_data[0] = dp; + fi.fin_data[1] = sp; + ipn = nat_new(nat->nat_ptr, ip, &fi, + IPN_UDP | (sp ? 0 : FI_W_SPORT), NAT_OUTBOUND); + if (ipn != NULL) { + ipn->nat_age = fr_defnatage; + (void) fr_addstate(ip, &fi, sp ? 0 : FI_W_SPORT); + } + } + + if ((rap->rap_mode & RAP_M_UDP) == RAP_M_UDP) { + sp = rap->rap_plport; + tcp2->th_sport = htons(sp); + tcp2->th_dport = 0; /* XXX - don't specify remote port */ + fi.fin_data[0] = sp; + fi.fin_data[1] = 0; + ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_UDP|FI_W_DPORT, + NAT_OUTBOUND); + if (ipn != NULL) { + ipn->nat_age = fr_defnatage; + (void) fr_addstate(ip, &fi, FI_W_DPORT); + } + } + + ip->ip_p = swp; + ip->ip_len = slen; + ip->ip_src = swa; + ip->ip_dst = swb; + return 0; +} Property changes on: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_raudio_pxy.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_rcmd_pxy.c =================================================================== --- vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_rcmd_pxy.c (nonexistent) +++ vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_rcmd_pxy.c (revision 60849) @@ -0,0 +1,165 @@ +/* + * $Id: ip_rcmd_pxy.c,v 1.4.2.1 2000/05/06 11:19:34 darrenr Exp $ + */ +/* + * Simple RCMD transparent proxy for in-kernel use. For use with the NAT + * code. + */ +#if SOLARIS && defined(_KERNEL) +extern kmutex_t ipf_rw; +#endif + +#define isdigit(x) ((x) >= '0' && (x) <= '9') + +#define IPF_RCMD_PROXY + + +int ippr_rcmd_init __P((void)); +int ippr_rcmd_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_rcmd_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +u_short ipf_rcmd_atoi __P((char *)); +int ippr_rcmd_portmsg __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); + +static frentry_t rcmdfr; + + +/* + * RCMD application proxy initialization. + */ +int ippr_rcmd_init() +{ + bzero((char *)&rcmdfr, sizeof(rcmdfr)); + rcmdfr.fr_ref = 1; + rcmdfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + return 0; +} + + +/* + * Setup for a new RCMD proxy. + */ +int ippr_rcmd_new(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; + + aps->aps_psiz = sizeof(u_32_t); + KMALLOCS(aps->aps_data, u_32_t *, sizeof(u_32_t)); + if (aps->aps_data == NULL) + return -1; + *(u_32_t *)aps->aps_data = 0; + aps->aps_sport = tcp->th_sport; + aps->aps_dport = tcp->th_dport; + return 0; +} + + +/* + * ipf_rcmd_atoi - implement a simple version of atoi + */ +u_short ipf_rcmd_atoi(ptr) +char *ptr; +{ + register char *s = ptr, c; + register u_short i = 0; + + while ((c = *s++) && isdigit(c)) { + i *= 10; + i += c - '0'; + } + return i; +} + + +int ippr_rcmd_portmsg(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + char portbuf[8], *s; + struct in_addr swip; + u_short sp, dp; + int off, dlen; + tcphdr_t *tcp, tcph, *tcp2 = &tcph; + fr_info_t fi; + nat_t *ipn; + mb_t *m; +#if SOLARIS + mb_t *m1; +#endif + + tcp = (tcphdr_t *)fin->fin_dp; + off = (ip->ip_hl << 2) + (tcp->th_off << 2); + m = *(mb_t **)fin->fin_mp; + +#if SOLARIS + m = fin->fin_qfm; + + dlen = msgdsize(m) - off; + bzero(portbuf, sizeof(portbuf)); + copyout_mblk(m, off, MIN(sizeof(portbuf), dlen), portbuf); +#else + dlen = mbufchainlen(m) - off; + bzero(portbuf, sizeof(portbuf)); + m_copydata(m, off, MIN(sizeof(portbuf), dlen), portbuf); +#endif + if ((*(u_32_t *)aps->aps_data != 0) && + (tcp->th_seq != *(u_32_t *)aps->aps_data)) + return 0; + + portbuf[sizeof(portbuf) - 1] = '\0'; + s = portbuf; + sp = ipf_rcmd_atoi(s); + if (!sp) + return 0; + + /* + * Add skeleton NAT entry for connection which will come back the + * other way. + */ + sp = htons(sp); + dp = htons(fin->fin_data[1]); + ipn = nat_outlookup(fin->fin_ifp, IPN_TCP, nat->nat_p, nat->nat_inip, + ip->ip_dst, (dp << 16) | sp); + if (ipn == NULL) { + int slen; + + slen = ip->ip_len; + ip->ip_len = fin->fin_hlen + sizeof(*tcp); + bcopy((char *)fin, (char *)&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 */ + tcp2->th_off = 5; + fi.fin_data[0] = ntohs(sp); + fi.fin_data[1] = 0; + fi.fin_dp = (char *)tcp2; + swip = ip->ip_src; + ip->ip_src = nat->nat_inip; + ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_TCP|FI_W_DPORT, + NAT_OUTBOUND); + if (ipn != NULL) { + ipn->nat_age = fr_defnatage; + fi.fin_fr = &rcmdfr; + (void) fr_addstate(ip, &fi, FI_W_DPORT); + } + ip->ip_len = slen; + ip->ip_src = swip; + } + return 0; +} + + +int ippr_rcmd_out(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + return ippr_rcmd_portmsg(fin, ip, aps, nat); +} Property changes on: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_rcmd_pxy.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_state.c =================================================================== --- vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_state.c (nonexistent) +++ vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_state.c (revision 60849) @@ -0,0 +1,1658 @@ +/* + * Copyright (C) 1995-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. + */ +#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_state.c,v 2.30.2.9 2000/05/22 10:26:15 darrenr Exp $"; +#endif + +#include +#include +#include +#include +#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ + defined(_KERNEL) +# include "opt_ipfilter_log.h" +#endif +#if defined(_KERNEL) && defined(__FreeBSD_version) && \ + (__FreeBSD_version >= 400000) && !defined(KLD_MODULE) +#include "opt_inet6.h" +#endif +#if !defined(_KERNEL) && !defined(KERNEL) && !defined(__KERNEL__) +# include +# include +# include +#else +# ifdef linux +# include +# include +# endif +#endif +#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) +# include +# include +# if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM) +# include "opt_ipfilter.h" +# endif +#else +# include +#endif +#include +#include +#ifndef linux +# include +#endif +#include +#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux) +# include +#endif +#if !defined(__SVR4) && !defined(__svr4__) +# ifndef linux +# include +# endif +#else +# include +# include +# ifdef _KERNEL +# include +# endif +# include +# include +#endif + +#include +#ifdef sun +# include +#endif +#include +#include +#include +#include +#include +#ifndef linux +# include +# include +#endif +#include +#include +#include "netinet/ip_compat.h" +#include +#include "netinet/ip_fil.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_frag.h" +#include "netinet/ip_proxy.h" +#include "netinet/ip_state.h" +#ifdef USE_INET6 +#include +#endif +#if (__FreeBSD_version >= 300000) +# include +# if (defined(_KERNEL) || defined(KERNEL)) && !defined(IPFILTER_LKM) +# include +# include +# endif +#endif + +#ifndef MIN +# define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +#define TCP_CLOSE (TH_FIN|TH_RST) + +static ipstate_t **ips_table = NULL; +static ipstate_t *ips_list = NULL; +static int ips_num = 0; +static ips_stat_t ips_stats; +#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) +extern KRWLOCK_T ipf_state, ipf_mutex; +extern kmutex_t ipf_rw; +#endif + +#ifdef USE_INET6 +static frentry_t *fr_checkicmp6matchingstate __P((ip6_t *, fr_info_t *)); +#endif +static int fr_matchsrcdst __P((ipstate_t *, union i6addr, union i6addr, + fr_info_t *, tcphdr_t *)); +static frentry_t *fr_checkicmpmatchingstate __P((ip_t *, fr_info_t *)); +static int fr_matchicmpqueryreply __P((int, ipstate_t *, icmphdr_t *)); +static int fr_state_flush __P((int)); +static ips_stat_t *fr_statetstats __P((void)); +static void fr_delstate __P((ipstate_t *)); +static int fr_state_remove __P((caddr_t)); +int fr_stputent __P((caddr_t)); +int fr_stgetent __P((caddr_t)); +void fr_stinsert __P((ipstate_t *)); + + +#define FIVE_DAYS (2 * 5 * 86400) /* 5 days: half closed session */ + +#define TCP_MSL 240 /* 2 minutes */ +u_long fr_tcpidletimeout = FIVE_DAYS, + fr_tcpclosewait = 2 * TCP_MSL, + fr_tcplastack = 2 * TCP_MSL, + fr_tcptimeout = 2 * TCP_MSL, + fr_tcpclosed = 1, + fr_udptimeout = 240, + fr_icmptimeout = 120; +int fr_statemax = IPSTATE_MAX, + fr_statesize = IPSTATE_SIZE; +int fr_state_doflush = 0, + fr_state_lock = 0; + +static int icmpreplytype4[ICMP_MAXTYPE + 1]; + +int fr_stateinit() +{ + int i; + + KMALLOCS(ips_table, ipstate_t **, fr_statesize * sizeof(ipstate_t *)); + if (ips_table != NULL) + bzero((char *)ips_table, fr_statesize * sizeof(ipstate_t *)); + else + return -1; + + /* fill icmp reply type table */ + for (i = 0; i <= ICMP_MAXTYPE; i++) + icmpreplytype4[i] = -1; + icmpreplytype4[ICMP_ECHO] = ICMP_ECHOREPLY; + icmpreplytype4[ICMP_TSTAMP] = ICMP_TSTAMPREPLY; + icmpreplytype4[ICMP_IREQ] = ICMP_IREQREPLY; + icmpreplytype4[ICMP_MASKREQ] = ICMP_MASKREPLY; + + return 0; +} + + +static ips_stat_t *fr_statetstats() +{ + ips_stats.iss_active = ips_num; + ips_stats.iss_table = ips_table; + ips_stats.iss_list = ips_list; + return &ips_stats; +} + + +/* + * flush state tables. two actions currently defined: + * which == 0 : flush all state table entries + * which == 1 : flush TCP connections which have started to close but are + * stuck for some reason. + */ +static int fr_state_flush(which) +int which; +{ + register ipstate_t *is, **isp; +#if defined(_KERNEL) && !SOLARIS + int s; +#endif + int delete, removed = 0; + + SPL_NET(s); + for (isp = &ips_list; (is = *isp); ) { + delete = 0; + + switch (which) + { + case 0 : + delete = 1; + break; + case 1 : + if (is->is_p != IPPROTO_TCP) + break; + if ((is->is_state[0] != TCPS_ESTABLISHED) || + (is->is_state[1] != TCPS_ESTABLISHED)) + delete = 1; + break; + } + + if (delete) { + if (is->is_p == IPPROTO_TCP) + ips_stats.iss_fin++; + else + ips_stats.iss_expire++; +#ifdef IPFILTER_LOG + ipstate_log(is, ISL_FLUSH); +#endif + fr_delstate(is); + removed++; + } else + isp = &is->is_next; + } + SPL_X(s); + return removed; +} + + +static int fr_state_remove(data) +caddr_t data; +{ + ipstate_t *sp, st; + int error; + + sp = &st; + error = IRCOPYPTR(data, (caddr_t)&st, sizeof(st)); + if (error) + return EFAULT; + + for (sp = ips_list; sp; sp = sp->is_next) + if ((sp->is_p == st.is_p) && (sp->is_v == st.is_v) && + !bcmp(&sp->is_src, &st.is_src, sizeof(st.is_src)) && + !bcmp(&sp->is_dst, &st.is_src, sizeof(st.is_dst)) && + !bcmp(&sp->is_ps, &st.is_ps, sizeof(st.is_ps))) { + WRITE_ENTER(&ipf_state); +#ifdef IPFILTER_LOG + ipstate_log(sp, ISL_REMOVE); +#endif + fr_delstate(sp); + RWLOCK_EXIT(&ipf_state); + return 0; + } + return ESRCH; +} + + +int fr_state_ioctl(data, cmd, mode) +caddr_t data; +#if defined(__NetBSD__) || defined(__OpenBSD__) +u_long cmd; +#else +int cmd; +#endif +int mode; +{ + int arg, ret, error = 0; + + switch (cmd) + { + case SIOCDELST : + error = fr_state_remove(data); + break; + case SIOCIPFFL : + error = IRCOPY(data, (caddr_t)&arg, sizeof(arg)); + if (error) + break; + if (arg == 0 || arg == 1) { + WRITE_ENTER(&ipf_state); + ret = fr_state_flush(arg); + RWLOCK_EXIT(&ipf_state); + error = IWCOPY((caddr_t)&ret, data, sizeof(ret)); + } else + error = EINVAL; + break; +#ifdef IPFILTER_LOG + case SIOCIPFFB : + if (!(mode & FWRITE)) + error = EPERM; + else { + int tmp; + + tmp = ipflog_clear(IPL_LOGSTATE); + IWCOPY((char *)&tmp, data, sizeof(tmp)); + } + break; +#endif + case SIOCGETFS : + error = IWCOPYPTR((caddr_t)fr_statetstats(), data, + sizeof(ips_stat_t)); + break; + case FIONREAD : +#ifdef IPFILTER_LOG + error = IWCOPY((caddr_t)&iplused[IPL_LOGSTATE], (caddr_t)data, + sizeof(iplused[IPL_LOGSTATE])); +#endif + break; + case SIOCSTLCK : + error = fr_lock(data, &fr_state_lock); + break; + case SIOCSTPUT : + if (!fr_state_lock) { + error = EACCES; + break; + } + error = fr_stputent(data); + break; + case SIOCSTGET : + if (!fr_state_lock) { + error = EACCES; + break; + } + error = fr_stgetent(data); + break; + default : + error = EINVAL; + break; + } + return error; +} + + +int fr_stgetent(data) +caddr_t data; +{ + register ipstate_t *is, *isn; + ipstate_save_t ips, *ipsp; + int error; + + error = IRCOPY(data, (caddr_t)&ipsp, sizeof(ipsp)); + if (error) + return EFAULT; + error = IRCOPY((caddr_t)ipsp, (caddr_t)&ips, sizeof(ips)); + if (error) + return EFAULT; + + isn = ips.ips_next; + if (!isn) { + isn = ips_list; + if (isn == NULL) { + if (ips.ips_next == NULL) + return ENOENT; + return 0; + } + } else { + /* + * Make sure the pointer we're copying from exists in the + * current list of entries. Security precaution to prevent + * copying of random kernel data. + */ + for (is = ips_list; is; is = is->is_next) + if (is == isn) + break; + if (!is) + return ESRCH; + } + ips.ips_next = isn->is_next; + bcopy((char *)isn, (char *)&ips.ips_is, sizeof(ips.ips_is)); + if (isn->is_rule) + bcopy((char *)isn->is_rule, (char *)&ips.ips_fr, + sizeof(ips.ips_fr)); + error = IWCOPY((caddr_t)&ips, ipsp, sizeof(ips)); + if (error) + return EFAULT; + return 0; +} + + +int fr_stputent(data) +caddr_t data; +{ + register ipstate_t *is, *isn; + ipstate_save_t ips, *ipsp; + frentry_t *fr; + int error; + + error = IRCOPY(data, (caddr_t)&ipsp, sizeof(ipsp)); + if (error) + return EFAULT; + error = IRCOPY((caddr_t)ipsp, (caddr_t)&ips, sizeof(ips)); + if (error) + return EFAULT; + + KMALLOC(isn, ipstate_t *); + if (isn == NULL) + return ENOMEM; + + bcopy((char *)&ips.ips_is, (char *)isn, sizeof(*isn)); + fr = isn->is_rule; + if (fr != NULL) { + if (isn->is_flags & FI_NEWFR) { + KMALLOC(fr, frentry_t *); + if (fr == NULL) { + KFREE(isn); + return ENOMEM; + } + bcopy((char *)&ips.ips_fr, (char *)fr, sizeof(*fr)); + isn->is_rule = fr; + ips.ips_is.is_rule = fr; + error = IWCOPY((caddr_t)&ips, ipsp, sizeof(ips)); + if (error) { + KFREE(isn); + KFREE(fr); + return EFAULT; + } + } else { + for (is = ips_list; is; is = is->is_next) + if (is->is_rule == fr) + break; + if (!is) { + KFREE(isn); + return ESRCH; + } + } + } + fr_stinsert(isn); + return 0; +} + + +void fr_stinsert(is) +register ipstate_t *is; +{ + register u_int hv = is->is_hv; + + MUTEX_INIT(&is->is_lock, "ipf state entry", NULL); + + is->is_ifname[0][sizeof(is->is_ifname[0]) - 1] = '\0'; + if (is->is_ifname[0][0] != '\0') { + is->is_ifp[0] = GETUNIT(is->is_ifname[0], is->is_v); + } + is->is_ifname[1][sizeof(is->is_ifname[0]) - 1] = '\0'; + if (is->is_ifname[1][0] != '\0') { + is->is_ifp[1] = GETUNIT(is->is_ifname[1], is->is_v); + } + + /* + * add into list table. + */ + if (ips_list) + ips_list->is_pnext = &is->is_next; + is->is_pnext = &ips_list; + is->is_next = ips_list; + ips_list = is; + if (ips_table[hv]) + ips_table[hv]->is_phnext = &is->is_hnext; + else + ips_stats.iss_inuse++; + is->is_phnext = ips_table + hv; + is->is_hnext = ips_table[hv]; + ips_table[hv] = is; +} + + +/* + * Create a new ipstate structure and hang it off the hash table. + */ +ipstate_t *fr_addstate(ip, fin, flags) +ip_t *ip; +fr_info_t *fin; +u_int flags; +{ + register tcphdr_t *tcp = NULL; + register ipstate_t *is; + register u_int hv; + ipstate_t ips; + u_int pass; + int out; + + if (fr_state_lock || (fin->fin_off & IP_OFFMASK) || + (fin->fin_fi.fi_fl & FI_SHORT)) + return NULL; + if (ips_num == fr_statemax) { + ips_stats.iss_max++; + fr_state_doflush = 1; + return NULL; + } + out = fin->fin_out; + is = &ips; + bzero((char *)is, sizeof(*is)); + ips.is_age = 1; + ips.is_state[0] = 0; + ips.is_state[1] = 0; + /* + * Copy and calculate... + */ + hv = (is->is_p = fin->fin_fi.fi_p); + is->is_src = fin->fin_fi.fi_src; + hv += is->is_saddr; + is->is_dst = fin->fin_fi.fi_dst; + hv += is->is_daddr; +#ifdef USE_INET6 + if (fin->fin_v == 6) { + if (is->is_p == IPPROTO_ICMPV6) { + if (IN6_IS_ADDR_MULTICAST(&is->is_dst.in6)) + flags |= FI_W_DADDR; + if (out) + hv -= is->is_daddr; + else + hv -= is->is_saddr; + } + } +#endif + + switch (is->is_p) + { +#ifdef USE_INET6 + case IPPROTO_ICMPV6 : +#endif + case IPPROTO_ICMP : + { + struct icmp *ic = (struct icmp *)fin->fin_dp; + +#ifdef USE_INET6 + if ((is->is_p == IPPROTO_ICMPV6) && + ((ic->icmp_type & ICMP6_INFOMSG_MASK) == 0)) + return NULL; +#endif + switch (ic->icmp_type) + { +#ifdef USE_INET6 + case ICMP6_ECHO_REQUEST : + is->is_icmp.ics_type = ICMP6_ECHO_REPLY; + hv += (is->is_icmp.ics_id = ic->icmp_id); + hv += (is->is_icmp.ics_seq = ic->icmp_seq); + break; + case ICMP6_MEMBERSHIP_QUERY : + case ND_ROUTER_SOLICIT : + case ND_NEIGHBOR_SOLICIT : + is->is_icmp.ics_type = ic->icmp_type + 1; + break; + break; +#endif + case ICMP_ECHO : + case ICMP_TSTAMP : + case ICMP_IREQ : + case ICMP_MASKREQ : + is->is_icmp.ics_type = ic->icmp_type; + hv += (is->is_icmp.ics_id = ic->icmp_id); + hv += (is->is_icmp.ics_seq = ic->icmp_seq); + break; + default : + return NULL; + } + ATOMIC_INCL(ips_stats.iss_icmp); + is->is_age = fr_icmptimeout; + break; + } + case IPPROTO_TCP : + { + tcp = (tcphdr_t *)fin->fin_dp; + + if (tcp->th_flags & TH_RST) + return NULL; + /* + * The endian of the ports doesn't matter, but the ack and + * sequence numbers do as we do mathematics on them later. + */ + is->is_dport = tcp->th_dport; + is->is_sport = tcp->th_sport; + if ((flags & (FI_W_DPORT|FI_W_SPORT)) == 0) { + hv += tcp->th_dport; + hv += tcp->th_sport; + } + is->is_send = ntohl(tcp->th_seq) + ip->ip_len - + fin->fin_hlen - (tcp->th_off << 2) + + ((tcp->th_flags & TH_SYN) ? 1 : 0) + + ((tcp->th_flags & TH_FIN) ? 1 : 0); + is->is_maxsend = is->is_send; + is->is_dend = 0; + is->is_maxdwin = 1; + is->is_maxswin = ntohs(tcp->th_win); + if (is->is_maxswin == 0) + is->is_maxswin = 1; + /* + * If we're creating state for a starting connection, start the + * timer on it as we'll never see an error if it fails to + * connect. + */ + ATOMIC_INCL(ips_stats.iss_tcp); + break; + } + case IPPROTO_UDP : + { + tcp = (tcphdr_t *)fin->fin_dp; + + is->is_dport = tcp->th_dport; + is->is_sport = tcp->th_sport; + if ((flags & (FI_W_DPORT|FI_W_SPORT)) == 0) { + hv += tcp->th_dport; + hv += tcp->th_sport; + } + ATOMIC_INCL(ips_stats.iss_udp); + is->is_age = fr_udptimeout; + break; + } + default : + return NULL; + } + + KMALLOC(is, ipstate_t *); + if (is == NULL) { + ATOMIC_INCL(ips_stats.iss_nomem); + return NULL; + } + bcopy((char *)&ips, (char *)is, sizeof(*is)); + hv %= fr_statesize; + is->is_hv = hv; + is->is_rule = fin->fin_fr; + if (is->is_rule != NULL) { + ATOMIC_INC32(is->is_rule->fr_ref); + pass = is->is_rule->fr_flags; + } else + pass = fr_flags; + WRITE_ENTER(&ipf_state); + + is->is_pass = pass; + is->is_pkts = 1; + is->is_bytes = fin->fin_dlen + fin->fin_hlen; + /* + * We want to check everything that is a property of this packet, + * but we don't (automatically) care about it's fragment status as + * this may change. + */ + is->is_v = fin->fin_fi.fi_v; + is->is_opt = fin->fin_fi.fi_optmsk; + is->is_optmsk = 0xffffffff; + is->is_sec = fin->fin_fi.fi_secmsk; + is->is_secmsk = 0xffff; + is->is_auth = fin->fin_fi.fi_auth; + is->is_authmsk = 0xffff; + is->is_flags = fin->fin_fi.fi_fl & FI_CMP; + is->is_flags |= FI_CMP << 4; + is->is_flags |= flags & (FI_WILDP|FI_WILDA); + is->is_ifp[1 - out] = NULL; + is->is_ifp[out] = fin->fin_ifp; +#ifdef _KERNEL + strncpy(is->is_ifname[out], IFNAME(fin->fin_ifp), IFNAMSIZ); +#endif + is->is_ifname[1 - out][0] = '\0'; + if (pass & FR_LOGFIRST) + is->is_pass &= ~(FR_LOGFIRST|FR_LOG); + fr_stinsert(is); + ips_num++; + if (is->is_p == IPPROTO_TCP) { + MUTEX_ENTER(&is->is_lock); + fr_tcp_age(&is->is_age, is->is_state, fin, + tcp->th_sport == is->is_sport); + MUTEX_EXIT(&is->is_lock); + } +#ifdef IPFILTER_LOG + ipstate_log(is, ISL_NEW); +#endif + RWLOCK_EXIT(&ipf_state); + fin->fin_rev = IP6NEQ(is->is_dst, fin->fin_fi.fi_dst); + if (fin->fin_fi.fi_fl & FI_FRAG) + ipfr_newfrag(ip, fin, pass ^ FR_KEEPSTATE); + return is; +} + + + +/* + * check to see if a packet with TCP headers fits within the TCP window. + * change timeout depending on whether new packet is a SYN-ACK returning for a + * SYN or a RST or FIN which indicate time to close up shop. + */ +int fr_tcpstate(is, fin, ip, tcp) +register ipstate_t *is; +fr_info_t *fin; +ip_t *ip; +tcphdr_t *tcp; +{ + register tcp_seq seq, ack, end; + register int ackskew; + tcpdata_t *fdata, *tdata; + u_short win, maxwin; + int ret = 0; + int source; + + /* + * Find difference between last checked packet and this packet. + */ + source = IP6EQ(fin->fin_fi.fi_src, is->is_src); + fdata = &is->is_tcp.ts_data[!source]; + tdata = &is->is_tcp.ts_data[source]; + seq = ntohl(tcp->th_seq); + ack = ntohl(tcp->th_ack); + win = ntohs(tcp->th_win); + end = seq + fin->fin_dlen - (tcp->th_off << 2) + + ((tcp->th_flags & TH_SYN) ? 1 : 0) + + ((tcp->th_flags & TH_FIN) ? 1 : 0); + + if (fdata->td_end == 0) { + /* + * Must be a (outgoing) SYN-ACK in reply to a SYN. + */ + fdata->td_end = end; + fdata->td_maxwin = 1; + fdata->td_maxend = end + 1; + } + + if (!(tcp->th_flags & TH_ACK)) { /* Pretend an ack was sent */ + ack = tdata->td_end; + } else if (((tcp->th_flags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) && + (ack == 0)) { + /* gross hack to get around certain broken tcp stacks */ + ack = tdata->td_end; + } + + if (seq == end) + seq = end = fdata->td_end; + + maxwin = tdata->td_maxwin; + ackskew = tdata->td_end - ack; + +#define SEQ_GE(a,b) ((int)((a) - (b)) >= 0) +#define SEQ_GT(a,b) ((int)((a) - (b)) > 0) + if ((SEQ_GE(fdata->td_maxend, end)) && + (SEQ_GE(seq, fdata->td_end - maxwin)) && +/* XXX what about big packets */ +#define MAXACKWINDOW 66000 + (ackskew >= -MAXACKWINDOW) && + (ackskew <= MAXACKWINDOW)) { + /* if ackskew < 0 then this should be due to fragented + * packets. There is no way to know the length of the + * total packet in advance. + * We do know the total length from the fragment cache though. + * Note however that there might be more sessions with + * exactly the same source and destination paramters in the + * state cache (and source and destination is the only stuff + * that is saved in the fragment cache). Note further that + * some TCP connections in the state cache are hashed with + * sport and dport as well which makes it not worthwhile to + * look for them. + * Thus, when ackskew is negative but still seems to belong + * to this session, we bump up the destinations end value. + */ + if (ackskew < 0) + tdata->td_end = ack; + + /* update max window seen */ + if (fdata->td_maxwin < win) + fdata->td_maxwin = win; + if (SEQ_GT(end, fdata->td_end)) + fdata->td_end = end; + if (SEQ_GE(ack + win, tdata->td_maxend)) { + tdata->td_maxend = ack + win; + if (win == 0) + tdata->td_maxend++; + } + + ATOMIC_INCL(ips_stats.iss_hits); + is->is_pkts++; + is->is_bytes += fin->fin_dlen + fin->fin_hlen; + /* + * Nearing end of connection, start timeout. + */ + MUTEX_ENTER(&is->is_lock); + fr_tcp_age(&is->is_age, is->is_state, fin, source); + MUTEX_EXIT(&is->is_lock); + ret = 1; + } + return ret; +} + + +static int fr_matchsrcdst(is, src, dst, fin, tcp) +ipstate_t *is; +union i6addr src, dst; +fr_info_t *fin; +tcphdr_t *tcp; +{ + int ret = 0, rev, out, flags; + u_short sp, dp; + void *ifp; + + rev = fin->fin_rev = IP6NEQ(is->is_dst, dst); + ifp = fin->fin_ifp; + out = fin->fin_out; + + if (tcp != NULL) { + flags = is->is_flags; + sp = tcp->th_sport; + dp = tcp->th_dport; + } else { + flags = is->is_flags & FI_WILDA; + sp = 0; + dp = 0; + } + + if (rev == 0) { + if (!out) { + if (is->is_ifpin == NULL || is->is_ifpin == ifp) + ret = 1; + } else { + if (is->is_ifpout == NULL || is->is_ifpout == ifp) + ret = 1; + } + } else { + if (out) { + if (is->is_ifpin == NULL || is->is_ifpin == ifp) + ret = 1; + } else { + if (is->is_ifpout == NULL || is->is_ifpout == ifp) + ret = 1; + } + } + if (ret == 0) + return 0; + ret = 0; + + if (rev == 0) { + if ( + (IP6EQ(is->is_dst, dst) || (flags & FI_W_DADDR)) && + (IP6EQ(is->is_src, src) || (flags & FI_W_SADDR)) && + (!tcp || ((sp == is->is_sport || flags & FI_W_SPORT) && + (dp == is->is_dport || flags & FI_W_DPORT)))) { + ret = 1; + } + } else { + if ( + (IP6EQ(is->is_dst, src) || (flags & FI_W_DADDR)) && + (IP6EQ(is->is_src, dst) || (flags & FI_W_SADDR)) && + (!tcp || ((sp == is->is_dport || flags & FI_W_DPORT) && + (dp == is->is_sport || flags & FI_W_SPORT)))) { + ret = 1; + } + } + if (ret == 0) + return 0; + + /* + * Whether or not this should be here, is questionable, but the aim + * is to get this out of the main line. + */ + if (tcp == NULL) + flags = is->is_flags & (FI_CMP|(FI_CMP<<4)); + + if (((fin->fin_fi.fi_fl & (flags >> 4)) != (flags & FI_CMP)) || + ((fin->fin_fi.fi_optmsk & is->is_optmsk) != is->is_opt) || + ((fin->fin_fi.fi_secmsk & is->is_secmsk) != is->is_sec) || + ((fin->fin_fi.fi_auth & is->is_authmsk) != is->is_auth)) + return 0; + + if ((flags & (FI_W_SPORT|FI_W_DPORT))) { + if ((flags & FI_W_SPORT) != 0) { + if (rev == 0) { + is->is_sport = sp; + is->is_send = htonl(tcp->th_seq); + } else { + is->is_sport = dp; + is->is_send = htonl(tcp->th_ack); + } + is->is_maxsend = is->is_send + 1; + } else if ((flags & FI_W_DPORT) != 0) { + if (rev == 0) { + is->is_dport = dp; + is->is_dend = htonl(tcp->th_ack); + } else { + is->is_dport = sp; + is->is_dend = htonl(tcp->th_seq); + } + is->is_maxdend = is->is_dend + 1; + } + is->is_flags &= ~(FI_W_SPORT|FI_W_DPORT); + } + + ret = -1; + + if (!rev) { + if (out) { + if (!is->is_ifpout) + ret = 1; + } else { + if (!is->is_ifpin) + ret = 0; + } + } else { + if (out) { + if (!is->is_ifpin) + ret = 0; + } else { + if (!is->is_ifpout) + ret = 1; + } + } + + if (ret >= 0) { + is->is_ifp[ret] = ifp; +#ifdef _KERNEL + strncpy(is->is_ifname[out], IFNAME(fin->fin_ifp), + sizeof(is->is_ifname[1])); +#endif + } +#ifdef _KERNEL + if (ret >= 0) { + strncpy(is->is_ifname[out], IFNAME(fin->fin_ifp), + sizeof(is->is_ifname[1])); + } +#endif + return 1; +} + +static int fr_matchicmpqueryreply(v, is, icmp) +int v; +ipstate_t *is; +icmphdr_t *icmp; +{ + if (v == 4) { + /* + * If we matched its type on the way in, then when going out + * it will still be the same type. + */ + if (((icmp->icmp_type == is->is_type) || + (icmpreplytype4[is->is_type] == icmp->icmp_type)) && + (icmp->icmp_id == is->is_icmp.ics_id) && + (icmp->icmp_seq == is->is_icmp.ics_seq)) { + return 1; + }; + } +#ifdef USE_INET6 + else if (is->is_v == 6) { + if ((is->is_type == ICMP6_ECHO_REPLY) && + (icmp->icmp_type == ICMP6_ECHO_REQUEST) && + (icmp->icmp_id == is->is_icmp.ics_id) && + (icmp->icmp_seq == is->is_icmp.ics_seq)) { + return 1; + }; + } +#endif + return 0; +} + +static frentry_t *fr_checkicmpmatchingstate(ip, fin) +ip_t *ip; +fr_info_t *fin; +{ + register ipstate_t *is, **isp; + register u_short sport, dport; + register u_char pr; + union i6addr dst, src; + struct icmp *ic; + u_short savelen; + fr_info_t ofin; + tcphdr_t *tcp; + icmphdr_t *icmp; + frentry_t *fr; + ip_t *oip; + int type; + u_int hv; + + /* + * Does it at least have the return (basic) IP header ? + * Only a basic IP header (no options) should be with + * an ICMP error header. + */ + if (((ip->ip_v != 4) && (ip->ip_hl != 5)) || + (fin->fin_plen < ICMPERR_MINPKTLEN)) + return NULL; + ic = (struct icmp *)fin->fin_dp; + type = ic->icmp_type; + /* + * If it's not an error type, then return + */ + if ((type != ICMP_UNREACH) && (type != ICMP_SOURCEQUENCH) && + (type != ICMP_REDIRECT) && (type != ICMP_TIMXCEED) && + (type != ICMP_PARAMPROB)) + return NULL; + + oip = (ip_t *)((char *)ic + ICMPERR_ICMPHLEN); + if (fin->fin_plen < ICMPERR_MAXPKTLEN + ((oip->ip_hl - 5) << 2)) + return NULL; + + if (oip->ip_p == IPPROTO_ICMP) { + icmp = (icmphdr_t *)((char *)oip + (oip->ip_hl << 2)); + + /* + * a ICMP error can only be generated as a result of an + * ICMP query, not as the response on an ICMP error + * + * XXX theoretically ICMP_ECHOREP and the other reply's are + * ICMP query's as well, but adding them here seems strange XXX + */ + if ((icmp->icmp_type != ICMP_ECHO) && + (icmp->icmp_type != ICMP_TSTAMP) && + (icmp->icmp_type != ICMP_IREQ) && + (icmp->icmp_type != ICMP_MASKREQ)) + return NULL; + + /* + * perform a lookup of the ICMP packet in the state table + */ + hv = (pr = oip->ip_p); + src.in4 = oip->ip_src; + hv += src.in4.s_addr; + dst.in4 = oip->ip_dst; + hv += dst.in4.s_addr; + hv += icmp->icmp_id; + hv += icmp->icmp_seq; + hv %= fr_statesize; + + oip->ip_len = ntohs(oip->ip_len); + fr_makefrip(oip->ip_hl << 2, oip, &ofin); + oip->ip_len = htons(oip->ip_len); + ofin.fin_ifp = fin->fin_ifp; + ofin.fin_out = !fin->fin_out; + ofin.fin_mp = NULL; /* if dereferenced, panic XXX */ + + READ_ENTER(&ipf_state); + for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) + if ((is->is_p == pr) && (is->is_v == 4) && + fr_matchsrcdst(is, src, dst, &ofin, NULL) && + fr_matchicmpqueryreply(is->is_v, is, icmp)) { + ips_stats.iss_hits++; + is->is_pkts++; + is->is_bytes += ip->ip_len; + fr = is->is_rule; + RWLOCK_EXIT(&ipf_state); + return fr; + } + RWLOCK_EXIT(&ipf_state); + return NULL; + }; + + if ((oip->ip_p != IPPROTO_TCP) && (oip->ip_p != IPPROTO_UDP)) + return NULL; + + tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2)); + dport = tcp->th_dport; + sport = tcp->th_sport; + + hv = (pr = oip->ip_p); + src.in4 = oip->ip_src; + hv += src.in4.s_addr; + dst.in4 = oip->ip_dst; + hv += dst.in4.s_addr; + hv += dport; + hv += sport; + hv %= fr_statesize; + /* + * we make an fin entry to be able to feed it to + * matchsrcdst note that not all fields are encessary + * but this is the cleanest way. Note further we fill + * in fin_mp such that if someone uses it we'll get + * a kernel panic. fr_matchsrcdst does not use this. + * + * watch out here, as ip is in host order and oip in network + * order. Any change we make must be undone afterwards. + */ + savelen = oip->ip_len; + oip->ip_len = ip->ip_len - (ip->ip_hl << 2) - ICMPERR_ICMPHLEN; + fr_makefrip(oip->ip_hl << 2, oip, &ofin); + oip->ip_len = savelen; + ofin.fin_ifp = fin->fin_ifp; + ofin.fin_out = !fin->fin_out; + ofin.fin_mp = NULL; /* if dereferenced, panic XXX */ + READ_ENTER(&ipf_state); + for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) { + /* + * Only allow this icmp though if the + * encapsulated packet was allowed through the + * other way around. Note that the minimal amount + * of info present does not allow for checking against + * tcp internals such as seq and ack numbers. + */ + if ((is->is_p == pr) && (is->is_v == 4) && + fr_matchsrcdst(is, src, dst, &ofin, tcp)) { + fr = is->is_rule; + ips_stats.iss_hits++; + /* + * we must swap src and dst here because the icmp + * comes the other way around + */ + is->is_pkts++; + is->is_bytes += fin->fin_plen; + /* + * we deliberately do not touch the timeouts + * for the accompanying state table entry. + * It remains to be seen if that is correct. XXX + */ + RWLOCK_EXIT(&ipf_state); + return fr; + } + } + RWLOCK_EXIT(&ipf_state); + return NULL; +} + +/* + * Check if a packet has a registered state. + */ +frentry_t *fr_checkstate(ip, fin) +ip_t *ip; +fr_info_t *fin; +{ + union i6addr dst, src; + register ipstate_t *is, **isp; + register u_char pr; + u_int hv, hvm, hlen, tryagain, pass, v; + struct icmp *ic; + frentry_t *fr; + tcphdr_t *tcp; + + if (fr_state_lock || (fin->fin_off & IP_OFFMASK) || + (fin->fin_fi.fi_fl & FI_SHORT)) + return NULL; + + is = NULL; + hlen = fin->fin_hlen; + tcp = (tcphdr_t *)((char *)ip + hlen); + ic = (struct icmp *)tcp; + hv = (pr = fin->fin_fi.fi_p); + src = fin->fin_fi.fi_src; + dst = fin->fin_fi.fi_dst; + hv += src.in4.s_addr; + hv += dst.in4.s_addr; + + /* + * Search the hash table for matching packet header info. + */ + v = fin->fin_fi.fi_v; + switch (fin->fin_fi.fi_p) + { +#ifdef USE_INET6 + case IPPROTO_ICMPV6 : + if (v == 6) { + if (fin->fin_out) + hv -= dst.in4.s_addr; + else + hv -= src.in4.s_addr; + if ((ic->icmp_type == ICMP6_ECHO_REQUEST) || + (ic->icmp_type == ICMP6_ECHO_REPLY)) { + hv += ic->icmp_id; + hv += ic->icmp_seq; + } + } +#endif + case IPPROTO_ICMP : + if (v == 4) { + hv += ic->icmp_id; + hv += ic->icmp_seq; + } + hv %= fr_statesize; + READ_ENTER(&ipf_state); + for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) { + if ((is->is_p == pr) && (is->is_v == v) && + fr_matchsrcdst(is, src, dst, fin, NULL) && + fr_matchicmpqueryreply(v, is, ic)) { + is->is_age = fr_icmptimeout; + break; + } + } + if (is != NULL) + break; + RWLOCK_EXIT(&ipf_state); + /* + * No matching icmp state entry. Perhaps this is a + * response to another state entry. + */ +#ifdef USE_INET6 + if (v == 6) + fr = fr_checkicmp6matchingstate((ip6_t *)ip, fin); + else +#endif + fr = fr_checkicmpmatchingstate(ip, fin); + if (fr) + return fr; + break; + case IPPROTO_TCP : + { + register u_short dport = tcp->th_dport, sport = tcp->th_sport; + + tryagain = 0; +retry_tcp: + hvm = hv % fr_statesize; + WRITE_ENTER(&ipf_state); + for (isp = &ips_table[hvm]; (is = *isp); + isp = &is->is_hnext) + + + if ((is->is_p == pr) && (is->is_v == v) && + fr_matchsrcdst(is, src, dst, fin, tcp)) { + if (fr_tcpstate(is, fin, ip, tcp)) + break; + is = NULL; + break; + } + if (is != NULL) + break; + RWLOCK_EXIT(&ipf_state); + hv += dport; + hv += sport; + if (tryagain == 0) { + tryagain = 1; + goto retry_tcp; + } + break; + } + case IPPROTO_UDP : + { + register u_short dport = tcp->th_dport, sport = tcp->th_sport; + + tryagain = 0; +retry_udp: + hvm = hv % fr_statesize; + /* + * Nothing else to match on but ports. and IP#'s + */ + READ_ENTER(&ipf_state); + for (is = ips_table[hvm]; is; is = is->is_hnext) + if ((is->is_p == pr) && (is->is_v == v) && + fr_matchsrcdst(is, src, dst, fin, tcp)) { + is->is_age = fr_udptimeout; + break; + } + if (is != NULL) + break; + RWLOCK_EXIT(&ipf_state); + hv += dport; + hv += sport; + if (tryagain == 0) { + tryagain = 1; + goto retry_udp; + } + break; + } + default : + break; + } + if (is == NULL) { + ATOMIC_INCL(ips_stats.iss_miss); + return NULL; + } + MUTEX_ENTER(&is->is_lock); + is->is_bytes += fin->fin_plen; + ips_stats.iss_hits++; + is->is_pkts++; + MUTEX_EXIT(&is->is_lock); + fr = is->is_rule; + fin->fin_fr = fr; + pass = is->is_pass; +#ifndef _KERNEL + if (tcp->th_flags & TCP_CLOSE) + fr_delstate(is); +#endif + RWLOCK_EXIT(&ipf_state); + if (fin->fin_fi.fi_fl & FI_FRAG) + ipfr_newfrag(ip, fin, pass ^ FR_KEEPSTATE); + return fr; +} + + +void ip_statesync(ifp) +void *ifp; +{ + register ipstate_t *is; + + WRITE_ENTER(&ipf_state); + for (is = ips_list; is; is = is->is_next) { + if (is->is_ifpin == ifp) { + is->is_ifpin = GETUNIT(is->is_ifname[0], is->is_v); + if (!is->is_ifpin) + is->is_ifpin = (void *)-1; + } + if (is->is_ifpout == ifp) { + is->is_ifpout = GETUNIT(is->is_ifname[1], is->is_v); + if (!is->is_ifpout) + is->is_ifpout = (void *)-1; + } + } + RWLOCK_EXIT(&ipf_state); +} + + +static void fr_delstate(is) +ipstate_t *is; +{ + frentry_t *fr; + + if (is->is_next) + is->is_next->is_pnext = is->is_pnext; + *is->is_pnext = is->is_next; + if (is->is_hnext) + is->is_hnext->is_phnext = is->is_phnext; + *is->is_phnext = is->is_hnext; + if (ips_table[is->is_hv] == NULL) + ips_stats.iss_inuse--; + + fr = is->is_rule; + if (fr != NULL) { + ATOMIC_DEC32(fr->fr_ref); + if (fr->fr_ref == 0) + KFREE(fr); + } +#ifdef _KERNEL + MUTEX_DESTROY(&is->is_lock); +#endif + KFREE(is); + ips_num--; +} + + +/* + * Free memory in use by all state info. kept. + */ +void fr_stateunload() +{ + register ipstate_t *is; + + WRITE_ENTER(&ipf_state); + while ((is = ips_list)) + fr_delstate(is); + ips_stats.iss_inuse = 0; + ips_num = 0; + RWLOCK_EXIT(&ipf_state); + KFREES(ips_table, fr_statesize * sizeof(ipstate_t *)); + ips_table = NULL; +} + + +/* + * Slowly expire held state for thingslike UDP and ICMP. Timeouts are set + * in expectation of this being called twice per second. + */ +void fr_timeoutstate() +{ + register ipstate_t *is, **isp; +#if defined(_KERNEL) && !SOLARIS + int s; +#endif + + SPL_NET(s); + WRITE_ENTER(&ipf_state); + for (isp = &ips_list; (is = *isp); ) + if (is->is_age && !--is->is_age) { + if (is->is_p == IPPROTO_TCP) + ips_stats.iss_fin++; + else + ips_stats.iss_expire++; +#ifdef IPFILTER_LOG + ipstate_log(is, ISL_EXPIRE); +#endif + fr_delstate(is); + } else + isp = &is->is_next; + RWLOCK_EXIT(&ipf_state); + SPL_X(s); + if (fr_state_doflush) { + (void) fr_state_flush(1); + fr_state_doflush = 0; + } +} + + +/* + * Original idea freom Pradeep Krishnan for use primarily with NAT code. + * (pkrishna@netcom.com) + */ +void fr_tcp_age(age, state, fin, dir) +u_long *age; +u_char *state; +fr_info_t *fin; +int dir; +{ + tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; + u_char flags = tcp->th_flags; + int dlen, ostate; + + ostate = state[1 - dir]; + + dlen = fin->fin_plen - fin->fin_hlen - (tcp->th_off << 2); + + if (flags & TH_RST) { + if (!(tcp->th_flags & TH_PUSH) && !dlen) { + *age = fr_tcpclosed; + state[dir] = TCPS_CLOSED; + } else { + *age = fr_tcpclosewait; + state[dir] = TCPS_CLOSE_WAIT; + } + return; + } + + *age = fr_tcptimeout; /* 1 min */ + + switch(state[dir]) + { + case TCPS_CLOSED: + if ((flags & (TH_FIN|TH_SYN|TH_RST|TH_ACK)) == TH_ACK) { + state[dir] = TCPS_ESTABLISHED; + *age = fr_tcpidletimeout; + } + case TCPS_FIN_WAIT_2: + if ((flags & TH_OPENING) == TH_OPENING) + state[dir] = TCPS_SYN_RECEIVED; + else if (flags & TH_SYN) + state[dir] = TCPS_SYN_SENT; + break; + case TCPS_SYN_RECEIVED: + case TCPS_SYN_SENT: + if ((flags & (TH_FIN|TH_ACK)) == TH_ACK) { + state[dir] = TCPS_ESTABLISHED; + *age = fr_tcpidletimeout; + } else if ((flags & (TH_FIN|TH_ACK)) == (TH_FIN|TH_ACK)) { + state[dir] = TCPS_CLOSE_WAIT; + if (!(flags & TH_PUSH) && !dlen && + ostate > TCPS_ESTABLISHED) + *age = fr_tcplastack; + else + *age = fr_tcpclosewait; + } + break; + case TCPS_ESTABLISHED: + if (flags & TH_FIN) { + state[dir] = TCPS_CLOSE_WAIT; + if (!(flags & TH_PUSH) && !dlen && + ostate > TCPS_ESTABLISHED) + *age = fr_tcplastack; + else + *age = fr_tcpclosewait; + } else { + if (ostate < TCPS_CLOSE_WAIT) + *age = fr_tcpidletimeout; + } + break; + case TCPS_CLOSE_WAIT: + if ((flags & TH_FIN) && !(flags & TH_PUSH) && !dlen && + ostate > TCPS_ESTABLISHED) { + *age = fr_tcplastack; + state[dir] = TCPS_LAST_ACK; + } else + *age = fr_tcpclosewait; + break; + case TCPS_LAST_ACK: + if (flags & TH_ACK) { + state[dir] = TCPS_FIN_WAIT_2; + if (!(flags & TH_PUSH) && !dlen && + ostate > TCPS_ESTABLISHED) + *age = fr_tcplastack; + else { + *age = fr_tcpclosewait; + state[dir] = TCPS_CLOSE_WAIT; + } + } + break; + } +} + + +#ifdef IPFILTER_LOG +void ipstate_log(is, type) +struct ipstate *is; +u_int type; +{ + struct ipslog ipsl; + void *items[1]; + size_t sizes[1]; + int types[1]; + + ipsl.isl_type = type; + ipsl.isl_pkts = is->is_pkts; + ipsl.isl_bytes = is->is_bytes; + ipsl.isl_src = is->is_src; + ipsl.isl_dst = is->is_dst; + ipsl.isl_p = is->is_p; + ipsl.isl_v = is->is_v; + ipsl.isl_flags = is->is_flags; + if (ipsl.isl_p == IPPROTO_TCP || ipsl.isl_p == IPPROTO_UDP) { + ipsl.isl_sport = is->is_sport; + ipsl.isl_dport = is->is_dport; + if (ipsl.isl_p == IPPROTO_TCP) { + ipsl.isl_state[0] = is->is_state[0]; + ipsl.isl_state[1] = is->is_state[1]; + } + } else if (ipsl.isl_p == IPPROTO_ICMP) + ipsl.isl_itype = is->is_icmp.ics_type; + else { + ipsl.isl_ps.isl_filler[0] = 0; + ipsl.isl_ps.isl_filler[1] = 0; + } + items[0] = &ipsl; + sizes[0] = sizeof(ipsl); + types[0] = 0; + + (void) ipllog(IPL_LOGSTATE, NULL, items, sizes, types, 1); +} +#endif + + +#ifdef USE_INET6 +frentry_t *fr_checkicmp6matchingstate(ip, fin) +ip6_t *ip; +fr_info_t *fin; +{ + register ipstate_t *is, **isp; + register u_short sport, dport; + register u_char pr; + struct icmp6_hdr *ic, *oic; + union i6addr dst, src; + u_short savelen; + fr_info_t ofin; + tcphdr_t *tcp; + frentry_t *fr; + ip6_t *oip; + int type; + u_int hv; + + /* + * Does it at least have the return (basic) IP header ? + * Only a basic IP header (no options) should be with + * an ICMP error header. + */ + if ((fin->fin_v != 6) || (fin->fin_plen < ICMP6ERR_MINPKTLEN)) + return NULL; + ic = (struct icmp6_hdr *)fin->fin_dp; + type = ic->icmp6_type; + /* + * If it's not an error type, then return + */ + if ((type != ICMP6_DST_UNREACH) && (type != ICMP6_PACKET_TOO_BIG) && + (type != ICMP6_TIME_EXCEEDED) && (type != ICMP6_PARAM_PROB)) + return NULL; + + oip = (ip6_t *)((char *)ic + ICMPERR_ICMPHLEN); + if (fin->fin_plen < sizeof(*oip)) + return NULL; + + if (oip->ip6_nxt == IPPROTO_ICMPV6) { + oic = (struct icmp6_hdr *)(oip + 1); + /* + * a ICMP error can only be generated as a result of an + * ICMP query, not as the response on an ICMP error + * + * XXX theoretically ICMP_ECHOREP and the other reply's are + * ICMP query's as well, but adding them here seems strange XXX + */ + if (!(oic->icmp6_type & ICMP6_INFOMSG_MASK)) + return NULL; + + /* + * perform a lookup of the ICMP packet in the state table + */ + hv = (pr = oip->ip6_nxt); + src.in6 = oip->ip6_src; + hv += src.in4.s_addr; + dst.in6 = oip->ip6_dst; + hv += dst.in4.s_addr; + hv += oic->icmp6_id; + hv += oic->icmp6_seq; + hv %= fr_statesize; + + oip->ip6_plen = ntohs(oip->ip6_plen); + fr_makefrip(sizeof(*oip), (ip_t *)oip, &ofin); + oip->ip6_plen = htons(oip->ip6_plen); + ofin.fin_ifp = fin->fin_ifp; + ofin.fin_out = !fin->fin_out; + ofin.fin_mp = NULL; /* if dereferenced, panic XXX */ + + READ_ENTER(&ipf_state); + for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) + if ((is->is_p == pr) && + (oic->icmp6_id == is->is_icmp.ics_id) && + (oic->icmp6_seq == is->is_icmp.ics_seq) && + fr_matchsrcdst(is, src, dst, &ofin, NULL)) { + /* + * in the state table ICMP query's are stored + * with the type of the corresponding ICMP + * response. Correct here + */ + if (((is->is_type == ICMP6_ECHO_REPLY) && + (oic->icmp6_type == ICMP6_ECHO_REQUEST)) || + (is->is_type - 1 == oic->icmp6_type )) { + ips_stats.iss_hits++; + is->is_pkts++; + is->is_bytes += fin->fin_plen; + return is->is_rule; + } + } + RWLOCK_EXIT(&ipf_state); + + return NULL; + }; + + if ((oip->ip6_nxt != IPPROTO_TCP) && (oip->ip6_nxt != IPPROTO_UDP)) + return NULL; + tcp = (tcphdr_t *)(oip + 1); + dport = tcp->th_dport; + sport = tcp->th_sport; + + hv = (pr = oip->ip6_nxt); + src.in6 = oip->ip6_src; + hv += src.in4.s_addr; + dst.in6 = oip->ip6_dst; + hv += dst.in4.s_addr; + hv += dport; + hv += sport; + hv %= fr_statesize; + /* + * we make an fin entry to be able to feed it to + * matchsrcdst note that not all fields are encessary + * but this is the cleanest way. Note further we fill + * in fin_mp such that if someone uses it we'll get + * a kernel panic. fr_matchsrcdst does not use this. + * + * watch out here, as ip is in host order and oip in network + * order. Any change we make must be undone afterwards. + */ + savelen = oip->ip6_plen; + oip->ip6_plen = ip->ip6_plen - sizeof(*ip) - ICMPERR_ICMPHLEN; + ofin.fin_v = 6; + fr_makefrip(sizeof(*oip), (ip_t *)oip, &ofin); + oip->ip6_plen = savelen; + ofin.fin_ifp = fin->fin_ifp; + ofin.fin_out = !fin->fin_out; + ofin.fin_mp = NULL; /* if dereferenced, panic XXX */ + READ_ENTER(&ipf_state); + for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) { + /* + * Only allow this icmp though if the + * encapsulated packet was allowed through the + * other way around. Note that the minimal amount + * of info present does not allow for checking against + * tcp internals such as seq and ack numbers. + */ + if ((is->is_p == pr) && (is->is_v == 6) && + fr_matchsrcdst(is, src, dst, &ofin, tcp)) { + fr = is->is_rule; + ips_stats.iss_hits++; + /* + * we must swap src and dst here because the icmp + * comes the other way around + */ + is->is_pkts++; + is->is_bytes += fin->fin_plen; + /* + * we deliberately do not touch the timeouts + * for the accompanying state table entry. + * It remains to be seen if that is correct. XXX + */ + RWLOCK_EXIT(&ipf_state); + return fr; + } + } + RWLOCK_EXIT(&ipf_state); + return NULL; +} +#endif Property changes on: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_state.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_state.h =================================================================== --- vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_state.h (nonexistent) +++ vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_state.h (revision 60849) @@ -0,0 +1,194 @@ +/* + * Copyright (C) 1995-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. + * + * @(#)ip_state.h 1.3 1/12/96 (C) 1995 Darren Reed + * $Id: ip_state.h,v 2.13 2000/03/13 22:10:23 darrenr Exp $ + */ +#ifndef __IP_STATE_H__ +#define __IP_STATE_H__ + +#if defined(__STDC__) || defined(__GNUC__) +# define SIOCDELST _IOW('r', 61, struct ipstate *) +#else +# define SIOCDELST _IOW(r, 61, struct ipstate *) +#endif + +#define IPSTATE_SIZE 257 +#define IPSTATE_MAX 2048 /* Maximum number of states held */ + +#define PAIRS(s1,d1,s2,d2) ((((s1) == (s2)) && ((d1) == (d2))) ||\ + (((s1) == (d2)) && ((d1) == (s2)))) +#define IPPAIR(s1,d1,s2,d2) PAIRS((s1).s_addr, (d1).s_addr, \ + (s2).s_addr, (d2).s_addr) + + +typedef struct udpstate { + u_short us_sport; + u_short us_dport; +} udpstate_t; + +typedef struct icmpstate { + u_short ics_id; + u_short ics_seq; + u_char ics_type; +} icmpstate_t; + +typedef struct tcpdata { + u_32_t td_end; + u_32_t td_maxend; + u_short td_maxwin; +} tcpdata_t; + +typedef struct tcpstate { + u_short ts_sport; + u_short ts_dport; + tcpdata_t ts_data[2]; + u_char ts_state[2]; +} tcpstate_t; + +typedef struct ipstate { + struct ipstate *is_next; + struct ipstate **is_pnext; + struct ipstate *is_hnext; + struct ipstate **is_phnext; + u_long is_age; + u_int is_pass; + U_QUAD_T is_pkts; + U_QUAD_T is_bytes; + void *is_ifp[2]; + frentry_t *is_rule; + union i6addr is_src; + union i6addr is_dst; + u_char is_p; /* Protocol */ + u_char is_v; + u_int is_hv; + u_32_t is_flags; + u_32_t is_opt; /* packet options set */ + u_32_t is_optmsk; /* " " mask */ + u_short is_sec; /* security options set */ + u_short is_secmsk; /* " " mask */ + u_short is_auth; /* authentication options set */ + u_short is_authmsk; /* " " mask */ + union { + icmpstate_t is_ics; + tcpstate_t is_ts; + udpstate_t is_us; + } is_ps; + char is_ifname[2][IFNAMSIZ]; +#if SOLARIS || defined(__sgi) + kmutex_t is_lock; +#endif +} ipstate_t; + +#define is_saddr is_src.in4.s_addr +#define is_daddr is_dst.in4.s_addr +#define is_icmp is_ps.is_ics +#define is_type is_icmp.ics_type +#define is_code is_icmp.ics_code +#define is_tcp is_ps.is_ts +#define is_udp is_ps.is_us +#define is_send is_tcp.ts_data[0].td_end +#define is_dend is_tcp.ts_data[1].td_end +#define is_maxswin is_tcp.ts_data[0].td_maxwin +#define is_maxdwin is_tcp.ts_data[1].td_maxwin +#define is_maxsend is_tcp.ts_data[0].td_maxend +#define is_maxdend is_tcp.ts_data[1].td_maxend +#define is_sport is_tcp.ts_sport +#define is_dport is_tcp.ts_dport +#define is_state is_tcp.ts_state +#define is_ifpin is_ifp[0] +#define is_ifpout is_ifp[1] + +#define TH_OPENING (TH_SYN|TH_ACK) +/* + * is_flags: + * Bits 0 - 3 are use as a mask with the current packet's bits to check for + * whether it is short, tcp/udp, a fragment or the presence of IP options. + * Bits 4 - 7 are set from the initial packet and contain what the packet + * anded with bits 0-3 must match. + * Bits 8,9 are used to indicate wildcard source/destination port matching. + */ + +typedef struct ipstate_save { + void *ips_next; + struct ipstate ips_is; + struct frentry ips_fr; +} ipstate_save_t; + +#define ips_rule ips_is.is_rule + + +typedef struct ipslog { + U_QUAD_T isl_pkts; + U_QUAD_T isl_bytes; + union i6addr isl_src; + union i6addr isl_dst; + u_short isl_type; + union { + u_short isl_filler[2]; + u_short isl_ports[2]; + u_short isl_icmp; + } isl_ps; + u_char isl_v; + u_char isl_p; + u_char isl_flags; + u_char isl_state[2]; +} ipslog_t; + +#define isl_sport isl_ps.isl_ports[0] +#define isl_dport isl_ps.isl_ports[1] +#define isl_itype isl_ps.isl_icmp + +#define ISL_NEW 0 +#define ISL_EXPIRE 0xffff +#define ISL_FLUSH 0xfffe +#define ISL_REMOVE 0xfffd + + +typedef struct ips_stat { + u_long iss_hits; + u_long iss_miss; + u_long iss_max; + u_long iss_tcp; + u_long iss_udp; + u_long iss_icmp; + u_long iss_nomem; + u_long iss_expire; + u_long iss_fin; + u_long iss_active; + u_long iss_logged; + u_long iss_logfail; + u_long iss_inuse; + ipstate_t **iss_table; + ipstate_t *iss_list; +} ips_stat_t; + + +extern u_long fr_tcpidletimeout; +extern u_long fr_tcpclosewait; +extern u_long fr_tcplastack; +extern u_long fr_tcptimeout; +extern u_long fr_tcpclosed; +extern u_long fr_udptimeout; +extern u_long fr_icmptimeout; +extern int fr_state_lock; +extern int fr_stateinit __P((void)); +extern int fr_tcpstate __P((ipstate_t *, fr_info_t *, ip_t *, tcphdr_t *)); +extern ipstate_t *fr_addstate __P((ip_t *, fr_info_t *, u_int)); +extern frentry_t *fr_checkstate __P((ip_t *, fr_info_t *)); +extern void ip_statesync __P((void *)); +extern void fr_timeoutstate __P((void)); +extern void fr_tcp_age __P((u_long *, u_char *, fr_info_t *, int)); +extern void fr_stateunload __P((void)); +extern void ipstate_log __P((struct ipstate *, u_int)); +#if defined(__NetBSD__) || defined(__OpenBSD__) +extern int fr_state_ioctl __P((caddr_t, u_long, int)); +#else +extern int fr_state_ioctl __P((caddr_t, int, int)); +#endif + +#endif /* __IP_STATE_H__ */ Property changes on: vendor-sys/ipfilter/v3_4_4/sys/netinet/ip_state.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor-sys/ipfilter/v3_4_4/sys/netinet/ipl.h =================================================================== --- vendor-sys/ipfilter/v3_4_4/sys/netinet/ipl.h (nonexistent) +++ vendor-sys/ipfilter/v3_4_4/sys/netinet/ipl.h (revision 60849) @@ -0,0 +1,17 @@ +/* + * 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. + * + * @(#)ipl.h 1.21 6/5/96 + * $Id: ipl.h,v 2.15.2.5 2000/05/22 10:26:16 darrenr Exp $ + */ + +#ifndef __IPL_H__ +#define __IPL_H__ + +#define IPL_VERSION "IP Filter: v3.4.4" + +#endif Property changes on: vendor-sys/ipfilter/v3_4_4/sys/netinet/ipl.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: vendor-sys/ipfilter/v3_4_4/sys/netinet/mlfk_ipl.c =================================================================== --- vendor-sys/ipfilter/v3_4_4/sys/netinet/mlfk_ipl.c (nonexistent) +++ vendor-sys/ipfilter/v3_4_4/sys/netinet/mlfk_ipl.c (revision 60849) @@ -0,0 +1,181 @@ +/* + * Copyright 1999 Guido van Rooij. All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: mlfk_ipl.c,v 2.1.2.1 2000/04/26 12:17:24 darrenr Exp $ + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include + +static dev_t ipf_devs[IPL_LOGMAX + 1]; + +SYSCTL_DECL(_net_inet); +SYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW, 0, "IPF"); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &fr_flags, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_pass, CTLFLAG_RW, &fr_pass, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &fr_active, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RW, + &fr_tcpidletimeout, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RW, + &fr_tcpclosewait, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RW, + &fr_tcplastack, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RW, + &fr_tcptimeout, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RW, + &fr_tcpclosed, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RW, + &fr_udptimeout, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RW, + &fr_icmptimeout, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RW, + &fr_defnatage, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW, + &fr_ipfrttl, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, ipl_unreach, CTLFLAG_RW, + &ipl_unreach, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_running, CTLFLAG_RD, + &fr_running, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RD, + &fr_authsize, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD, + &fr_authused, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW, + &fr_defaultauthage, 0, ""); + +#define CDEV_MAJOR 79 +static struct cdevsw ipl_cdevsw = { + /* open */ iplopen, + /* close */ iplclose, + /* read */ iplread, + /* write */ nowrite, + /* ioctl */ iplioctl, + /* poll */ nopoll, + /* mmap */ nommap, + /* strategy */ nostrategy, + /* name */ "ipl", + /* maj */ CDEV_MAJOR, + /* dump */ nodump, + /* psize */ nopsize, + /* flags */ 0, + /* bmaj */ -1 +}; + +static int +ipfilter_modevent(module_t mod, int type, void *unused) +{ + char *c; + int i, error = 0; + + switch (type) { + case MOD_LOAD : + + error = iplattach(); + if (error) + break; + + c = NULL; + for(i=strlen(IPL_NAME); i>0; i--) + if (IPL_NAME[i] == '/') { + c = &IPL_NAME[i+1]; + break; + } + if (!c) + c = IPL_NAME; + ipf_devs[IPL_LOGIPF] = + make_dev(&ipl_cdevsw, IPL_LOGIPF, 0, 0, 0600, c); + + c = NULL; + for(i=strlen(IPL_NAT); i>0; i--) + if (IPL_NAT[i] == '/') { + c = &IPL_NAT[i+1]; + break; + } + if (!c) + c = IPL_NAT; + ipf_devs[IPL_LOGNAT] = + make_dev(&ipl_cdevsw, IPL_LOGNAT, 0, 0, 0600, c); + + c = NULL; + for(i=strlen(IPL_STATE); i>0; i--) + if (IPL_STATE[i] == '/') { + c = &IPL_STATE[i+1]; + break; + } + if (!c) + c = IPL_STATE; + ipf_devs[IPL_LOGSTATE] = + make_dev(&ipl_cdevsw, IPL_LOGSTATE, 0, 0, 0600, c); + + c = NULL; + for(i=strlen(IPL_AUTH); i>0; i--) + if (IPL_AUTH[i] == '/') { + c = &IPL_AUTH[i+1]; + break; + } + if (!c) + c = IPL_AUTH; + ipf_devs[IPL_LOGAUTH] = + make_dev(&ipl_cdevsw, IPL_LOGAUTH, 0, 0, 0600, c); + + break; + case MOD_UNLOAD : + destroy_dev(ipf_devs[IPL_LOGIPF]); + destroy_dev(ipf_devs[IPL_LOGNAT]); + destroy_dev(ipf_devs[IPL_LOGSTATE]); + destroy_dev(ipf_devs[IPL_LOGAUTH]); + error = ipldetach(); + break; + default: + error = EINVAL; + break; + } + return error; +} + +static moduledata_t ipfiltermod = { + IPL_VERSION, + ipfilter_modevent, + 0 +}; +DECLARE_MODULE(ipfilter, ipfiltermod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); Property changes on: vendor-sys/ipfilter/v3_4_4/sys/netinet/mlfk_ipl.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property