This patch affects both kernel and userland. Make sure you have both kenel and userland sources before applying this patch. Apply by doing: # cd /usr/src # patch -p0 < 023_ipf.patch now, build a kernel. Eg, for GENERIC: # cd sys/arch/i386/conf # config GENERIC # cd ../compile/GENERIC # make clean && make depend && make # cp /bsd /bsd.old # cp bsd /bsd Export headers to userland # cd /usr/src # make includes And now rebuild userland # cd /usr/src/sbin/ipf # make obj && make cleandir && make && make install # cd /usr/src/sbin/ipnat # make obj && make cleandir && make && make install # cd /usr/src/sbin/ipfstat # make obj && make cleandir && make && make install # cd /usr/src/usr.sbin/ipmon # make obj && make cleandir && make && make install # cd /usr/src/usr.sbin/ipftest # make obj && make cleandir && make && make install Reboot to activate the new ipf. To check that all was successful, do: # ipf -V You should see something like: ipf: IP Filter: v3.3.16 (184) Kernel: IP Filter: v3.3.16 Running: yes Log Flags: 0 = none set Default: pass all, Logging: available Active list: 0 Index: sys/netinet/ipl.h =================================================================== RCS file: ipl.h diff -N ipl.h --- /dev/null Wed May 24 17:02:20 2000 +++ sys/netinet/ipl.h Wed May 24 17:46:34 2000 @@ -0,0 +1,18 @@ +/* $OpenBSD: ipl.h,v 1.11 2000/05/24 21:59:11 kjell Exp $ */ + +/* + * Copyright (C) 1993-1999 by Darren Reed. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and due credit is given + * to the original author and the contributors. + * + * @(#)ipl.h 1.21 6/5/96 + */ + +#ifndef __IPL_H__ +#define __IPL_H__ + +#define IPL_VERSION "IP Filter: v3.3.16" + +#endif Index: sys/netinet/fil.c =================================================================== RCS file: /cvs/src/sys/netinet/fil.c,v retrieving revision 1.15 retrieving revision 1.25 diff -u -r1.15 -r1.25 --- sys/netinet/fil.c 1999/02/19 20:52:22 1.15 +++ sys/netinet/fil.c 2000/05/24 21:59:10 1.25 @@ -1,4 +1,5 @@ -/* $OpenBSD: fil.c,v 1.15 1999/02/19 20:52:22 kjell Exp $ */ +/* $OpenBSD: fil.c,v 1.25 2000/05/24 21:59:10 kjell Exp $ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -8,7 +9,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-1996 Darren Reed"; -static const char rcsid[] = "@(#)$Id: fil.c,v 1.15 1999/02/19 20:52:22 kjell Exp $"; +static const char rcsid[] = "@(#)$IPFilter: fil.c,v 2.3.2.20 2000/05/22 06:57:42 darrenr Exp $"; #endif #include @@ -16,7 +17,17 @@ #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 @@ -32,9 +43,9 @@ #else # include # if SOLARIS2 < 5 -# include +# include # endif -# include +# include #endif #ifndef linux # include @@ -51,14 +62,14 @@ #ifndef linux # include #endif +#if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */ +# include +# include +#endif #include #include #include -#if defined(__OpenBSD__) -# include -#else -# include -#endif +#include #include #include #include @@ -66,9 +77,16 @@ #include #include #include +# 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)) +# define MIN(a,b) (((a)<(b))?(a):(b)) #endif +#include #ifndef _KERNEL # include "ipf.h" @@ -81,14 +99,7 @@ second; } # define FR_VERBOSE(verb_pr) verbose verb_pr # define FR_DEBUG(verb_pr) debug verb_pr -# define SEND_RESET(ip, qif, if, m) send_reset(ip, if) # define IPLLOG(a, c, d, e) ipllog() -# define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, ip) -# if SOLARIS -# define ICMP_ERROR(b, ip, t, c, if, src) icmp_error(ip) -# else -# define ICMP_ERROR(b, ip, t, c, if, src) icmp_error(b, ip, if) -# endif #else /* #ifndef _KERNEL */ # define FR_IFVERBOSE(ex,second,verb_pr) ; # define FR_IFDEBUG(ex,second,verb_pr) ; @@ -96,39 +107,8 @@ # 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; +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) send_reset(ip, qif) -# define ICMP_ERROR(b, ip, t, c, if, src) \ - icmp_error(ip, t, c, if, src) -# else /* SOLARIS */ -# define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, ip) -# ifdef linux -# define SEND_RESET(ip, qif, if) send_reset((tcpiphdr_t *)ip,\ - ifp) -# else -# define SEND_RESET(ip, qif, if) send_reset((tcpiphdr_t *)ip) -# endif -# ifdef __sgi -# define ICMP_ERROR(b, ip, t, c, if, src) \ - icmp_error(b, t, c, if, src, if) -# else -# if BSD < 199103 -# ifdef linux -# define ICMP_ERROR(b, ip, t, c, if, src) icmp_send(b,t,c,0,if) -# else -# define ICMP_ERROR(b, ip, t, c, if, src) \ - icmp_error(mtod(b, ip_t *), t, c, if, src) -# endif /* linux */ -# else -# define ICMP_ERROR(b, ip, t, c, if, src) \ - icmp_error(b, t, c, (src).s_addr, if) -# endif /* BSD < 199103 */ -# endif /* __sgi */ # endif /* SOLARIS || __sgi */ #endif /* _KERNEL */ @@ -143,12 +123,15 @@ #else int fr_pass = (IPF_DEFAULT_PASS|FR_NOMATCH); #endif +char ipfilter_version[] = IPL_VERSION; fr_info_t frcache[2]; -static void fr_makefrip __P((int, ip_t *, fr_info_t *)); static int fr_tcpudpchk __P((frentry_t *, fr_info_t *)); -static int frflushlist __P((int, int, int *, frentry_t *, frentry_t **)); +static int frflushlist __P((int, minor_t, int *, frentry_t **)); +#ifdef _KERNEL +static void frsynclist __P((frentry_t *)); +#endif /* @@ -196,7 +179,7 @@ * compact the IP header into a structure which contains just the info. * which is useful for comparing IP headers with. */ -static void fr_makefrip(hlen, ip, fin) +void fr_makefrip(hlen, ip, fin) int hlen; ip_t *ip; fr_info_t *fin; @@ -208,6 +191,7 @@ int i, mv, ol, off; u_char *s, opt; + fin->fin_rev = 0; fin->fin_fr = NULL; fin->fin_tcpf = 0; fin->fin_data[0] = 0; @@ -225,8 +209,8 @@ tcp = (tcphdr_t *)((char *)ip + hlen); fin->fin_dp = (void *)tcp; (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4)); - (*(((u_32_t *)fi) + 1)) = (*(((u_32_t *)ip) + 3)); - (*(((u_32_t *)fi) + 2)) = (*(((u_32_t *)ip) + 4)); + fi->fi_src.s_addr = ip->ip_src.s_addr; + fi->fi_dst.s_addr = ip->ip_dst.s_addr; fi->fi_fl = (hlen > sizeof(ip_t)) ? FI_OPTIONS : 0; off = (ip->ip_off & IP_OFFMASK) << 3; @@ -244,6 +228,17 @@ if (!off && (icmp->icmp_type == ICMP_ECHOREPLY || icmp->icmp_type == ICMP_ECHO)) minicmpsz = ICMP_MINLEN; + + if (!off && (icmp->icmp_type == ICMP_TSTAMP || + icmp->icmp_type == ICMP_TSTAMPREPLY)) + minicmpsz = 20; +/* type(1) + code(1) + cksum(2) + id(2) + seq(2) + 3*timestamp(3*4) */ + + if (!off && (icmp->icmp_type == ICMP_MASKREQ || + icmp->icmp_type == ICMP_MASKREPLY)) + minicmpsz = 12; +/* type(1) + code(1) + cksum(2) + id(2) + seq(2) + mask(4) */ + if ((!(ip->ip_len >= hlen + minicmpsz) && !off) || (off && off < sizeof(struct icmp))) fi->fi_fl |= FI_SHORT; @@ -275,12 +270,19 @@ } - for (s = (u_char *)(ip + 1), hlen -= sizeof(*ip); hlen; ) { - if (!(opt = *s)) - break; - ol = (opt == IPOPT_NOP) ? 1 : (int)*(s+1); - if (opt > 1 && (ol < 2 || ol > hlen)) + 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) { @@ -421,14 +423,15 @@ * kernel sauce. */ int fr_scanlist(pass, ip, fin, m) -int pass; +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; + int rulen, portcmp = 0, off, skip = 0, logged = 0; + u_32_t passt; fr = fin->fin_fr; fin->fin_fr = NULL; @@ -452,8 +455,16 @@ * check that we are working for the right interface */ #ifdef _KERNEL - if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) - continue; +# 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"); @@ -473,10 +484,12 @@ i = ((lip[0] & lm[0]) != ld[0]); FR_IFDEBUG(i,continue,("0. %#08x & %#08x != %#08x\n", lip[0], lm[0], ld[0])); - i |= ((lip[1] & lm[1]) != ld[1]) << 21; + i |= ((lip[1] & lm[1]) != ld[1]) << 19; + i ^= (fr->fr_flags & FR_NOTSRCIP); FR_IFDEBUG(i,continue,("1. %#08x & %#08x != %#08x\n", lip[1], lm[1], ld[1])); - i |= ((lip[2] & lm[2]) != ld[2]) << 22; + i |= ((lip[2] & lm[2]) != ld[2]) << 20; + i ^= (fr->fr_flags & FR_NOTDSTIP); FR_IFDEBUG(i,continue,("2. %#08x & %#08x != %#08x\n", lip[2], lm[2], ld[2])); i |= ((lip[3] & lm[3]) != ld[3]); @@ -485,7 +498,6 @@ i |= ((lip[4] & lm[4]) != ld[4]); FR_IFDEBUG(i,continue,("4. %#08x & %#08x != %#08x\n", lip[4], lm[4], ld[4])); - i ^= (fi->fi_fl & (FR_NOTSRCIP|FR_NOTDSTIP)); if (i) continue; } @@ -515,18 +527,23 @@ /* * Just log this packet... */ - if (!(skip = fr->fr_skip)) - pass = fr->fr_flags; - if ((pass & FR_CALLNOW) && fr->fr_func) - pass = (*fr->fr_func)(pass, ip, fin); + 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 ((pass & FR_LOGMASK) == FR_LOG) { - if (!IPLLOG(fr->fr_flags, ip, fin, m)) { + if ((passt & FR_LOGMASK) == FR_LOG) { + if (!IPLLOG(passt, ip, fin, m)) { + if (passt & FR_LOGORBLOCK) + passt |= FR_BLOCK|FR_QUICK; ATOMIC_INC(frstats[fin->fin_out].fr_skip); } ATOMIC_INC(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_INC(fr->fr_hits); if (pass & FR_ACCOUNT) @@ -535,7 +552,6 @@ fin->fin_icode = fr->fr_icode; fin->fin_rule = rulen; fin->fin_group = fr->fr_group; - fin->fin_fr = fr; if (fr->fr_grp) { fin->fin_fr = fr->fr_grp; pass = fr_scanlist(pass, ip, fin, m); @@ -544,10 +560,14 @@ 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; } @@ -576,7 +596,8 @@ fr_info_t frinfo, *fc; register fr_info_t *fin = &frinfo; frentry_t *fr = NULL; - int pass, changed, apass, error = EHOSTUNREACH; + int changed, error = EHOSTUNREACH; + u_32_t pass, apass; #if !SOLARIS || !defined(_KERNEL) register mb_t *m = *mp; #endif @@ -597,7 +618,17 @@ */ 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; @@ -611,8 +642,8 @@ case IPPROTO_UDP: plen = sizeof(udphdr_t); break; + /* 96 - enough for complete ICMP error IP header */ case IPPROTO_ICMP: - /* need enough for complete ICMP error IP header */ plen = ICMPERR_MAXPKTLEN - sizeof(ip_t); break; } @@ -648,16 +679,30 @@ # if SOLARIS mb_t *m = qif->qf_m; + if ((u_int)ip & 0x3) + return 2; fin->fin_qfm = m; + fin->fin_qif = qif; # endif #endif /* _KERNEL */ + + /* + * Be careful here: ip_id is in network byte order when called + * from ip_output() + */ + if (out) + ip->ip_id = ntohs(ip->ip_id); fr_makefrip(hlen, ip, fin); fin->fin_ifp = ifp; fin->fin_out = out; fin->fin_mp = mp; + pass = fr_pass; READ_ENTER(&ipf_mutex); + if (fin->fin_fi.fi_fl & FI_SHORT) + ATOMIC_INC(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 @@ -668,15 +713,15 @@ apass = fr_checkauth(ip, fin); if (!out) { - changed = ip_natin(ip, hlen, fin); + changed = ip_natin(ip, fin); if (!apass && (fin->fin_fr = ipacct[0][fr_active]) && - (FR_SCANLIST(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { + (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { ATOMIC_INC(frstats[0].fr_acct); } } - if (apass || (!(pass = ipfr_knownfrag(ip, fin)) && - !(pass = fr_checkstate(ip, fin)))) { + 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 @@ -694,13 +739,13 @@ if ((fr = fin->fin_fr)) { ATOMIC_INC(fr->fr_hits); pass = fr->fr_flags; - } else - pass = fr_pass; + } } else { - pass = fr_pass; if ((fin->fin_fr = ipfilter[out][fr_active])) - pass = FR_SCANLIST(fr_pass, ip, fin, m); - bcopy((char *)fin, (char *)fc, FI_COPYSIZE); + 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_INC(frstats[out].fr_nom); } @@ -715,7 +760,7 @@ * then pretend we've dropped it already. */ if ((pass & FR_AUTH)) - if (FR_NEWAUTH(m, fin, ip, qif) != 0) + if (fr_newauth((mb_t *)m, fin, ip) != 0) #ifdef _KERNEL m = *mp = NULL; #else @@ -725,7 +770,7 @@ if (pass & FR_PREAUTH) { READ_ENTER(&ipf_auth); if ((fin->fin_fr = ipauth) && - (pass = FR_SCANLIST(0, ip, fin, m))) { + (pass = fr_scanlist(0, ip, fin, m))) { ATOMIC_INC(fr_authstats.fas_hits); } else { ATOMIC_INC(fr_authstats.fas_miss); @@ -733,7 +778,8 @@ RWLOCK_EXIT(&ipf_auth); } - if (pass & FR_KEEPFRAG) { + 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_INC(frstats[out].fr_bnfr); @@ -745,12 +791,16 @@ } } if (pass & FR_KEEPSTATE) { - if (fr_addstate(ip, fin, pass) == -1) { + if (fr_addstate(ip, fin, 0) == NULL) { ATOMIC_INC(frstats[out].fr_bads); } else { ATOMIC_INC(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)) @@ -762,13 +812,13 @@ */ if (out && (pass & FR_PASS)) { if ((fin->fin_fr = ipacct[1][fr_active]) && - (FR_SCANLIST(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { + (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { ATOMIC_INC(frstats[1].fr_acct); } - fin->fin_fr = NULL; - changed = ip_natout(ip, hlen, fin); - } - fin->fin_fr = fr; + fin->fin_fr = fr; + changed = ip_natout(ip, fin); + } else + fin->fin_fr = fr; RWLOCK_EXIT(&ipf_mutex); #ifdef IPFILTER_LOG @@ -798,6 +848,10 @@ } } #endif /* IPFILTER_LOG */ + + if (out) + ip->ip_id = htons(ip->ip_id); + #ifdef _KERNEL /* * Only allow FR_DUP to work if a rule matched - it makes no sense to @@ -830,27 +884,28 @@ if (!out) { #ifdef _KERNEL if (pass & FR_RETICMP) { -# if SOLARIS - ICMP_ERROR(q, ip, ICMP_UNREACH, fin->fin_icode, - qif, ip->ip_src); -# else - ICMP_ERROR(m, ip, ICMP_UNREACH, fin->fin_icode, - ifp, ip->ip_src); - m = *mp = NULL; /* freed by icmp_error() */ -# endif + struct in_addr dst; + if ((pass & FR_RETMASK) == FR_FAKEICMP) + dst = ip->ip_dst; + else + dst.s_addr = 0; + send_icmp_err(ip, ICMP_UNREACH, fin, dst); ATOMIC_INC(frstats[0].fr_ret); - } else if ((pass & FR_RETRST) && + } else if (((pass & FR_RETMASK) == FR_RETRST) && !(fin->fin_fi.fi_fl & FI_SHORT)) { - if (SEND_RESET(ip, qif, ifp) == 0) { + if (send_reset(ip, fin) == 0) { ATOMIC_INC(frstats[1].fr_ret); } } #else - if (pass & FR_RETICMP) { + if ((pass & FR_RETMASK) == FR_RETICMP) { verbose("- ICMP unreachable sent\n"); ATOMIC_INC(frstats[0].fr_ret); - } else if ((pass & FR_RETRST) && + } else if ((pass & FR_RETMASK) == FR_FAKEICMP) { + verbose("- forged ICMP unreachable sent\n"); + ATOMIC_INC(frstats[0].fr_ret); + } else if (((pass & FR_RETMASK) == FR_RETRST) && !(fin->fin_fi.fi_fl & FI_SHORT)) { verbose("- TCP RST sent\n"); ATOMIC_INC(frstats[1].fr_ret); @@ -875,10 +930,10 @@ if (fr) { frdest_t *fdp = &fr->fr_tif; - if ((pass & FR_FASTROUTE) || + if (((pass & FR_FASTROUTE) && !out) || (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) { - ipfr_fastroute(m, fin, fdp); - m = *mp = NULL; + if (ipfr_fastroute(m, fin, fdp) == 0) + m = *mp = NULL; } if (mc) ipfr_fastroute(mc, fin, &fr->fr_dif); @@ -890,21 +945,20 @@ m_copyback(m, 0, up, hbuf); # endif # endif /* !linux */ - return (pass & FR_PASS) ? 0 : error; # else /* !SOLARIS */ if (fr) { frdest_t *fdp = &fr->fr_tif; - if ((pass & FR_FASTROUTE) || + if (((pass & FR_FASTROUTE) && !out) || (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) { - ipfr_fastroute(qif, ip, m, mp, fin, fdp); - m = *mp = NULL; + 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); } - return (pass & FR_PASS) ? changed : error; # endif /* !SOLARIS */ + return (pass & FR_PASS) ? 0 : error; #else /* _KERNEL */ if (pass & FR_NOMATCH) return 1; @@ -949,23 +1003,21 @@ * and the TCP header. We also assume that data blocks aren't allocated in * odd sizes. */ -u_short fr_tcpsum(m, ip, tcp, len) +u_short fr_tcpsum(m, ip, tcp) mb_t *m; ip_t *ip; tcphdr_t *tcp; -int len; { 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(ip->ip_p); + sum = htons((u_short)ip->ip_p); sum += htons(slen); sp = (u_short *)&ip->ip_src; sum += *sp++; /* ip_src */ @@ -976,7 +1028,7 @@ tcp->th_sum = 0; #ifdef KERNEL # if SOLARIS - sum2 = ip_cksum(m, hlen, sum); + sum2 = ip_cksum(m, hlen, sum); /* hlen == offset */ sum2 = (sum2 & 0xffff) + (sum2 >> 16); sum2 = ~sum2 & 0xffff; # else /* SOLARIS */ @@ -1003,13 +1055,11 @@ sum2 = (sum2 & 0xffff) + (sum2 >> 16); # else /* defined(BSD) || defined(sun) */ { - union { u_char c[2]; u_short s; } bytes; - u_32_t sum; - u_short *sp, slen; + u_short len = ip->ip_len; # if defined(__sgi) int add; # endif @@ -1020,7 +1070,7 @@ sp = (u_short *)&ip->ip_src; len -= (ip->ip_hl << 2); sum = ntohs(IPPROTO_TCP); - sum += htons((u_short)len); + sum += htons(len); sum += *sp++; /* ip_src */ sum += *sp++; sum += *sp++; /* ip_dst */ @@ -1034,8 +1084,8 @@ sum += *sp++; /* ack */ sum += *sp++; sum += *sp++; /* off */ - sum += *sp; /* win */ - sp += 2; /* Skip over checksum */ + sum += *sp++; /* win */ + sum += *sp++; /* Skip over checksum */ sum += *sp++; /* urp */ # ifdef __sgi @@ -1093,7 +1143,7 @@ sum = (sum & 0xffff) + (sum >> 16); sum2 = (u_short)(~sum & 0xffff); } -# endif /* defined(BSD) || defined(sun) */ +# endif /* defined(BSD) || defined(sun) */ # endif /* SOLARIS */ #else /* KERNEL */ sum2 = 0; @@ -1137,7 +1187,7 @@ * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 - * $Id: fil.c,v 1.15 1999/02/19 20:52:22 kjell Exp $ + * $IPFilter: fil.c,v 2.3.2.20 2000/05/22 06:57:42 darrenr Exp $ */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, @@ -1237,9 +1287,10 @@ frgroup_t *fr_findgroup(num, flags, which, set, fgpp) -u_short num; +u_int num; u_32_t flags; -int which, set; +minor_t which; +int set; frgroup_t ***fgpp; { frgroup_t *fg, **fgp; @@ -1252,6 +1303,7 @@ fgp = &ipfgroups[0][set]; else return NULL; + num &= 0xffff; while ((fg = *fgp)) if (fg->fg_num == num) @@ -1265,18 +1317,19 @@ frgroup_t *fr_addgroup(num, fp, which, set) -u_short num; +u_int num; frentry_t *fp; -int which, set; +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 *, sizeof(*fg)); + KMALLOC(fg, frgroup_t *); if (fg) { - fg->fg_num = num; + fg->fg_num = num & 0xffff; fg->fg_next = *fgp; fg->fg_head = fp; fg->fg_start = &fp->fr_grp; @@ -1287,9 +1340,10 @@ void fr_delgroup(num, flags, which, set) -u_short num; +u_int num; u_32_t flags; -int which, set; +minor_t which; +int set; { frgroup_t *fg, **fgp; @@ -1307,63 +1361,257 @@ * 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, list, listp) -int set, unit, *nfreedp; -frentry_t *list, **listp; +static int frflushlist(set, unit, nfreedp, listp) +int set; +minor_t unit; +int *nfreedp; +frentry_t **listp; { - register frentry_t *fp = list, *fpn; - register int freed = 0; + register int freed = 0, i; + register frentry_t *fp; - while (fp) { - fpn = fp->fr_next; + while ((fp = *listp)) { + *listp = fp->fr_next; if (fp->fr_grp) { - fp->fr_ref -= frflushlist(set, unit, nfreedp, - fp->fr_grp, &fp->fr_grp); + i = frflushlist(set, unit, nfreedp, &fp->fr_grp); + MUTEX_ENTER(&ipf_rw); + fp->fr_ref -= i; + MUTEX_EXIT(&ipf_rw); } - if (fp->fr_ref == 1) { - if (fp->fr_grhead) - fr_delgroup(fp->fr_grhead, fp->fr_flags, unit, - set); + ATOMIC_DEC(fp->fr_ref); + if (fp->fr_grhead) { + fr_delgroup((u_int)fp->fr_grhead, fp->fr_flags, + unit, set); + fp->fr_grhead = NULL; + } + if (fp->fr_ref == 0) { KFREE(fp); - *listp = fpn; freed++; - } - fp = fpn; + } else + fp->fr_next = NULL; } *nfreedp += freed; return freed; } -void frflush(unit, result) -int unit; -int *result; +int frflush(unit, flags) +minor_t unit; +int flags; { - int flags = *result, flushed = 0, set = fr_active; + 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) { + (void) frflushlist(set, unit, &flushed, &ipfilter[1][set]); + (void) frflushlist(set, unit, &flushed, &ipacct[1][set]); + } + if (flags & FR_INQUE) { + (void) frflushlist(set, unit, &flushed, &ipfilter[0][set]); + (void) frflushlist(set, unit, &flushed, &ipacct[0][set]); + } + RWLOCK_EXIT(&ipf_mutex); + return flushed; +} - if (unit == IPL_LOGIPF) { - if (flags & FR_OUTQUE) { - (void) frflushlist(set, unit, &flushed, - ipfilter[1][set], - &ipfilter[1][set]); - (void) frflushlist(set, unit, &flushed, - ipacct[1][set], &ipacct[1][set]); - } - if (flags & FR_INQUE) { - (void) frflushlist(set, unit, &flushed, - ipfilter[0][set], - &ipfilter[0][set]); - (void) frflushlist(set, unit, &flushed, - ipacct[0][set], &ipacct[0][set]); + +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(ifptr, inp) +void *ifptr; +struct in_addr *inp; +{ +# if SOLARIS + ill_t *ill = ifptr; +# else + struct ifnet *ifp = ifptr; +# endif + struct in_addr in; + +# if SOLARIS + in.s_addr = ill->ill_ipif->ipif_local_addr; +# else /* SOLARIS */ +# if linux + ; +# else /* linux */ + struct ifaddr *ifa; + struct sockaddr_in *sin; + +# 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 && + sin->sin_family != AF_INET) { +# 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) */ + in = sin->sin_addr; +# endif /* linux */ +# endif /* SOLARIS */ + *inp = in; + 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); + if (fr->fr_ifa == NULL) + fr->fr_ifa = (void *)-1; } + if (fr->fr_grp) + frsynclist(fr->fr_grp); + } +} + + +void frsync() +{ + register struct ifnet *ifp; + +# if !SOLARIS +# 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]); RWLOCK_EXIT(&ipf_mutex); - *result = flushed; } + +#else + + +/* + * return the first IP Address associated with an interface + */ +int fr_ifpaddr(ifptr, inp) +void *ifptr; +struct in_addr *inp; +{ + return 0; +} +#endif Index: sys/netinet/ip_auth.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_auth.c,v retrieving revision 1.5 retrieving revision 1.14 diff -u -r1.5 -r1.14 --- sys/netinet/ip_auth.c 1999/02/05 05:58:49 1.5 +++ sys/netinet/ip_auth.c 2000/05/24 21:59:10 1.14 @@ -1,4 +1,5 @@ -/* $OpenBSD: ip_auth.c,v 1.5 1999/02/05 05:58:49 deraadt Exp $ */ +/* $OpenBSD: ip_auth.c,v 1.14 2000/05/24 21:59:10 kjell Exp $ */ + /* * Copyright (C) 1998 by Darren Reed & Guido van Rooij. * @@ -7,7 +8,7 @@ * to the original author and the contributors. */ #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_auth.c,v 1.5 1999/02/05 05:58:49 deraadt Exp $"; +static const char rcsid[] = "@(#)$IPFilter: ip_auth.c,v 2.1.2.4 2000/05/22 06:57:45 darrenr Exp $"; #endif #include @@ -20,7 +21,7 @@ # include # include #endif -#if defined(KERNEL) && (__FreeBSD_version >= 220000) +#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) # include # include #else @@ -41,34 +42,39 @@ #else # include # 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 +# include #endif #include #include #include #include #ifndef KERNEL -#define KERNEL -#define NOT_KERNEL +# define KERNEL +# define NOT_KERNEL #endif #ifndef linux # include #endif #ifdef NOT_KERNEL -#undef KERNEL +# undef KERNEL #endif #ifdef __sgi # ifdef IFF_DRVRLOCK /* IRIX6 */ -#include +# include # endif #endif #include @@ -76,17 +82,16 @@ extern struct ifqueue ipintrq; /* ip packet input queue */ #else # ifndef linux +# if __FreeBSD_version >= 300000 +# include +# endif # include # include # endif #endif #include #include -#if defined(__OpenBSD__) -# include -#else -# include -#endif +#include #include #include #include @@ -96,6 +101,14 @@ # 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) @@ -125,7 +138,7 @@ * authorization result and that would result in a feedback loop (i.e. it * will end up returning FR_AUTH) then return FR_BLOCK instead. */ -int fr_checkauth(ip, fin) +u_32_t fr_checkauth(ip, fin) ip_t *ip; fr_info_t *fin; { @@ -185,29 +198,27 @@ * 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 -#if defined(_KERNEL) && SOLARIS -, qif) -qif_t *qif; -#else -) -#endif +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; WRITE_ENTER(&ipf_auth); - if ((fr_authstart > fr_authend) && (fr_authstart - fr_authend == -1)) { - fr_authstats.fas_nospace++; - RWLOCK_EXIT(&ipf_auth); - return 0; - } - if (fr_authend - fr_authstart == FR_NUMAUTH - 1) { + 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++; @@ -304,24 +315,27 @@ KFREE(fae); } } else { - KMALLOC(fae, frauthent_t *, sizeof(*fae)); + KMALLOC(fae, frauthent_t *); if (fae != NULL) { IRCOPY((char *)data, (char *)&fae->fae_fr, sizeof(fae->fae_fr)); WRITE_ENTER(&ipf_auth); - if (!fae->fae_age) - fae->fae_age = fr_defaultauthage; + 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); IWCOPY((char *)&fr_authstats, data, sizeof(fr_authstats)); break; case SIOCAUTHW: @@ -381,7 +395,12 @@ # 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++; @@ -471,6 +490,7 @@ *faep = fae->fae_next; KFREE(fae); } + ipauth = NULL; RWLOCK_EXIT(&ipf_auth); } @@ -502,13 +522,14 @@ } for (faep = &fae_list; (fae = *faep); ) { - if (!--fra->fra_age) { + 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); } Index: sys/netinet/ip_auth.h =================================================================== RCS file: /cvs/src/sys/netinet/ip_auth.h,v retrieving revision 1.3 retrieving revision 1.8 diff -u -r1.3 -r1.8 --- sys/netinet/ip_auth.h 1999/02/05 05:58:50 1.3 +++ sys/netinet/ip_auth.h 2000/05/24 21:59:11 1.8 @@ -1,4 +1,5 @@ -/* $OpenBSD: ip_auth.h,v 1.3 1999/02/05 05:58:50 deraadt Exp $ */ +/* $OpenBSD: ip_auth.h,v 1.8 2000/05/24 21:59:11 kjell Exp $ */ + /* * Copyright (C) 1997-1998 by Darren Reed & Guido Van Rooij. * @@ -6,7 +7,7 @@ * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * $Id: ip_auth.h,v 1.3 1999/02/05 05:58:50 deraadt Exp $ + * $IPFilter: ip_auth.h,v 2.1.2.1 2000/05/22 06:57:47 darrenr Exp $ * */ #ifndef __IP_AUTH_H__ @@ -14,18 +15,6 @@ #define FR_NUMAUTH 32 -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; -} fr_authstat_t; - typedef struct frauth { int fra_age; int fra_index; @@ -42,6 +31,19 @@ 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; @@ -50,15 +52,11 @@ extern int fr_authend; extern int fr_authsize; extern int fr_authused; -extern int fr_checkauth __P((ip_t *, fr_info_t *)); +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[]; -#if defined(_KERNEL) && SOLARIS -extern int fr_newauth __P((mb_t *, fr_info_t *, ip_t *, qif_t *)); -#else extern int fr_newauth __P((mb_t *, fr_info_t *, ip_t *)); -#endif #if defined(__NetBSD__) || defined(__OpenBSD__) extern int fr_auth_ioctl __P((caddr_t, u_long, frentry_t *, frentry_t **)); #else Index: sys/netinet/ip_fil_compat.h =================================================================== RCS file: /cvs/src/sys/netinet/ip_fil_compat.h,v retrieving revision 1.10 retrieving revision 1.16 diff -u -r1.10 -r1.16 --- sys/netinet/ip_fil_compat.h 1999/02/05 05:58:51 1.10 +++ sys/netinet/ip_fil_compat.h 2000/05/01 06:16:47 1.16 @@ -1,4 +1,5 @@ -/* $OpenBSD: ip_fil_compat.h,v 1.10 1999/02/05 05:58:51 deraadt Exp $ */ +/* $OpenBSD: ip_fil_compat.h,v 1.16 2000/05/01 06:16:47 kjell Exp $ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -7,7 +8,7 @@ * to the original author and the contributors. * * @(#)ip_compat.h 1.8 1/14/96 - * $Id: ip_fil_compat.h,v 1.10 1999/02/05 05:58:51 deraadt Exp $ + * $IPFilter: ip_compat.h,v 2.1.2.6 2000/04/25 16:21:11 darrenr Exp $ */ #ifndef __IP_COMPAT_H__ @@ -18,9 +19,12 @@ # define __P(x) x # else # define __P(x) () -# define const # endif #endif +#ifndef __STDC__ +# undef const +# define const +#endif #ifndef SOLARIS #define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) @@ -73,6 +77,7 @@ #endif #if SOLARIS # define MTYPE(m) ((m)->b_datap->db_type) +# include # include # include # include @@ -87,15 +92,30 @@ # 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 +# define ipif_local_addr ipif_lcl_addr +/* Only defined in private include file */ +# define V4_PART_OF_V6(v6) v6.s6_addr32[3] +# 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))) @@ -122,7 +142,7 @@ /* * Really, any arch where sizeof(long) != sizeof(int). */ -# if defined(__alpha__) || defined(__alpha) +# if defined(__alpha__) || defined(__alpha) || defined(_LP64) typedef unsigned int u_32_t; # else typedef unsigned long u_32_t; @@ -190,7 +210,7 @@ #define IPOPT_FINN 205 /* FINN */ -#if defined(__FreeBSD__) && defined(KERNEL) +#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL)) # if __FreeBSD__ < 3 # include # endif @@ -214,6 +234,10 @@ # 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) @@ -242,7 +266,8 @@ # define htons(x) (x) # define htonl(x) (x) # endif /* sparc */ -# define KMALLOC(a,b,c) (a) = (b)kmem_alloc((c), KM_NOSLEEP) +# 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; @@ -258,18 +283,20 @@ 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. */ - int qf_off; - int qf_len; /* this field is used for in ipfr_fastroute */ + 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... */ - int qf_hl; /* header length */ + size_t qf_hl; /* header length */ } qif_t; extern ill_t *get_unit __P((char *)); # define GETUNIT(n) get_unit((n)) +# define IFNAME(x) ((ill_t *)x)->ill_name # else /* SOLARIS */ # if defined(__sgi) +# define hz HZ # include # define IPF_LOCK_PL plhi # include @@ -286,6 +313,7 @@ # 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); @@ -295,6 +323,7 @@ # 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) ; @@ -311,10 +340,17 @@ # if !SOLARIS # include # define GETUNIT(n) ifunit((n), IFNAMSIZ) +# define IFNAME(x) ((struct ifnet *)x)->if_name # endif # else # ifndef linux # define GETUNIT(n) 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 */ @@ -331,11 +367,14 @@ # ifdef __sgi # include # include -# define KMALLOC(a,b,c) (a) = (b)kmem_alloc((c), KM_NOSLEEP) +# 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,c) (a) = (b)new_kmem_alloc((c), KMEM_NOSLEEP) +# 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 */ @@ -352,11 +391,13 @@ # include # endif /* !__FreeBSD__ || (__FreeBSD__ && __FreeBSD__>=3) */ # ifdef M_PFIL -# define KMALLOC(a, b, c) MALLOC((a), b, (c), M_PFIL, M_NOWAIT) +# 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, c) MALLOC((a), b, (c), M_TEMP, M_NOWAIT) +# 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 */ @@ -384,6 +425,7 @@ # 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) ; @@ -391,7 +433,8 @@ # define SPL_IMP(x) ; # undef SPL_X # define SPL_X(x) ; -# define KMALLOC(a,b,c) (a) = (b)malloc(c) +# 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) get_unit(x) @@ -401,6 +444,15 @@ #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 @@ -619,8 +671,8 @@ __u8 ip_hl:4; __u8 ip_v:4; # else - __u8 ip_hl:4; __u8 ip_v:4; + __u8 ip_hl:4; # endif __u8 ip_tos; __u16 ip_len; @@ -727,7 +779,8 @@ # define UNITNAME(n) dev_get((n)) -# define KMALLOC(a,b,c) (a) = (b)kmalloc((c), GFP_ATOMIC) +# 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(a,b,c) { \ @@ -791,7 +844,9 @@ * 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_MINPKTLEN (20 + 8 + 20) -#define ICMPERR_MAXPKTLEN (20 + 8 + 20 + 8) +#define ICMPERR_ICMPHLEN 8 +#define ICMPERR_IPICMPHLEN (20 + 8) +#define ICMPERR_MINPKTLEN (20 + 8 + 20) +#define ICMPERR_MAXPKTLEN (20 + 8 + 20 + 8) #endif /* __IP_COMPAT_H__ */ Index: sys/netinet/ip_fil.h =================================================================== RCS file: /cvs/src/sys/netinet/ip_fil.h,v retrieving revision 1.12 retrieving revision 1.20 diff -u -r1.12 -r1.20 --- sys/netinet/ip_fil.h 1999/02/05 05:58:50 1.12 +++ sys/netinet/ip_fil.h 2000/05/24 21:59:11 1.20 @@ -1,4 +1,5 @@ -/* $OpenBSD: ip_fil.h,v 1.12 1999/02/05 05:58:50 deraadt Exp $ */ +/* $OpenBSD: ip_fil.h,v 1.20 2000/05/24 21:59:11 kjell Exp $ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -7,16 +8,12 @@ * to the original author and the contributors. * * @(#)ip_fil.h 1.35 6/5/96 - * $Id: ip_fil.h,v 1.12 1999/02/05 05:58:50 deraadt Exp $ + * $IPFilter: ip_fil.h,v 2.3.2.11 2000/05/22 06:57:50 darrenr Exp $ */ #ifndef __IP_FIL_H__ #define __IP_FIL_H__ -#if defined(__NetBSD__) && defined(PFIL_HOOKS) -#include "opt_pfil_hooks.h" -#endif - /* * Pathnames for various IP Filter control devices. Used by LKM * and userland, so defined here. @@ -26,11 +23,11 @@ #define IPAUTH_NAME "/dev/ipauth" #ifndef SOLARIS -#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #endif #if defined(KERNEL) && !defined(_KERNEL) -#define _KERNEL +# define _KERNEL #endif #ifndef __P @@ -42,45 +39,45 @@ #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 _IOR('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 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 _IOR('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) #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 _IOR(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 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 _IOR(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) #endif #define SIOCADDFR SIOCADAFR #define SIOCDELFR SIOCRMAFR @@ -103,32 +100,43 @@ #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) + +/* + * 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_WILD (FI_W_SPORT|FI_W_DPORT) 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_short fin_out; /* in or out ? 1 == out, 0 == in */ + 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_short fin_group; /* group number, -1 for none */ - u_short fin_dlen; /* length of data portion of packet */ - u_short fin_id; /* IP packet id field */ - void *fin_ifp; /* interface packet is `on' */ 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 && defined(_KERNEL) void *fin_qfm; /* pointer to mblk where pkt starts */ + void *fin_qif; #endif } fr_info_t; /* * Size for compares on fr_info structures */ -#define FI_CSIZE offsetof(fr_info_t, fin_icode) +#define FI_CSIZE offsetof(fr_info_t, fin_icode) /* * Size for copying cache fr_info structure @@ -148,6 +156,9 @@ 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 @@ -173,10 +184,14 @@ u_short fr_stop; /* top port for <> and >< */ u_short fr_dtop; /* top port for <> and >< */ u_32_t fr_flags; /* per-rule flags && options (see below) */ - int fr_skip; /* # of rules to skip */ + u_short fr_skip; /* # of rules to skip */ + u_short fr_loglevel; /* syslog log facility + priority */ int (*fr_func) __P((int, ip_t *, fr_info_t *)); /* call this function */ - char fr_icode; /* return ICMP code */ + 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 */ } frentry_t; @@ -208,6 +223,7 @@ #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 */ @@ -222,8 +238,10 @@ #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 @@ -255,6 +273,7 @@ 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 */ @@ -276,6 +295,7 @@ 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 } filterstats_t; @@ -289,8 +309,17 @@ struct frentry *f_acctin[2]; struct frentry *f_acctout[2]; struct frentry *f_auth; + struct frgroup *f_groups[3][2]; u_long f_froute[2]; - int f_active; + 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 */ +#if !SOLARIS && defined(sun) + char f_version[17]; /* version string */ +#else + char f_version[32]; /* version string */ +#endif } friostat_t; typedef struct optlist { @@ -316,11 +345,10 @@ * structure which is then followed by any packet data. */ typedef struct iplog { - u_long ipl_magic; + u_32_t ipl_magic; + u_int ipl_count; u_long ipl_sec; u_long ipl_usec; - u_int ipl_len; - u_int ipl_count; size_t ipl_dsize; struct iplog *ipl_next; } iplog_t; @@ -339,7 +367,9 @@ u_char fl_hlen; /* length of IP headers saved */ u_short fl_rule; /* assume never more than 64k rules, total */ u_short fl_group; + u_short fl_loglevel; /* syslog log level */ u_32_t fl_flags; + u_32_t fl_lflags; } ipflog_t; @@ -352,7 +382,6 @@ #ifndef IPF_LOGGING # define IPF_LOGGING 0 #endif - #ifndef IPF_DEFAULT_PASS # define IPF_DEFAULT_PASS FR_PASS #endif @@ -386,16 +415,32 @@ # 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 void ipfr_fastroute __P((ip_t *, fr_info_t *, frdest_t *)); +extern int ipfr_fastroute __P((ip_t *, fr_info_t *, frdest_t *)); extern struct ifnet *get_unit __P((char *)); -# define FR_SCANLIST(p, ip, fi, m) fr_scanlist(p, ip, fi, m) -# if defined(__NetBSD__) || defined(__OpenBSD__) || (_BSDI_VERSION >= 199701) +# 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)); @@ -404,39 +449,34 @@ extern int iplclose __P((dev_t, int)); #else /* #ifndef _KERNEL */ # if defined(__NetBSD__) && defined(PFIL_HOOKS) -extern int ipfilterattach __P((int)); +extern void ipfilterattach __P((int)); # endif - -#if !defined(__OpenBSD__) -/* - * OpenBSD has this call in the kernel but doesn't export it to userland. - * See ip_fil.c for actual hook and more details. - */ extern int iplattach __P((void)); -#endif - extern int ipl_enable __P((void)); extern int ipl_disable __P((void)); extern void ipflog_init __P((void)); -extern int ipflog_clear __P((int)); -extern int ipflog_read __P((int, struct uio *)); +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, u_long, void **, size_t *, int *, int)); +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 *, struct in_addr)); +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 **)); -extern int icmp_error __P((ip_t *, int, int, qif_t *, - struct in_addr)); -extern int iplioctl __P((dev_t, int, int, int, cred_t *, int *)); +# 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 send_reset __P((ip_t *, qif_t *)); 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 *, int, int, char *)); -extern void copyout_mblk __P((mblk_t *, int, int, char *)); +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 *)); # ifdef IPFILTER_LOG @@ -445,12 +485,7 @@ # 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 **)); -# ifdef linux -extern int send_reset __P((tcpiphdr_t *, struct ifnet *)); -# else -extern int send_reset __P((tcpiphdr_t *)); -# endif -extern void ipfr_fastroute __P((mb_t *, fr_info_t *, frdest_t *)); +extern int ipfr_fastroute __P((mb_t *, fr_info_t *, frdest_t *)); extern size_t mbufchainlen __P((mb_t *)); # ifdef __sgi # include @@ -468,67 +503,65 @@ # endif # if (_BSDI_VERSION >= 199510) || (__FreeBSD_version >= 220000) || \ (NetBSD >= 199511) || defined(__OpenBSD__) -# if defined(__NetBSD__) || (_BSDI_VERSION >= 199701) || 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 /* FreeBSD v2.2+ or BSDI >= 199510 and < 199701 */ +# else extern int iplioctl __P((dev_t, int, caddr_t, int, struct proc *)); -# endif /* NetBSD, modern BSDI and OpenBSD */ +# endif extern int iplopen __P((dev_t, int, int, struct proc *)); extern int iplclose __P((dev_t, int, int, struct proc *)); -# else /* everybody else */ -# ifdef linux -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 *)); - else -extern int iplioctl __P((dev_t, int, caddr_t, int)); +# else +# ifndef linux extern int iplopen __P((dev_t, int)); extern int iplclose __P((dev_t, int)); -# endif /* linux */ +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 -# ifdef linux -extern int iplread(struct inode *, struct file *, char *, int); - else +# ifndef linux extern int iplread __P((dev_t, struct uio *)); -# endif /* linux */ +# else +extern int iplread(struct inode *, struct file *, char *, int); +# endif /* !linux */ # endif /* BSD >= 199306 */ # endif /* __ sgi */ # endif /* SOLARIS */ #endif /* #ifndef _KERNEL */ - -/* - * 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) -# define NETBSD_PF -#endif +extern void fixskip __P((frentry_t **, frentry_t *, int)); +extern int countbits __P((u_32_t)); extern int ipldetach __P((void)); -extern u_short fr_tcpsum __P((mb_t *, ip_t *, tcphdr_t *, int)); -#define FR_SCANLIST(p, ip, fi, m) fr_scanlist(p, ip, fi, m) -extern int fr_scanlist __P((int, ip_t *, fr_info_t *, void *)); +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 u_short ipf_cksum __P((u_short *, int)); extern int fr_copytolog __P((int, char *, int)); -extern void frflush __P((int, int *)); -extern frgroup_t *fr_addgroup __P((u_short, frentry_t *, int, int)); -extern frgroup_t *fr_findgroup __P((u_short, u_32_t, int, int, frgroup_t ***)); -extern void fr_delgroup __P((u_short, u_32_t, int, int)); +extern void fr_forgetifp __P((void *)); +extern int frflush __P((minor_t, int)); +extern void frsync __P((void)); +extern frgroup_t *fr_addgroup __P((u_int, frentry_t *, minor_t, int)); +extern frgroup_t *fr_findgroup __P((u_int, u_32_t, minor_t, int, frgroup_t ***)); +extern void fr_delgroup __P((u_int, u_32_t, minor_t, int)); +extern void fr_makefrip __P((int, ip_t *, fr_info_t *)); +extern int fr_ifpaddr __P((void *, struct in_addr *)); +extern char *memstr __P((char *, char *, int, int)); extern int ipl_unreach; -extern int ipl_inited; +extern int fr_running; extern u_long ipl_frouteok[2]; extern int fr_pass; extern int fr_flags; extern int fr_active; extern fr_info_t frcache[2]; +extern char ipfilter_version[]; #ifdef IPFILTER_LOG extern iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1]; -extern int iplused[IPL_LOGMAX + 1]; +extern size_t iplused[IPL_LOGMAX + 1]; #endif extern struct frentry *ipfilter[2][2], *ipacct[2][2]; extern struct frgroup *ipfgroups[3][2]; Index: sys/netinet/ip_fil.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_fil.c,v retrieving revision 1.24 retrieving revision 1.35 diff -u -r1.24 -r1.35 --- sys/netinet/ip_fil.c 1999/06/07 22:00:32 1.24 +++ sys/netinet/ip_fil.c 2000/05/24 21:59:11 1.35 @@ -1,4 +1,5 @@ -/* $OpenBSD: ip_fil.c,v 1.24 1999/06/07 22:00:32 deraadt Exp $ */ +/* $OpenBSD: ip_fil.c,v 1.35 2000/05/24 21:59:11 kjell Exp $ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -8,7 +9,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_fil.c,v 1.24 1999/06/07 22:00:32 deraadt Exp $"; +static const char rcsid[] = "@(#)$IPFilter: ip_fil.c,v 2.4.2.21 2000/05/22 06:57:47 darrenr Exp $"; #endif #ifndef SOLARIS @@ -18,6 +19,11 @@ #if defined(KERNEL) && !defined(_KERNEL) # define _KERNEL #endif +#include +#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ + defined(_KERNEL) +# include "opt_ipfilter_log.h" +#endif #ifdef __FreeBSD__ # if defined(_KERNEL) && !defined(IPFILTER_LKM) # include @@ -30,10 +36,10 @@ # include # include # include +# include #endif #include #include -#include #include #if __FreeBSD_version >= 220000 && defined(_KERNEL) # include @@ -47,7 +53,7 @@ #endif #include #if !SOLARIS -# if (NetBSD > 199609) || (OpenBSD > 199603) +# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000) # include # else # include @@ -65,6 +71,9 @@ #endif #if __FreeBSD_version >= 300000 # include +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# include "opt_ipfilter.h" +# endif #endif #ifdef __sgi #include @@ -75,7 +84,7 @@ #include #include #if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */ -#include +# include #endif #include #include @@ -85,23 +94,24 @@ #include #include #ifndef _KERNEL +# include # include #endif -#if defined(__OpenBSD__) #include -#else -#include -#endif #include #include #include #include #include #include +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) +# include +#endif #ifndef MIN -#define MIN(a,b) (((a)<(b))?(a):(b)) +# define MIN(a,b) (((a)<(b))?(a):(b)) #endif -#if !SOLARIS && defined(_KERNEL) +#if !SOLARIS && defined(_KERNEL) && !defined(__sgi) +# include extern int ip_optcopy __P((struct ip *, struct ip *)); #endif @@ -113,27 +123,20 @@ static struct ifnet **ifneta = NULL; static int nifs = 0; #else -# if (BSD < 199306) && !defined(__sgi) -static int (*fr_saveslowtimo) __P((void)); -# else -static void (*fr_saveslowtimo) __P((void)); -# endif # if (BSD < 199306) || defined(__sgi) extern int tcp_ttl; # endif #endif -int ipl_inited = 0; -#if defined(__OpenBSD__) +# if defined (__OpenBSD__) int ipl_unreach = ICMP_UNREACH_FILTER_PROHIB; -#else +# else int ipl_unreach = ICMP_UNREACH_FILTER; -#endif +# endif + u_long ipl_frouteok[2] = {0, 0}; -static void fixskip __P((frentry_t **, frentry_t *, int)); static void frzerostats __P((caddr_t)); -static void frsync __P((void)); #if defined(__NetBSD__) || defined(__OpenBSD__) static int frrequest __P((int, u_long, caddr_t, int)); #else @@ -141,8 +144,10 @@ #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)); @@ -159,7 +164,12 @@ struct sockaddr *, struct rtentry *)); # endif #endif +int fr_running = 0; +#if (__FreeBSD_version >= 300000) && defined(_KERNEL) +struct callout_handle ipfr_slowtimer_ch; +#endif + #if (_BSDI_VERSION >= 199510) && defined(_KERNEL) # include # include @@ -207,61 +217,68 @@ ipfilterattach(count) int count; { - iplattach(); + if (iplattach() != 0) + printf("IP Filter failed to attach\n"); } # endif -#if defined( __OpenBSD__) -/* - * Since iplattach() is called by main() at boot time, we put in a - * fake stub so that none of the machinery is initialized till explicitly - * enabled via ipf -E. Therefore we rename the real iplattach() to - * ipl_enable(). See also skeleton iplinit() later in this file. - */ -void iplattach __P((int)); -void iplattach(int dummy) {}; -int ipl_enable() -# else int iplattach() -# endif /* OpenBSD */ { char *defpass; int s; -# ifdef __sgi - int error; +# if defined(__sgi) || (defined(NETBSD_PF) && (__NetBSD_Version__ >= 104200000)) + int error = 0; # endif SPL_NET(s); - if (ipl_inited || (fr_checkp == fr_check)) { + 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) { + appr_unload(); + ip_natunload(); + fr_stateunload(); + return error; + } +# else pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT); +# endif # endif # ifdef __sgi error = ipfilter_sgi_attach(); if (error) { SPL_X(s); + appr_unload(); + ip_natunload(); + fr_stateunload(); return error; } # endif - ipl_inited = 1; bzero((char *)frcache, sizeof(frcache)); - bzero((char *)nat_table, sizeof(nat_table)); fr_savep = fr_checkp; fr_checkp = fr_check; - fr_saveslowtimo = inetsw[0].pr_slowtimo; - inetsw[0].pr_slowtimo = ipfr_slowtimer; + fr_running = 1; -# ifdef IPFILTER_LOG - ipflog_init(); -# endif SPL_X(s); if (fr_pass & FR_PASS) defpass = "pass"; @@ -270,6 +287,7 @@ else defpass = "no-match -> block"; +#if !defined(__OpenBSD__) printf("IP Filter: initialized. Default = %s all, Logging = %s\n", defpass, # ifdef IPFILTER_LOG @@ -277,6 +295,16 @@ # else "disabled"); # endif + printf("%s\n", ipfilter_version); +#endif + +#ifdef _KERNEL +# if (__FreeBSD_version >= 300000) && defined(_KERNEL) + ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); +# else + timeout(ipfr_slowtimer, NULL, hz/2); +# endif +#endif return 0; } @@ -285,16 +313,26 @@ * Disable the filter by removing the hooks from the IP input/output * stream. */ -# if defined(__OpenBSD__) -int ipl_disable() -# else int ipldetach() -# endif { int s, i = FR_INQUE|FR_OUTQUE; +#if defined(NETBSD_PF) && (__NetBSD_Version__ >= 104200000) + int error = 0; +#endif +#ifdef _KERNEL +# if (__FreeBSD_version >= 300000) + untimeout(ipfr_slowtimer, NULL, ipfr_slowtimer_ch); +# else +# ifdef __sgi + untimeout(ipfr_slowtimer); +# else + untimeout(ipfr_slowtimer, NULL); +# endif +# endif +#endif SPL_NET(s); - if (!ipl_inited) + if (!fr_running) { printf("IP Filter: not initialized\n"); SPL_X(s); @@ -302,18 +340,25 @@ } fr_checkp = fr_savep; - inetsw[0].pr_slowtimo = fr_saveslowtimo; - frflush(IPL_LOGIPF, &i); - ipl_inited = 0; + 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 # endif # ifdef __sgi ipfilter_sgi_detach(); # endif + appr_unload(); ipfr_unload(); ip_natunload(); fr_stateunload(); @@ -328,7 +373,7 @@ static void frzerostats(data) caddr_t data; { - struct friostat fio; + friostat_t fio; bcopy((char *)frstats, (char *)fio.f_st, sizeof(struct filterstats) * 2); @@ -367,7 +412,8 @@ ) #endif dev_t dev; -#if defined(__NetBSD__) || defined(__OpenBSD__) || (_BSDI_VERSION >= 199701) +#if defined(__NetBSD__) || defined(__OpenBSD__) || \ + (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) u_long cmd; #else int cmd; @@ -381,12 +427,17 @@ #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; # if defined(__OpenBSD__) + /* Prevent IPF and NAT changes when securelevel > 1 */ if (securelevel > 1) { switch (cmd) { # ifndef IPFILTER_LKM @@ -414,17 +465,26 @@ } } # endif /* OpenBSD */ -#endif /* _KERNEL */ +#else /* _KERNEL */ + unit = dev; +#endif SPL_NET(s); if (unit == IPL_LOGNAT) { - error = nat_ioctl(data, cmd, mode); + if (fr_running) + error = nat_ioctl(data, cmd, mode); + else + error = EIO; SPL_X(s); return error; } + if (unit == IPL_LOGSTATE) { - error = fr_state_ioctl(data, cmd, mode); + if (fr_running) + error = fr_state_ioctl(data, cmd, mode); + else + error = EIO; SPL_X(s); return error; } @@ -446,15 +506,9 @@ else { IRCOPY(data, (caddr_t)&enable, sizeof(enable)); if (enable) -# if defined(__OpenBSD__) - error = ipl_enable(); - else - error = ipl_disable(); -# else error = iplattach(); else error = ipldetach(); -# endif /* OpenBSD */ } break; } @@ -512,6 +566,21 @@ fio.f_active = fr_active; fio.f_froute[0] = ipl_frouteok[0]; fio.f_froute[1] = ipl_frouteok[1]; + fio.f_running = fr_running; + fio.f_groups[0][0] = ipfgroups[0][0]; + fio.f_groups[0][1] = ipfgroups[0][1]; + fio.f_groups[1][0] = ipfgroups[1][0]; + fio.f_groups[1][1] = ipfgroups[1][1]; + fio.f_groups[2][0] = ipfgroups[2][0]; + fio.f_groups[2][1] = ipfgroups[2][1]; +#ifdef IPFILTER_LOG + fio.f_logging = 1; +#else + fio.f_logging = 0; +#endif + fio.f_defpass = fr_pass; + strncpy(fio.f_version, ipfilter_version, + sizeof(fio.f_version)); IWCOPY((caddr_t)&fio, data, sizeof(fio)); break; } @@ -526,7 +595,7 @@ error = EPERM; else { IRCOPY(data, (caddr_t)&tmp, sizeof(tmp)); - frflush(unit, &tmp); + tmp = frflush(unit, tmp); IWCOPY((caddr_t)&tmp, data, sizeof(tmp)); } break; @@ -568,38 +637,27 @@ return error; } - -static void frsync() -{ -#ifdef _KERNEL - struct ifnet *ifp; - -# if defined(__OpenBSD__) || (NetBSD >= 199511) - for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) -# else - for (ifp = ifnet; ifp; ifp = ifp->if_next) -# endif - ip_natsync(ifp); -#endif -} - -static void fixskip(listp, rp, addremove) -frentry_t **listp, *rp; -int addremove; +void fr_forgetifp(ifp) +void *ifp; { - frentry_t *fp; - int rules = 0, rn = 0; + register frentry_t *f; - 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; + 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; + RWLOCK_EXIT(&ipf_mutex); + ip_natsync(ifp); } @@ -618,20 +676,22 @@ frentry_t frd; frdest_t *fdp; frgroup_t *fg = NULL; - int error = 0, in, group; + int error = 0, in; + u_int group; fp = &frd; IRCOPY(data, (caddr_t)fp, sizeof(*fp)); + fp->fr_ref = 0; /* * Check that the group number does exist and that if a head group * has been specified, doesn't exist. */ - if (fp->fr_grhead && - fr_findgroup(fp->fr_grhead, fp->fr_flags, unit, set, NULL)) + if ((req != SIOCZRLST) && fp->fr_grhead && + fr_findgroup((u_int)fp->fr_grhead, fp->fr_flags, unit, set, NULL)) return EEXIST; - if (fp->fr_group && - !fr_findgroup(fp->fr_group, fp->fr_flags, unit, set, NULL)) + 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; @@ -658,6 +718,13 @@ if (!fp->fr_ifa) fp->fr_ifa = (void *)-1; } +#if BSD >= 199306 + if (*fp->fr_oifname) { + fp->fr_oifa = GETUNIT(fp->fr_oifname); + if (!fp->fr_oifa) + fp->fr_oifa = (void *)-1; + } +#endif fdp = &fp->fr_dif; fp->fr_flags &= ~FR_DUP; @@ -698,14 +765,14 @@ } if (!f) { - ftail = fprev; - if (req != SIOCINAFR && req != SIOCINIFR) - while ((f = *ftail)) - ftail = &f->fr_next; - else if (fp->fr_hits) - while (--fp->fr_hits && (f = *ftail)) - ftail = &f->fr_next; - f = NULL; + if (req == SIOCINAFR || req == SIOCINIFR) { + ftail = fprev; + if (fp->fr_hits) { + while (--fp->fr_hits && (f = *ftail)) + ftail = &f->fr_next; + } + f = NULL; + } } if (req == SIOCDELFR || req == SIOCRMIFR) { @@ -719,8 +786,8 @@ if (unit == IPL_LOGAUTH) return fr_auth_ioctl(data, req, f, ftail); if (f->fr_grhead) - fr_delgroup(f->fr_grhead, fp->fr_flags, unit, - set); + fr_delgroup((u_int)f->fr_grhead, fp->fr_flags, + unit, set); fixskip(fprev, f, -1); *ftail = f->fr_next; KFREE(f); @@ -730,8 +797,8 @@ error = EEXIST; else { if (unit == IPL_LOGAUTH) - return fr_auth_ioctl(data, req, f, ftail); - KMALLOC(f, frentry_t *, sizeof(*f)); + 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++; @@ -757,33 +824,33 @@ /* * routines below for saving IP headers to buffer */ -#ifdef __sgi -# ifdef _KERNEL +# ifdef __sgi +# ifdef _KERNEL int IPL_EXTERN(open)(dev_t *pdev, int flags, int devtype, cred_t *cp) -# else +# else int IPL_EXTERN(open)(dev_t dev, int flags) -# endif -#else +# endif +# else int IPL_EXTERN(open)(dev, flags -# if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ +# if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ (__FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL) , devtype, p) int devtype; struct proc *p; -# else +# else ) -# endif +# endif dev_t dev; int flags; -#endif /* __sgi */ +# endif /* __sgi */ { -#if defined(__sgi) && defined(_KERNEL) +# if defined(__sgi) && defined(_KERNEL) u_int min = geteminor(*pdev); -#else +# else u_int min = GET_MINOR(dev); -#endif +# endif - if (2 < min) + if (IPL_LOGMAX < min) min = ENXIO; else min = 0; @@ -791,25 +858,25 @@ } -#ifdef __sgi +# 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) || \ +# if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ (__FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL) , devtype, p) int devtype; struct proc *p; -# else +# else ) -# endif +# endif dev_t dev; int flags; -#endif /* __sgi */ +# endif /* __sgi */ { u_int min = GET_MINOR(dev); - if (2 < min) + if (IPL_LOGMAX < min) min = ENXIO; else min = 0; @@ -822,9 +889,9 @@ * called during packet processing and cause an inconsistancy to appear in * the filter lists. */ -#ifdef __sgi +# ifdef __sgi int IPL_EXTERN(read)(dev_t dev, uio_t *uio, cred_t *crp) -#else +# else # if BSD >= 199306 int IPL_EXTERN(read)(dev, uio, ioflag) int ioflag; @@ -833,13 +900,13 @@ # endif dev_t dev; register struct uio *uio; -#endif /* __sgi */ +# endif /* __sgi */ { -# ifdef IPFILTER_LOG +# ifdef IPFILTER_LOG return ipflog_read(GET_MINOR(dev), uio); -# else +# else return ENXIO; -# endif +# endif } @@ -847,77 +914,155 @@ * 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(ti) -struct tcpiphdr *ti; +int send_reset(oip, fin) +struct ip *oip; +fr_info_t *fin; { - struct tcpiphdr *tp; - struct tcphdr *tcp; + struct tcphdr *tcp, *tcp2; struct mbuf *m; - int tlen = 0, err; + int tlen = 0; ip_t *ip; -# if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) - struct route ro; -# endif - if (ti->ti_flags & TH_RST) + 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); - m->m_data += max_linkhdr; # endif if (m == NULL) + return ENOBUFS; + if (m == NULL) return -1; - if (ti->ti_flags & TH_SYN) + if (tcp->th_flags & TH_SYN) tlen = 1; - m->m_len = sizeof (struct tcpiphdr); + m->m_len = sizeof(*tcp2) + sizeof(*ip); # if BSD >= 199306 - m->m_pkthdr.len = sizeof (struct tcpiphdr); + m->m_data += max_linkhdr; + m->m_pkthdr.len = sizeof(*tcp2) + sizeof(*ip); m->m_pkthdr.rcvif = (struct ifnet *)0; # endif - bzero(mtod(m, char *), sizeof(struct tcpiphdr)); ip = mtod(m, struct ip *); - tp = mtod(m, struct tcpiphdr *); - tcp = (struct tcphdr *)((char *)ip + sizeof(struct ip)); + bzero((char *)ip, sizeof(*tcp2) + sizeof(*ip)); + tcp2 = (struct tcphdr *)(ip + 1); + + ip->ip_src.s_addr = oip->ip_dst.s_addr; + ip->ip_dst.s_addr = oip->ip_src.s_addr; + tcp2->th_dport = tcp->th_sport; + tcp2->th_sport = tcp->th_dport; + 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; + ip->ip_p = IPPROTO_TCP; + ip->ip_len = htons(sizeof(struct tcphdr)); + tcp2->th_sum = in_cksum(m, sizeof(*ip) + sizeof(*tcp2)); + + ip->ip_id = oip->ip_id; + ip->ip_tos = oip->ip_tos; + ip->ip_len = sizeof(*ip) + sizeof(*tcp2); + + return send_ip(ip, fin, m); +} + - ip->ip_src.s_addr = ti->ti_dst.s_addr; - ip->ip_dst.s_addr = ti->ti_src.s_addr; - tcp->th_dport = ti->ti_sport; - tcp->th_sport = ti->ti_dport; - tcp->th_ack = htonl(ntohl(ti->ti_seq) + tlen); - tcp->th_off = sizeof(struct tcphdr) >> 2; - tcp->th_flags = TH_RST|TH_ACK; - tp->ti_pr = ((struct ip *)ti)->ip_p; - tp->ti_len = htons(sizeof(struct tcphdr)); - tcp->th_sum = in_cksum(m, sizeof(struct tcpiphdr)); - - ip->ip_tos = ((struct ip *)ti)->ip_tos; - ip->ip_p = ((struct ip *)ti)->ip_p; - ip->ip_len = sizeof (struct tcpiphdr); +static int send_ip(ip, fin, m) +fr_info_t *fin; +struct mbuf *m; +ip_t *ip; +{ + ip->ip_v = IPVERSION; + ip->ip_hl = (sizeof(*ip) >> 2); # if (BSD < 199306) || defined(__sgi) ip->ip_ttl = tcp_ttl; # else ip->ip_ttl = ip_defttl; # 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; +struct in_addr dst; +{ + struct icmp *icmp; + struct mbuf *m; + ip_t *nip; + int code; + + if ((oip->ip_p == IPPROTO_ICMP) && !(fin->fin_fi.fi_fl & FI_SHORT)) + switch (ntohs(fin->fin_data[0]) >> 8) + { + case ICMP_ECHO : + case ICMP_TSTAMP : + case ICMP_IREQ : + case ICMP_MASKREQ : + break; + default : + return 0; + } -# if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) - bzero((char *)&ro, sizeof(ro)); - err = ip_output(m, (struct mbuf *)0, &ro, 0, 0); - if (ro.ro_rt) - RTFREE(ro.ro_rt); + code = fin->fin_icode; +# if (BSD < 199306) || defined(__sgi) + m = m_get(M_DONTWAIT, MT_HEADER); # else - /* - * extra 0 in case of multicast - */ -# ifdef __OpenBSD__ - err = ip_output(m, (struct mbuf *)0, 0, 0, 0, 0); -# else - err = ip_output(m, (struct mbuf *)0, 0, 0, 0); -# endif + m = m_gethdr(M_DONTWAIT, MT_HEADER); +# endif + if (m == NULL) + return ENOBUFS; + m->m_len = sizeof(*nip) + sizeof(*icmp) + 8; +# if BSD >= 199306 + m->m_data += max_linkhdr; + m->m_pkthdr.len = sizeof(*nip) + sizeof(*icmp) + 8; + m->m_pkthdr.rcvif = (struct ifnet *)0; +# endif + + bzero(mtod(m, char *), (size_t)sizeof(*nip) + sizeof(*icmp) + 8); + nip = mtod(m, ip_t *); + icmp = (struct icmp *)(nip + 1); + + nip->ip_p = IPPROTO_ICMP; + nip->ip_id = oip->ip_id; + nip->ip_sum = 0; + nip->ip_ttl = 60; + nip->ip_tos = oip->ip_tos; + nip->ip_len = sizeof(*nip) + sizeof(*icmp) + 8; + if (dst.s_addr == 0) { + if (fr_ifpaddr(fin->fin_ifp, &dst) == -1) + return -1; + } + nip->ip_src = dst; + nip->ip_dst = oip->ip_src; + + icmp->icmp_type = type; + icmp->icmp_code = code; + icmp->icmp_cksum = 0; + bcopy((char *)oip, (char *)&icmp->icmp_ip, sizeof(*oip)); + bcopy((char *)oip + (oip->ip_hl << 2), + (char *)&icmp->icmp_ip + sizeof(*oip), 8); /* 64 bits */ +# ifndef sparc + { + register u_short __iplen, __ipoff; + ip_t *ip = &icmp->icmp_ip; + + __iplen = ip->ip_len; + __ipoff = ip->ip_off; + ip->ip_len = htons(__iplen); + ip->ip_off = htons(__ipoff); + } # endif - return err; + icmp->icmp_cksum = ipf_cksum((u_short *)icmp, sizeof(*icmp) + 8); + return send_ip(nip, fin, m); } @@ -933,15 +1078,11 @@ # endif iplinit() { -# if defined(__OpenBSD__) - /* must explicitly enable with 'ipf -E' - * which invokes ipl_enable(); */ -# else - (void) iplattach(); -# endif + if (iplattach() != 0) + printf("IP Filter failed to attach\n"); ip_init(); } -# endif /* !LKM, !sgi, FreeBSD < 3 */ +# endif /* ! __NetBSD__ */ size_t mbufchainlen(m0) @@ -955,7 +1096,7 @@ } -void ipfr_fastroute(m0, fin, fdp) +int ipfr_fastroute(m0, fin, fdp) struct mbuf *m0; fr_info_t *fin; frdest_t *fdp; @@ -963,12 +1104,13 @@ register struct ip *ip, *mhip; register struct mbuf *m = m0; register struct route *ro; - struct ifnet *ifp = fdp->fd_ifp; - int len, off, error = 0; - int hlen = fin->fin_hlen; - struct route iproute; + 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 *); /* * Route packet. @@ -977,13 +1119,32 @@ bzero((caddr_t)ro, sizeof (*ro)); dst = (struct sockaddr_in *)&ro->ro_dst; dst->sin_family = AF_INET; - dst->sin_addr = fdp->fd_ip.s_addr ? fdp->fd_ip : ip->ip_dst; -# ifdef __bsdi__ + + 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 +# ifdef RTF_CLONING rtalloc_ign(ro, RTF_CLONING); # else rtalloc_ign(ro, RTF_PRCLONING); @@ -992,7 +1153,7 @@ rtalloc(ro); # endif if (!ifp) { - if (!(fin->fin_fr->fr_flags & FR_FASTROUTE)) { + if (!fr || !(fr->fr_flags & FR_FASTROUTE)) { error = -2; goto bad; } @@ -1014,15 +1175,19 @@ * 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)) { + (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { ATOMIC_INC(frstats[1].fr_acct); } fin->fin_fr = NULL; - (void) ip_natout(ip, hlen, fin); - } - if (fin->fin_out) + 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. @@ -1066,7 +1231,11 @@ 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; @@ -1096,6 +1265,10 @@ error = ENOBUFS; /* ??? */ goto sendorfree; } +# if BSD >= 199306 + m->m_pkthdr.len = mhlen + len; + m->m_pkthdr.rcvif = NULL; +# endif mhip->ip_off = htons((u_short)mhip->ip_off); mhip->ip_sum = 0; mhip->ip_sum = in_cksum(m, mhlen); @@ -1135,50 +1308,56 @@ if (ro->ro_rt) RTFREE(ro->ro_rt); - return; + return 0; bad: + if (error == EMSGSIZE) { + sifp = fin->fin_ifp; + fin->fin_ifp = ifp; + code = fin->fin_icode; + fin->fin_icode = ICMP_UNREACH_NEEDFRAG; + (void) send_icmp_err(ip, ICMP_UNREACH, fin, ip->ip_dst); + fin->fin_ifp = sifp; + fin->fin_icode = code; + } m_freem(m); goto done; } #else /* #ifdef _KERNEL */ -#ifdef __sgi +# ifdef __sgi static int no_output __P((struct ifnet *ifp, struct mbuf *m, struct sockaddr *s)) -#else +# else static int no_output __P((struct ifnet *ifp, struct mbuf *m, struct sockaddr *s, struct rtentry *rt)) -#endif +# endif { return 0; } # ifdef __STDC__ -#ifdef __sgi +# ifdef __sgi static int write_output __P((struct ifnet *ifp, struct mbuf *m, struct sockaddr *s)) -#else +# else static int write_output __P((struct ifnet *ifp, struct mbuf *m, struct sockaddr *s, struct rtentry *rt)) -#endif +# endif { -# if !(defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) ip_t *ip = (ip_t *)m; -# endif # else static int write_output(ifp, ip) struct ifnet *ifp; ip_t *ip; { # endif - FILE *fp; char fname[32]; + FILE *fp; # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) + (defined(OpenBSD) && (OpenBSD >= 199603)) # if defined __OpenBSD__ sprintf(fname, "/var/run/%s", ifp->if_xname); # else @@ -1258,7 +1437,6 @@ void init_ifp() { - struct ifnet *ifp, **ifa; char fname[32]; int fd; @@ -1271,8 +1449,11 @@ sprintf(fname, "/var/run/%s", ifp->if_xname); # else sprintf(fname, "/tmp/%s", ifp->if_xname); -#endif - if ((fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0600)) != -1) +# endif + fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); + if (fd == -1) + perror("open"); + else close(fd); } # else @@ -1280,14 +1461,17 @@ for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { ifp->if_output = write_output; sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit); - if ((fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0600)) != -1) + fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); + if (fd == -1) + perror("open"); + else close(fd); } # endif } -void ipfr_fastroute(ip, fin, fdp) +int ipfr_fastroute(ip, fin, fdp) ip_t *ip; fr_info_t *fin; frdest_t *fdp; @@ -1295,7 +1479,7 @@ struct ifnet *ifp = fdp->fd_ifp; if (!ifp) - return; /* no routing table out here */ + 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)); @@ -1305,6 +1489,7 @@ #else (*ifp->if_output)(ifp, (void *)ip, NULL, 0); #endif + return 0; } @@ -1330,5 +1515,11 @@ { verbose("- TCP RST sent\n"); return 0; +} + + +void frsync() +{ + return; } #endif /* _KERNEL */ Index: sys/netinet/ip_frag.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_frag.c,v retrieving revision 1.11 retrieving revision 1.17 diff -u -r1.11 -r1.17 --- sys/netinet/ip_frag.c 1999/02/05 05:58:51 1.11 +++ sys/netinet/ip_frag.c 2000/03/13 23:40:18 1.17 @@ -1,4 +1,5 @@ -/* $OpenBSD: ip_frag.c,v 1.11 1999/02/05 05:58:51 deraadt Exp $ */ +/* $OpenBSD: ip_frag.c,v 1.17 2000/03/13 23:40:18 kjell Exp $ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -8,7 +9,11 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_frag.c,v 1.11 1999/02/05 05:58:51 deraadt Exp $"; +static const char rcsid[] = "@(#)$IPFilter: ip_frag.c,v 2.4.2.4 1999/11/28 04:52:10 darrenr Exp $"; +#endif + +#if defined(KERNEL) && !defined(_KERNEL) +# define _KERNEL #endif #include @@ -22,49 +27,49 @@ # include #endif #if defined(KERNEL) && (__FreeBSD_version >= 220000) -#include -#include +# include +# include #else -#include +# include #endif #include #ifndef linux -#include +# 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 -# include +# ifdef _KERNEL +# include +# endif # include # include #endif - #include #ifdef sun -#include +# include #endif #include #include #include #include #ifndef linux -#include +# include #endif #include #include #include -#if defined(__OpenBSD__) -# include -#else -# include -#endif +#include #include #include #include @@ -72,6 +77,17 @@ #include #include #include +#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 + ipfr_t *ipfr_heads[IPFT_SIZE]; ipfr_t *ipfr_nattab[IPFT_SIZE]; @@ -79,16 +95,26 @@ int ipfr_inuse = 0, fr_ipfrttl = 120; /* 60 seconds */ #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; +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 *, int, ipfr_t **)); +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() @@ -107,10 +133,10 @@ static ipfr_t *ipfr_new(ip, fin, pass, table) ip_t *ip; fr_info_t *fin; -int pass; +u_int pass; ipfr_t *table[]; { - ipfr_t **fp, *fr, frag; + ipfr_t **fp, *fra, frag; u_int idx; frag.ipfr_p = ip->ip_p; @@ -128,8 +154,8 @@ /* * first, make sure it isn't already there... */ - for (fp = &table[idx]; (fr = *fp); fp = &fr->ipfr_next) - if (!bcmp((char *)&frag.ipfr_src, (char *)&fr->ipfr_src, + for (fp = &table[idx]; (fra = *fp); fp = &fra->ipfr_next) + if (!bcmp((char *)&frag.ipfr_src, (char *)&fra->ipfr_src, IPFR_CMPSZ)) { ATOMIC_INC(ipfr_stats.ifs_exists); return NULL; @@ -139,39 +165,43 @@ * allocate some memory, if possible, if not, just record that we * failed to do so. */ - KMALLOC(fr, ipfr_t *, sizeof(*fr)); - if (fr == NULL) { + KMALLOC(fra, ipfr_t *); + if (fra == NULL) { ATOMIC_INC(ipfr_stats.ifs_nomem); return NULL; } + if ((fra->ipfr_rule = fin->fin_fr) != NULL) { + ATOMIC_INC(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 ((fr->ipfr_next = table[idx])) - table[idx]->ipfr_prev = fr; - fr->ipfr_prev = NULL; - fr->ipfr_data = NULL; - table[idx] = fr; - bcopy((char *)&frag.ipfr_src, (char *)&fr->ipfr_src, IPFR_CMPSZ); - fr->ipfr_ttl = fr_ipfrttl; - fr->ipfr_pass = pass & ~(FR_LOGFIRST|FR_LOG); + 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. */ - fr->ipfr_off = (ip->ip_off & IP_OFFMASK) + (fin->fin_dlen >> 3); + fra->ipfr_off = (ip->ip_off & IP_OFFMASK) + (fin->fin_dlen >> 3); ATOMIC_INC(ipfr_stats.ifs_new); ATOMIC_INC(ipfr_inuse); - return fr; + return fra; } int ipfr_newfrag(ip, fin, pass) ip_t *ip; fr_info_t *fin; -int pass; +u_int pass; { ipfr_t *ipf; @@ -185,7 +215,7 @@ int ipfr_nat_newfrag(ip, fin, pass, nat) ip_t *ip; fr_info_t *fin; -int pass; +u_int pass; nat_t *nat; { ipfr_t *ipf; @@ -251,14 +281,14 @@ f->ipfr_prev = NULL; table[idx] = f; } - off = ip->ip_off; + 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 & IP_OFFMASK) == f->ipfr_off) { - if (!(off & IP_MF)) + if (off == f->ipfr_off) { + if (!(ip->ip_off & IP_MF)) f->ipfr_ttl = 1; else f->ipfr_off = atoff; @@ -301,18 +331,19 @@ /* * functional interface for normal lookups of the fragment cache */ -int ipfr_knownfrag(ip, fin) +frentry_t *ipfr_knownfrag(ip, fin) ip_t *ip; fr_info_t *fin; { - int ret; - ipfr_t *ipf; + frentry_t *fr = NULL; + ipfr_t *fra; READ_ENTER(&ipf_frag); - ipf = ipfr_lookup(ip, fin, ipfr_heads); - ret = ipf ? ipf->ipfr_pass : 0; + fra = ipfr_lookup(ip, fin, ipfr_heads); + if (fra != NULL) + fr = fra->ipfr_rule; RWLOCK_EXIT(&ipf_frag); - return ret; + return fr; } @@ -335,34 +366,53 @@ } +static void ipfr_delete(fra) +ipfr_t *fra; +{ + frentry_t *fr; + + fr = fra->ipfr_rule; + if (fr != NULL) { + ATOMIC_DEC(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, *fr; + 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]; (fr = *fp); ) { - *fp = fr->ipfr_next; - KFREE(fr); + 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]; (fr = *fp); ) { - *fp = fr->ipfr_next; - nat = (nat_t *)fr->ipfr_data; + for (fp = &ipfr_nattab[idx]; (fra = *fp); ) { + *fp = fra->ipfr_next; + nat = fra->ipfr_data; if (nat != NULL) { - if (nat->nat_data == fr) + if (nat->nat_data == fra) nat->nat_data = NULL; } - KFREE(fr); + ipfr_delete(fra); } RWLOCK_EXIT(&ipf_natfrag); RWLOCK_EXIT(&ipf_nat); @@ -375,15 +425,30 @@ * 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 { - ipfr_t **fp, *fr; + ipfr_t **fp, *fra; nat_t *nat; - int s, idx; + int idx; +#if defined(_KERNEL) +# if !SOLARIS + int s; +# else + extern int fr_running; + + if (fr_running <= 0) + return; +# endif +#endif + READ_ENTER(&ipf_solaris); #ifdef __sgi ipfilter_sgi_intfsync(); #endif @@ -397,21 +462,15 @@ * remove it from the chain and free it. */ for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fp = &ipfr_heads[idx]; (fr = *fp); ) { - --fr->ipfr_ttl; - if (fr->ipfr_ttl == 0) { - if (fr->ipfr_prev) - fr->ipfr_prev->ipfr_next = - fr->ipfr_next; - if (fr->ipfr_next) - fr->ipfr_next->ipfr_prev = - fr->ipfr_prev; - *fp = fr->ipfr_next; + for (fp = &ipfr_heads[idx]; (fra = *fp); ) { + --fra->ipfr_ttl; + if (fra->ipfr_ttl == 0) { + *fp = fra->ipfr_next; + ipfr_delete(fra); ATOMIC_INC(ipfr_stats.ifs_expire); ATOMIC_DEC(ipfr_inuse); - KFREE(fr); } else - fp = &fr->ipfr_next; + fp = &fra->ipfr_next; } RWLOCK_EXIT(&ipf_frag); @@ -425,26 +484,20 @@ WRITE_ENTER(&ipf_nat); WRITE_ENTER(&ipf_natfrag); for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fp = &ipfr_nattab[idx]; (fr = *fp); ) { - --fr->ipfr_ttl; - if (fr->ipfr_ttl == 0) { - if (fr->ipfr_prev) - fr->ipfr_prev->ipfr_next = - fr->ipfr_next; - if (fr->ipfr_next) - fr->ipfr_next->ipfr_prev = - fr->ipfr_prev; - *fp = fr->ipfr_next; + for (fp = &ipfr_nattab[idx]; (fra = *fp); ) { + --fra->ipfr_ttl; + if (fra->ipfr_ttl == 0) { ATOMIC_INC(ipfr_stats.ifs_expire); ATOMIC_DEC(ipfr_inuse); - nat = (nat_t *)fr->ipfr_data; + nat = fra->ipfr_data; if (nat != NULL) { - if (nat->nat_data == fr) + if (nat->nat_data == fra) nat->nat_data = NULL; } - KFREE(fr); + *fp = fra->ipfr_next; + ipfr_delete(fra); } else - fp = &fr->ipfr_next; + fp = &fra->ipfr_next; } RWLOCK_EXIT(&ipf_natfrag); RWLOCK_EXIT(&ipf_nat); @@ -456,11 +509,16 @@ ipfr_timer_id = timeout(ipfr_slowtimer, NULL, drv_usectohz(500000)); # else # ifndef linux - ip_slowtimo(); +# if (__FreeBSD_version >= 300000) + ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); +# else + timeout(ipfr_slowtimer, NULL, hz/2); +# endif # endif # if (BSD < 199306) && !defined(__sgi) return 0; # endif # endif + RWLOCK_EXIT(&ipf_solaris); } #endif /* defined(_KERNEL) */ Index: sys/netinet/ip_frag.h =================================================================== RCS file: /cvs/src/sys/netinet/ip_frag.h,v retrieving revision 1.8 retrieving revision 1.12 diff -u -r1.8 -r1.12 --- sys/netinet/ip_frag.h 1999/02/05 05:58:51 1.8 +++ sys/netinet/ip_frag.h 2000/03/13 23:40:18 1.12 @@ -1,4 +1,5 @@ -/* $OpenBSD: ip_frag.h,v 1.8 1999/02/05 05:58:51 deraadt Exp $ */ +/* $OpenBSD: ip_frag.h,v 1.12 2000/03/13 23:40:18 kjell Exp $ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -7,7 +8,7 @@ * to the original author and the contributors. * * @(#)ip_frag.h 1.5 3/24/96 - * $Id: ip_frag.h,v 1.8 1999/02/05 05:58:51 deraadt Exp $ + * $IPFilter: ip_frag.h,v 2.2 1999/08/06 06:26:38 darrenr Exp $ */ #ifndef __IP_FRAG_H__ @@ -25,7 +26,7 @@ u_char ipfr_tos; u_short ipfr_off; u_short ipfr_ttl; - u_char ipfr_pass; + frentry_t *ipfr_rule; } ipfr_t; @@ -44,16 +45,21 @@ extern int fr_ipfrttl; extern ipfrstat_t *ipfr_fragstats __P((void)); -extern int ipfr_newfrag __P((ip_t *, fr_info_t *, int)); -extern int ipfr_nat_newfrag __P((ip_t *, fr_info_t *, int, struct nat *)); +extern 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 int ipfr_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)); #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__ */ Index: sys/netinet/ip_ftp_pxy.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_ftp_pxy.c,v retrieving revision 1.4 retrieving revision 1.10 diff -u -r1.4 -r1.10 --- sys/netinet/ip_ftp_pxy.c 1999/02/05 05:58:52 1.4 +++ sys/netinet/ip_ftp_pxy.c 2000/04/12 21:32:39 1.10 @@ -1,5 +1,6 @@ -/* $OpenBSD: ip_ftp_pxy.c,v 1.4 1999/02/05 05:58:52 deraadt Exp $ - * $Id: ip_ftp_pxy.c,v 1.4 1999/02/05 05:58:52 deraadt Exp $ +/* $OpenBSD: ip_ftp_pxy.c,v 1.10 2000/04/12 21:32:39 kjell Exp $ */ + +/* * Simple FTP transparent proxy for in-kernel use. For use with the NAT * code. */ @@ -8,6 +9,7 @@ #endif #define isdigit(x) ((x) >= '0' && (x) <= '9') +#define isupper(x) ((unsigned)((x) - 'A') <= 'Z' - 'A') #define IPF_FTP_PROXY @@ -15,29 +17,115 @@ #define IPF_MAXPORTLEN 30 #define IPF_MIN227LEN 39 #define IPF_MAX227LEN 51 +#define IPF_FTPBUFSZ MAX(96,IPF_MAX227LEN) /* This *MUST* be >= 51! */ -int ippr_ftp_init __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_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); -int ippr_ftp_portmsg __P((fr_info_t *, ip_t *, nat_t *nat)); -int ippr_ftp_pasvmsg __P((fr_info_t *, ip_t *, tcphdr_t *, nat_t *)); +int ippr_ftp_portmsg __P((fr_info_t *, ip_t *, nat_t *)); +int ippr_ftp_pasvmsg __P((fr_info_t *, ip_t *, nat_t *)); +int ippr_ftp_complete __P((char *, size_t)); + u_short ipf_ftp_atoi __P((char **)); +static frentry_t natfr; +int ippr_ftp_pasvonly = 0; + /* - * FTP application proxy initialization. + * Initialize local structures. */ -int ippr_ftp_init(fin, ip, aps, nat) +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_complete(buf, len) +char *buf; +size_t len; +{ + register char *s, c; + register size_t i; + + if (len < 5) + return -1; + s = buf; + c = *s++; + i = len - 1; + + 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 != ' ') + return -1; + } else + return -1; + } else + return -1; + } else + return -1; + } else + return -1; + + for (; i && (c = *s); i--, s++) { + if ((c == '\r') && (i != 2)) + return -1; + if ((c == '\n') && (i != 1)) + return -1; + else if ((i == 2) && (c != '\r')) + return -1; + else if ((i == 1) && (c != '\n')) + return -1; + } + return i; +} + + +int ippr_ftp_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; + ftpinfo_t *ftp; + + KMALLOC(ftp, ftpinfo_t *); + if (ftp == NULL) + return -1; + aps->aps_data = ftp; + aps->aps_psiz = sizeof(ftpinfo_t); - aps->aps_sport = tcp->th_sport; - aps->aps_dport = tcp->th_dport; + ftp->ftp_passok = 0; return 0; } @@ -76,12 +164,14 @@ ip_t *ip; nat_t *nat; { - char portbuf[IPF_MAXPORTLEN + 1], newbuf[IPF_MAXPORTLEN + 1], *s; - int off, olen, dlen, nlen = 0, inc = 0; - u_int a1, a2, a3, a4; + char portbuf[IPF_FTPBUFSZ], newbuf[IPF_FTPBUFSZ], *s; tcphdr_t *tcp, tcph, *tcp2 = &tcph; - struct in_addr swip; + size_t nlen = 0, dlen, olen; u_short a5, a6, sp, dp; + u_int a1, a2, a3, a4; + struct in_addr swip; + int off, inc = 0; + ftpinfo_t *ftp; fr_info_t fi; nat_t *ipn; mb_t *m; @@ -90,24 +180,51 @@ #endif tcp = (tcphdr_t *)fin->fin_dp; + bzero(portbuf, sizeof(portbuf)); 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); + if (dlen > 0) + copyout_mblk(m, off, MIN(sizeof(portbuf), dlen), portbuf); #else + m = *(mb_t **)fin->fin_mp; + dlen = mbufchainlen(m) - off; - bzero(portbuf, sizeof(portbuf)); - m_copydata(m, off, MIN(sizeof(portbuf), dlen), portbuf); + if (dlen > 0) + m_copydata(m, off, MIN(sizeof(portbuf), dlen), portbuf); #endif + if (dlen == 0) + return 0; portbuf[sizeof(portbuf) - 1] = '\0'; *newbuf = '\0'; - if (!strncmp(portbuf, "PORT ", 5)) { + /* + * Check that a user is progressing through the login ok. + */ + if (ippr_ftp_complete(portbuf, dlen)) + return 0; + + ftp = nat->nat_aps->aps_data; + switch (ftp->ftp_passok) + { + case 0 : + if (!strncmp(portbuf, "USER ", 5)) + ftp->ftp_passok = 1; + break; + case 2 : + if (!strncmp(portbuf, "PASS ", 5)) + ftp->ftp_passok = 3; + break; + } + if (ftp->ftp_passok != 4) + return 0; + /* + * Check for client sending out PORT message. + */ + if (!ippr_ftp_pasvonly && !strncmp(portbuf, "PORT ", 5)) { if (dlen < IPF_MINPORTLEN) return 0; } else @@ -128,9 +245,9 @@ 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. - */ + * 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)) @@ -139,14 +256,18 @@ a5 = ipf_ftp_atoi(&s); if (!s) return 0; + if (*s == ')') + s++; /* * check for CR-LF at the end. */ - if (((*s == '\r') && (*(s + 1) == '\n')) || - ((*(s - 1) == '\r') && (*s == '\n'))) + if (*s == '\n') + s--; + if ((*s == '\r') && (*(s + 1) == '\n')) { + s += 2; a6 = a5 & 0xff; - else + } else return 0; a5 >>= 8; /* @@ -157,8 +278,9 @@ a3 = (a1 >> 8) & 0xff; a4 = a1 & 0xff; a1 >>= 24; - olen = s - portbuf + 1; - (void) sprintf(newbuf, "%s %d,%d,%d,%d,%d,%d\r\n", + olen = s - portbuf; + /* 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); @@ -182,6 +304,9 @@ 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); @@ -191,7 +316,7 @@ /* the mbuf chain will be extended if necessary by m_copyback() */ m_copyback(m, off, nlen, newbuf); #endif - if (inc) { + if (inc != 0) { #if SOLARIS || defined(__sgi) register u_32_t sum1, sum2; @@ -204,32 +329,46 @@ sum2 -= sum1; sum2 = (sum2 & 0xffff) + (sum2 >> 16); - fix_outcksum(&ip->ip_sum, sum2); + 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. - */ + * 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_inip, sp, - ip->ip_dst, dp); + ipn = nat_outlookup(fin->fin_ifp, IPN_TCP, nat->nat_p, nat->nat_inip, + ip->ip_dst, (dp << 16) | sp); if (ipn == NULL) { bcopy((char *)fin, (char *)&fi, sizeof(fi)); bzero((char *)tcp2, sizeof(*tcp2)); + tcp2->th_win = htons(8192); tcp2->th_sport = sp; - tcp2->th_dport = dp; + 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, NAT_OUTBOUND); + 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, FR_INQUE|FR_PASS| - FR_QUICK|FR_KEEPSTATE); + (void) fr_addstate(ip, &fi, FI_W_DPORT); } ip->ip_src = swip; } @@ -247,18 +386,19 @@ } -int ippr_ftp_pasvmsg(fin, ip, tcp, nat) +int ippr_ftp_pasvmsg(fin, ip, nat) fr_info_t *fin; ip_t *ip; -tcphdr_t *tcp; nat_t *nat; { - char portbuf[IPF_MAX227LEN + 1], newbuf[IPF_MAX227LEN + 1], *s; + char portbuf[IPF_FTPBUFSZ], newbuf[IPF_FTPBUFSZ], *s; int off, olen, dlen, nlen = 0, inc = 0; - u_int a1, a2, a3, a4; tcphdr_t tcph, *tcp2 = &tcph; - struct in_addr swip; - u_short a5, a6; + struct in_addr swip, swip2; + u_short a5, a6, dp, sp; + u_int a1, a2, a3, a4; + ftpinfo_t *ftp; + tcphdr_t *tcp; fr_info_t fi; nat_t *ipn; mb_t *m; @@ -266,43 +406,72 @@ 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; + bzero(portbuf, sizeof(portbuf)); #if SOLARIS m = fin->fin_qfm; dlen = msgdsize(m) - off; - bzero(portbuf, sizeof(portbuf)); - copyout_mblk(m, off, MIN(sizeof(portbuf), dlen), portbuf); + if (dlen > 0) + 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); + if (dlen > 0) + m_copydata(m, off, MIN(sizeof(portbuf), dlen), portbuf); #endif + if (dlen == 0) + return 0; portbuf[sizeof(portbuf) - 1] = '\0'; *newbuf = '\0'; + /* + * Check that a user is progressing through the login ok. + * Don't put the switch in one common function because one side + * should only see numeric responses and the other commands. + */ + + ftp = nat->nat_aps->aps_data; + switch (ftp->ftp_passok) + { + case 1 : + if (!strncmp(portbuf, "331", 3)) + ftp->ftp_passok = 2; + else if (!strncmp(portbuf, "530", 3)) + ftp->ftp_passok = 0; + break; + case 3 : + if (!strncmp(portbuf, "230", 3)) + ftp->ftp_passok = 4; + break; + default : + break; + } + + if (ippr_ftp_complete(portbuf, dlen) || (ftp->ftp_passok != 4)) + return 0; + + /* + * Check for PASV reply message. + */ if (!strncmp(portbuf, "227 ", 4)) { if (dlen < IPF_MIN227LEN) return 0; else if (strncmp(portbuf, "227 Entering Passive Mode", 25)) return 0; -#ifndef notyet - return 0; -#endif } else return 0; - /* - * Skip the PORT command + space - */ + * Skip the PORT command + space + */ s = portbuf + 25; while (*s && !isdigit(*s)) s++; /* - * Pick out the address components, two at a time. - */ + * Pick out the address components, two at a time. + */ a1 = ipf_ftp_atoi(&s); if (!s) return 0; @@ -311,9 +480,9 @@ 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. - */ + * 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)) @@ -323,25 +492,29 @@ 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 - 1) == '\r') && (*s == '\n'))) + * check for CR-LF at the end. + */ + if ((*s == '\r') && (*(s + 1) == '\n')) { + s += 2; a6 = a5 & 0xff; - else + } else return 0; a5 >>= 8; /* - * Calculate new address parts for 227 reply - */ - a1 = ntohl(nat->nat_inip.s_addr); + * 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; - olen = s - portbuf + 1; - (void) sprintf(newbuf, "%s %d,%d,%d,%d,%d,%d\r\n", + olen = s - portbuf; + (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); @@ -374,7 +547,7 @@ /* the mbuf chain will be extended if necessary by m_copyback() */ m_copyback(m, off, nlen, newbuf); #endif - if (inc) { + if (inc != 0) { #if SOLARIS || defined(__sgi) register u_32_t sum1, sum2; @@ -387,7 +560,7 @@ sum2 -= sum1; sum2 = (sum2 & 0xffff) + (sum2 >> 16); - fix_outcksum(&ip->ip_sum, sum2); + fix_outcksum(&ip->ip_sum, sum2, 0); #endif ip->ip_len += inc; } @@ -396,27 +569,42 @@ * Add skeleton NAT entry for connection which will come back the * other way. */ - bcopy((char *)fin, (char *)&fi, sizeof(fi)); - bzero((char *)tcp2, sizeof(*tcp2)); - tcp2->th_sport = htons(a5 << 8 | a6); - fi.fin_dp = (char *)tcp2; - swip = ip->ip_src; - ip->ip_src = nat->nat_oip; - ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_TCP, NAT_INBOUND); - if (ipn != NULL) - ipn->nat_age = fr_defnatage; - (void) fr_addstate(ip, &fi, FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE); - ip->ip_src = swip; + 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) { + 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 */ + 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_src = swip; + ip->ip_dst = swip2; + } return inc; } + int ippr_ftp_in(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; - return ippr_ftp_pasvmsg(fin, ip, tcp, nat); + return ippr_ftp_pasvmsg(fin, ip, nat); } Index: sys/netinet/ip_log.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_log.c,v retrieving revision 1.4 retrieving revision 1.8 diff -u -r1.4 -r1.8 --- sys/netinet/ip_log.c 1999/02/05 05:58:52 1.4 +++ sys/netinet/ip_log.c 2000/03/13 23:40:18 1.8 @@ -1,4 +1,5 @@ -/* $OpenBSD: ip_log.c,v 1.4 1999/02/05 05:58:52 deraadt Exp $ */ +/* $OpenBSD: ip_log.c,v 1.8 2000/03/13 23:40:18 kjell Exp $ */ + /* * Copyright (C) 1997-1998 by Darren Reed. * @@ -6,23 +7,29 @@ * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * $Id: ip_log.c,v 1.4 1999/02/05 05:58:52 deraadt Exp $ + * $IPFilter: ip_log.c,v 2.1.2.2 1999/09/21 11:55:44 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) +# include +# 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 - -# if defined(KERNEL) && !defined(_KERNEL) -# define _KERNEL -# endif -# ifdef __FreeBSD__ -# if defined(_KERNEL) && !defined(IPFILTER_LKM) -# include -# else -# include -# endif -# endif # ifndef _KERNEL # include # include @@ -31,7 +38,6 @@ # endif # include # include -# include # include # if __FreeBSD_version >= 220000 && defined(_KERNEL) # include @@ -45,7 +51,7 @@ # endif # include # if !SOLARIS -# if (NetBSD > 199609) || (OpenBSD > 199603) +# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000) # include # else # include @@ -97,12 +103,8 @@ # endif # ifndef _KERNEL # include -# endif -# if defined(__OpenBSD__) -# include -# else -# include # endif +# include # include # include # include @@ -110,6 +112,10 @@ # include # include # include +# if (__FreeBSD_version >= 300000) +# include +# endif + # ifndef MIN # define MIN(a,b) (((a)<(b))?(a):(b)) # endif @@ -122,10 +128,9 @@ # endif # endif -iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1]; -int iplused[IPL_LOGMAX+1]; -u_long iplcrc[IPL_LOGMAX+1]; -u_long iplcrcinit; +iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1], *ipll[IPL_LOGMAX+1]; +size_t iplused[IPL_LOGMAX+1]; +fr_info_t iplcrc[IPL_LOGMAX+1]; # ifdef linux static struct wait_queue *iplwait[IPL_LOGMAX+1]; # endif @@ -137,20 +142,15 @@ */ void ipflog_init() { - struct timeval tv; 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])); } -# if BSD >= 199306 || defined(__FreeBSD__) || defined(__sgi) - microtime(&tv); -# else - uniqtime(&tv); -# endif - iplcrcinit = tv.tv_sec ^ (tv.tv_usec << 8) ^ tv.tv_usec; } @@ -169,8 +169,7 @@ mb_t *m; { ipflog_t ipfl; - register int mlen, hlen; - u_long crc; + register size_t mlen, hlen; size_t sizes[2]; void *ptrs[2]; int types[2]; @@ -193,12 +192,12 @@ struct icmp *icmp; icmp = (struct icmp *)((char *)ip + hlen); - + /* - * For ICMP, if the packet is an error packet, also - * include the information about the packet which - * caused the error. - */ + * 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 : @@ -243,11 +242,15 @@ 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 +# if SOLARIS /* * Are we copied from the mblk or an aligned array ? */ @@ -260,45 +263,47 @@ sizes[1] = hlen + mlen; types[1] = 0; } -#else +# else ptrs[1] = m; sizes[1] = hlen + mlen; types[1] = 1; -#endif - crc = (ipf_cksum((u_short *)fin, FI_CSIZE) << 8) + iplcrcinit; - return ipllog(IPL_LOGIPF, crc, ptrs, sizes, types, 2); +# endif + return ipllog(IPL_LOGIPF, fin, ptrs, sizes, types, 2); } /* * ipllog */ -int ipllog(dev, crc, items, itemsz, types, cnt) +int ipllog(dev, fin, items, itemsz, types, cnt) int dev; -u_long crc; +fr_info_t *fin; void **items; size_t *itemsz; int *types, cnt; { - iplog_t *ipl; caddr_t buf, s; - int len, i; + 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. */ - if (crc) { - MUTEX_ENTER(&ipl_mutex); - if ((iplcrc[dev] == crc) && *iplh[dev]) { - (*iplh[dev])->ipl_count++; + 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; } - iplcrc[dev] = crc; - MUTEX_EXIT(&ipl_mutex); - } + 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. @@ -310,7 +315,7 @@ * check that we have space to record this information and can * allocate that much. */ - KMALLOC(buf, caddr_t, len); + KMALLOCS(buf, caddr_t, len); if (!buf) return 0; MUTEX_ENTER(&ipl_mutex); @@ -356,6 +361,7 @@ s += itemsz[i]; } MUTEX_ENTER(&ipl_mutex); + ipll[dev] = ipl; *iplh[dev] = ipl; iplh[dev] = &ipl->ipl_next; # if SOLARIS @@ -374,11 +380,12 @@ int ipflog_read(unit, uio) -int unit; +minor_t unit; struct uio *uio; { + size_t dlen, copied; + int error = 0; iplog_t *ipl; - int error = 0, dlen, copied; # if defined(_KERNEL) && !SOLARIS int s; # endif @@ -387,7 +394,7 @@ * Sanity checks. Make sure the minor # is valid and we're copying * a valid chunk of data. */ - if ((IPL_LOGMAX < unit) || (unit < 0)) + if (IPL_LOGMAX < unit) return ENXIO; if (!uio->uio_resid) return 0; @@ -431,43 +438,48 @@ for (copied = 0; (ipl = iplt[unit]); copied += dlen) { dlen = ipl->ipl_dsize; - if (dlen + sizeof(iplog_t) > uio->uio_resid) + 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, ipl->ipl_dsize, UIO_READ, uio); - KFREES((caddr_t)ipl, ipl->ipl_dsize); - if (error) + 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); - iplused[unit] -= dlen; } - if (!ipl) { + if (!iplt[unit]) { iplused[unit] = 0; iplh[unit] = &iplt[unit]; + ipll[unit] = NULL; } - if (!error) { - MUTEX_EXIT(&ipl_mutex); - SPL_X(s); - } -#ifdef linux + MUTEX_EXIT(&ipl_mutex); + SPL_X(s); +# ifdef linux if (!error) - return copied; + return (int)copied; return -error; -#else +# else return error; -#endif +# endif } int ipflog_clear(unit) -int unit; +minor_t unit; { iplog_t *ipl; int used; @@ -478,9 +490,10 @@ KFREES((caddr_t)ipl, ipl->ipl_dsize); } iplh[unit] = &iplt[unit]; + ipll[unit] = NULL; used = iplused[unit]; iplused[unit] = 0; - iplcrc[unit] = 0; + bzero((char *)&iplcrc[unit], FI_CSIZE); MUTEX_EXIT(&ipl_mutex); return used; } Index: sys/netinet/ip_nat.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_nat.c,v retrieving revision 1.22 retrieving revision 1.32 diff -u -r1.22 -r1.32 --- sys/netinet/ip_nat.c 1999/08/08 00:43:00 1.22 +++ sys/netinet/ip_nat.c 2000/05/24 21:59:11 1.32 @@ -1,4 +1,5 @@ -/* $OpenBSD: ip_nat.c,v 1.22 1999/08/08 00:43:00 niklas Exp $ */ +/* $OpenBSD: ip_nat.c,v 1.32 2000/05/24 21:59:11 kjell Exp $ */ + /* * Copyright (C) 1995-1998 by Darren Reed. * @@ -10,7 +11,7 @@ */ #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 1.22 1999/08/08 00:43:00 niklas Exp $"; +static const char rcsid[] = "@(#)$IPFilter: ip_nat.c,v 2.2.2.18 2000/05/19 15:52:29 darrenr Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) @@ -22,12 +23,16 @@ #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) && (__FreeBSD_version >= 220000) +#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) # include # include #else @@ -49,7 +54,9 @@ #else # include # include -# include +# ifdef _KERNEL +# include +# endif # include # include #endif @@ -59,9 +66,12 @@ #include #if __FreeBSD_version >= 300000 # include +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# include "opt_ipfilter.h" +# endif #endif #ifdef sun -#include +# include #endif #include #include @@ -76,8 +86,8 @@ #endif #ifdef RFC1825 -#include -#include +# include +# include extern struct ifnet vpnif; #endif @@ -87,27 +97,35 @@ #include #include #include -#if defined(__OpenBSD__) #include -#else -#include -#endif #include #include #include #include #include #include +#if (__FreeBSD_version >= 300000) +# include +#endif #ifndef MIN -#define MIN(a,b) (((a)<(b))?(a):(b)) +# define MIN(a,b) (((a)<(b))?(a):(b)) #endif #undef SOCKADDR_IN #define SOCKADDR_IN struct sockaddr_in -nat_t *nat_table[2][NAT_SIZE], *nat_instances = NULL; +nat_t **nat_table[2] = { NULL, NULL }, + *nat_instances = NULL; ipnat_t *nat_list = NULL; -u_long fr_defnatage = 1200, /* 10 minutes (600 seconds) */ - fr_defnaticmpage = 6; /* 3 seconds */ +u_int ipf_nattable_sz = NAT_TABLE_SZ; +u_int ipf_natrules_sz = NAT_SIZE; +u_int ipf_rdrrules_sz = RDR_SIZE; +u_32_t nat_masks = 0; +u_32_t rdr_masks = 0; +ipnat_t **nat_rules = NULL; +ipnat_t **rdr_rules = NULL; + +u_long fr_defnatage = DEF_NAT_AGE, + fr_defnaticmpage = 6; /* 3 seconds */ natstat_t nat_stats; #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) extern kmutex_t ipf_rw; @@ -117,31 +135,87 @@ static int nat_flushtable __P((void)); static int nat_clearlist __P((void)); static void nat_delete __P((struct nat *)); -static int nat_ifpaddr __P((nat_t *, void *, struct in_addr *)); +static void nat_delrdr __P((struct ipnat *)); +static void nat_delnat __P((struct ipnat *)); + + +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; + return 0; +} + -#define LONG_SUM(in) (((in) & 0xffff) + ((in) >> 16)) +void nat_delrdr(n) +ipnat_t *n; +{ + ipnat_t **n1; + u_32_t iph; + u_int hv; + + iph = n->in_outip & n->in_outmsk; + hv = NAT_HASH_FN(iph, ipf_rdrrules_sz); + for (n1 = &rdr_rules[hv]; *n1 && (*n1 != n); n1 = &(*n1)->in_rnext) + ; + if (*n1) + *n1 = n->in_rnext; +} + + +static void nat_delnat(n) +ipnat_t *n; +{ + ipnat_t **n1; + u_32_t iph; + u_int hv; + + iph = n->in_inip & n->in_inmsk; + hv = NAT_HASH_FN(iph, ipf_natrules_sz); + for (n1 = &nat_rules[hv]; *n1 && (*n1 != n); n1 = &(*n1)->in_mnext) + ; + if (*n1) + *n1 = n->in_mnext; +} -#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); } -void fix_outcksum(sp, n) +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); @@ -152,15 +226,22 @@ } -void fix_incksum(sp, n) +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 sum1 = (~ntohs(*sp)) & 0xffff; sum1 += ~(n) & 0xffff; sum1 = (sum1 >> 16) + (sum1 & 0xffff); @@ -205,14 +286,20 @@ int mode; { register ipnat_t *nat, *nt, *n = NULL, **np = NULL; + int error = 0, ret, k; ipnat_t natd; - int error = 0, ret; + u_32_t i, j; #if defined(_KERNEL) && !SOLARIS int s; #endif +#if (BSD >= 199306) && defined(_KERNEL) + if ((securelevel >= 2) && (mode & FWRITE)) + return EPERM; +#endif + nat = NULL; /* XXX gcc -Wuninitialized */ - KMALLOC(nt, ipnat_t *, sizeof(*nt)); + KMALLOC(nt, ipnat_t *); if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) IRCOPY(data, (char *)&natd, sizeof(natd)); @@ -223,8 +310,12 @@ WRITE_ENTER(&ipf_nat); if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) { nat = &natd; - nat->in_inip &= nat->in_inmsk; - nat->in_outip &= nat->in_outmsk; + nat->in_flags &= IPN_USERFLAGS; + if ((nat->in_redir & NAT_MAPBLK) == 0) { + nat->in_inip &= nat->in_inmsk; + if ((nat->in_flags & IPN_RANGE) == 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)) @@ -233,6 +324,20 @@ 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; @@ -242,31 +347,82 @@ error = EEXIST; break; } - n = nt; - nt = NULL; - if (n == NULL) { + 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); if (!n->in_ifp) n->in_ifp = (void *)-1; if (n->in_plabel[0] != '\0') { - n->in_apr = ap_match(n->in_p, n->in_plabel); + 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) { + u_int hv; + + 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, ipf_rdrrules_sz); + np = rdr_rules + hv; + while (*np != NULL) + np = &(*np)->in_rnext; + n->in_rnext = NULL; + *np = n; + } + if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { + u_int hv; + + 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, ipf_natrules_sz); + np = nat_rules + hv; + while (*np != NULL) + np = &(*np)->in_mnext; + n->in_mnext = NULL; + *np = n; } - n->in_next = *np; + n->in_use = 0; - n->in_space = ~(0xffffffff & ntohl(n->in_outmsk)); - if (n->in_space) /* lose 2: broadcast + network address */ - n->in_space -= 2; + 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_RANGE) + n->in_space = ntohl(n->in_outmsk) - ntohl(n->in_outip); else - n->in_space = 1; /* single IP# mapping */ - if ((n->in_outmsk != 0xffffffff) && n->in_outmsk) + 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_RANGE) != 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_RANGE) == 0)) n->in_nip = ntohl(n->in_outip) + 1; else n->in_nip = ntohl(n->in_outip); @@ -275,12 +431,37 @@ /* * Multiply by the number of ports made available. */ - if (ntohs(n->in_pmax) > ntohs(n->in_pmin)) + if (ntohs(n->in_pmax) >= ntohs(n->in_pmin)) { n->in_space *= (ntohs(n->in_pmax) - - ntohs(n->in_pmin)); + 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 */ - *np = n; n = NULL; nat_stats.ns_rules++; break; @@ -294,10 +475,18 @@ 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) - ap_free(n->in_apr); + appr_free(n->in_apr); KFREE(n); nat_stats.ns_rules--; } else { @@ -311,6 +500,10 @@ 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; IWCOPY((char *)&nat_stats, (char *)data, sizeof(nat_stats)); break; @@ -387,17 +580,21 @@ break; } + if (natd->nat_fr != NULL) { + ATOMIC_DEC(natd->nat_fr->fr_ref); + } /* * 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. */ - if ((ipn = natd->nat_ptr)) { + 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) - ap_free(ipn->in_apr); + appr_free(ipn->in_apr); KFREE(ipn); nat_stats.ns_rules--; } @@ -423,7 +620,7 @@ *np = n->in_next; if (!n->in_use) { if (n->in_apr) - ap_free(n->in_apr); + appr_free(n->in_apr); KFREE(n); nat_stats.ns_rules--; } else { @@ -434,6 +631,7 @@ } } + /* * nat_flushtable - clear the NAT table of all mapping entries. */ @@ -441,13 +639,17 @@ { register nat_t *nat, **natp; register int j = 0; - + /* - * ALL NAT mappings deleted, so lets just make it the deletions + * ALL NAT mappings deleted, so lets just make the deletions * quicker. */ - bzero((char *)nat_table[0], sizeof(nat_table[0])); - bzero((char *)nat_table[1], sizeof(nat_table[1])); + 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; @@ -467,11 +669,16 @@ 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) - ap_free(n->in_apr); + appr_free(n->in_apr); KFREE(n); nat_stats.ns_rules--; } else { @@ -480,78 +687,13 @@ } i++; } + nat_masks = 0; + rdr_masks = 0; return i; } /* - * return the first IP Address associated with an interface - */ -static int nat_ifpaddr(nat, ifptr, inp) -nat_t *nat; -void *ifptr; -struct in_addr *inp; -{ -#if SOLARIS - ill_t *ill = ifptr; -#else - struct ifnet *ifp = ifptr; -#endif - struct in_addr in; - -#if SOLARIS - in.s_addr = ntohl(ill->ill_ipif->ipif_local_addr); -#else /* SOLARIS */ -# if linux - ; -# else /* linux */ - struct ifaddr *ifa; - struct sockaddr_in *sin; - -# 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 = (SOCKADDR_IN *)&ifa->ifa_addr; -# else - sin = (SOCKADDR_IN *)ifa->ifa_addr; - while (sin && ifa && - sin->sin_family != AF_INET) { -# if (__FreeBSD_version >= 300000) - ifa = TAILQ_NEXT(ifa, ifa_link); -# else -# if defined(__NetBSD__) || defined(__OpenBSD__) - ifa = ifa->ifa_list.tqe_next; -# else - ifa = ifa->ifa_next; -# endif -# endif /* __FreeBSD_version >= 300000 */ - if (ifa) - sin = (SOCKADDR_IN *)ifa->ifa_addr; - } - if (!ifa || !sin) - return -1; -# endif /* (BSD < 199306) && (!__sgi && IFF_DRVLOCK) */ - in = sin->sin_addr; - in.s_addr = ntohl(in.s_addr); -# endif /* linux */ -#endif /* SOLARIS */ - *inp = in; - return 0; -} - - -/* * Create a new NAT table entry. * NOTE: assumes write lock on ipf_nat has been obtained already. */ @@ -559,15 +701,19 @@ ipnat_t *np; ip_t *ip; fr_info_t *fin; -u_short flags; +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; + nat_t *nat, **natp, *natl = NULL; + struct in_addr in, inb; tcphdr_t *tcp = NULL; - nat_t *nat, **natp; u_short nflags; + u_int hv; +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) + qif_t *qf = fin->fin_qif; +#endif nflags = flags & np->in_flags; if (flags & IPN_TCPUDP) { @@ -577,20 +723,19 @@ } /* Give me a new nat */ - KMALLOC(nat, nat_t *, sizeof(*nat)); + KMALLOC(nat, nat_t *); if (nat == NULL) 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. - */ + * Values at which the search for a free resouce starts. + */ u_32_t st_ip; u_short st_port; @@ -603,85 +748,180 @@ st_port = np->in_pnext; do { - l++; port = 0; in.s_addr = np->in_nip; + if (l == 0) { + /* + * Check to see if there is an existing NAT + * setup for this IP address pair. + */ + natl = nat_maplookup(fin->fin_ifp, flags, + ip->ip_src, ip->ip_dst); + if (natl != NULL) { + in = natl->nat_outip; + if ((in.s_addr & np->in_outmsk) != + np->in_outip) + in.s_addr = 0; + else +#ifndef sparc + in.s_addr = ntohl(in.s_addr); +#else + ; +#endif + } + } + if ((np->in_outmsk == 0xffffffff) && (np->in_pnext == 0)) { - if (l > 1) { + if (l > 0) { KFREE(nat); return NULL; } } - if (!in.s_addr && (np->in_outmsk == 0xffffffff)) { - if ((l > 1) || - nat_ifpaddr(nat, fin->fin_ifp, &in) == -1) { + if (np->in_redir & NAT_MAPBLK) { + if ((l >= np->in_ppip) || ((l > 0) && + !(flags & IPN_TCPUDP))) { KFREE(nat); return NULL; + } + /* + * 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 (!in.s_addr && !np->in_outmsk) { - if (l > 1) { + } else if (!np->in_outip && + (np->in_outmsk == 0xffffffff)) { + /* + * 0/32 - use the interface's IP address. + */ + if ((l > 0) || + fr_ifpaddr(fin->fin_ifp, &in) == -1) { KFREE(nat); return NULL; } + 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) { + KFREE(nat); + return NULL; + } in.s_addr = ntohl(ip->ip_src.s_addr); - } else if ((nflags & IPN_TCPUDP)) { + } else if ((np->in_outmsk != 0xffffffff) && + (np->in_pnext == 0) && + ((l > 0) || (natl == 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) { + KFREE(nat); + return NULL; + } 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)) { + if (np->in_pnext > ntohs(np->in_pmax)) { np->in_pnext = ntohs(np->in_pmin); if (np->in_outmsk != 0xffffffff) np->in_nip++; } - } else if (np->in_outmsk != 0xffffffff) - np->in_nip++; + } - if (!np->in_nip && (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_flags & IPN_RANGE) { + 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; - if ((np->in_nip & ntohl(np->in_outmsk)) > - ntohl(np->in_outip)) - np->in_nip = ntohl(np->in_outip) + 1; + + /* + * 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_WILD, + (u_int)ip->ip_p, ip->ip_dst, inb, + (port << 16) | dport); /* - * Has the search wrapped around and come back to the - * start ? - */ - if ((np->in_pnext != 0) && (st_port == np->in_pnext) && + * 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)) { KFREE(nat); return NULL; } - - } while (nat_inlookup(fin->fin_ifp, flags, ip->ip_dst, - dport, in, port)); + l++; + } while (natl != NULL); - if (np->in_space > 1) + 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; - - sum1 = (ntohl(ip->ip_src.s_addr) & 0xffff) + - (ntohl(ip->ip_src.s_addr) >> 16) + ntohs(sport); - sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16) + ntohs(port); + 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; + 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, @@ -692,14 +932,22 @@ if (!(nport = np->in_pnext)) nport = dport; + /* + * 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) && (nport == dport)) { + KFREE(nat); + return NULL; + } + nat->nat_inip.s_addr = htonl(in.s_addr); nat->nat_outip = ip->ip_dst; nat->nat_oip = ip->ip_src; - - sum1 = (ntohl(ip->ip_dst.s_addr) & 0xffff) + - (ntohl(ip->ip_dst.s_addr) >> 16) + ntohs(dport); - sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16) + ntohs(nport); + 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; @@ -708,59 +956,60 @@ } } - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - /* Do it twice */ - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - - if (sum1 > sum2) - sum2--; /* Because ~1 == -2, We really need ~1 == -1 */ - sumd = sum2 - sum1; - sumd = (sumd & 0xffff) + (sumd >> 16); - nat->nat_sumd = (sumd & 0xffff) + (sumd >> 16); + 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 = (ntohl(ip->ip_src.s_addr) & 0xffff) + - (ntohl(ip->ip_src.s_addr) >> 16); + sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr)); else - sum1 = (ntohl(ip->ip_dst.s_addr) & 0xffff) + - (ntohl(ip->ip_dst.s_addr) >> 16); + sum1 = LONG_SUM(ntohl(ip->ip_dst.s_addr)); - sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16); + sum2 = LONG_SUM(in.s_addr); - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - /* Do it twice */ - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - - if (sum1 > sum2) - sum2--; /* Because ~1 == -2, We really need ~1 == -1 */ - sumd = sum2 - sum1; - sumd = (sumd & 0xffff) + (sumd >> 16); + CALC_SUMD(sum1, sum2, sumd); nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16); } else - nat->nat_ipsumd = nat->nat_sumd; + nat->nat_ipsumd = nat->nat_sumd[0]; in.s_addr = htonl(in.s_addr); nat->nat_next = nat_instances; nat_instances = nat; - natp = &nat_table[0][nat->nat_inip.s_addr % NAT_SIZE]; + hv = NAT_HASH_FN(nat->nat_inip.s_addr, ipf_nattable_sz); + natp = &nat_table[0][hv]; nat->nat_hstart[0] = natp; nat->nat_hnext[0] = *natp; *natp = nat; - natp = &nat_table[1][nat->nat_outip.s_addr % NAT_SIZE]; + hv = NAT_HASH_FN(nat->nat_outip.s_addr, ipf_nattable_sz); + natp = &nat_table[1][hv]; nat->nat_hstart[1] = natp; nat->nat_hnext[1] = *natp; *natp = 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_ifp = fin->fin_ifp; - nat->nat_dir = direction; nat->nat_age = fr_defnatage; + nat->nat_fr = fin->fin_fr; + if (nat->nat_fr != NULL) { + ATOMIC_INC(nat->nat_fr->fr_ref); + } if (direction == NAT_OUTBOUND) { if (flags & IPN_TCPUDP) tcp->th_sport = port; @@ -810,10 +1059,12 @@ flags = IPN_UDP; if (flags & IPN_TCPUDP) { tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2)); - return nat_inlookup(fin->fin_ifp, flags, oip->ip_dst, - tcp->th_dport, oip->ip_src, tcp->th_sport); + 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); } - return nat_inlookup(fin->fin_ifp, 0, oip->ip_dst, 0, oip->ip_src, 0); + return nat_inlookup(fin->fin_ifp, 0, (u_int)oip->ip_p, oip->ip_dst, + oip->ip_src, 0); } @@ -824,7 +1075,7 @@ nat_t *nat_icmpin(ip, fin, nflags) ip_t *ip; fr_info_t *fin; -int *nflags; +u_int *nflags; { u_32_t sum1, sum2, sumd; struct in_addr in; @@ -866,24 +1117,24 @@ CALC_SUMD(sum1, sum2, sumd); if (nat->nat_dir == NAT_OUTBOUND) { - fix_incksum(&oip->ip_sum, sumd); + fix_incksum(&oip->ip_sum, sumd, 0); sumd += (sumd & 0xffff); while (sumd > 0xffff) sumd = (sumd & 0xffff) + (sumd >> 16); - fix_outcksum(&icmp->icmp_cksum, sumd); + fix_outcksum(&icmp->icmp_cksum, sumd, 0); } else { - fix_outcksum(&oip->ip_sum, sumd); + fix_outcksum(&oip->ip_sum, sumd, 0); - sumd += (sumd & 0xffff); - while (sumd > 0xffff) - sumd = (sumd & 0xffff) + (sumd >> 16); - fix_incksum(&icmp->icmp_cksum, sumd); + 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; + 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))); @@ -894,7 +1145,7 @@ sum2 = ntohs(nat->nat_inport); CALC_SUMD(sum1, sum2, sumd); tcp->th_sport = nat->nat_inport; - fix_outcksum(&icmp->icmp_cksum, sumd); + fix_outcksum(&icmp->icmp_cksum, sumd, 0); } } else { if (tcp->th_dport != nat->nat_outport) { @@ -902,11 +1153,10 @@ sum2 = ntohs(nat->nat_outport); CALC_SUMD(sum1, sum2, sumd); tcp->th_dport = nat->nat_outport; - fix_incksum(&icmp->icmp_cksum, sumd); + fix_incksum(&icmp->icmp_cksum, sumd, 0); } } } - nat->nat_age = fr_defnaticmpage; return nat; } @@ -922,29 +1172,35 @@ * we're looking for a table entry, based on the destination address. * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ -#ifdef __STDC__ -nat_t *nat_inlookup(void *ifp, int flags, struct in_addr src, u_short sport, struct in_addr mapdst, u_short mapdport) -#else -nat_t *nat_inlookup(ifp, flags, src, sport, mapdst, mapdport) +nat_t *nat_inlookup(ifp, flags, p, src, mapdst, ports) void *ifp; -register int flags; +register u_int flags, p; struct in_addr src , mapdst; -u_short sport, mapdport; -#endif +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; - nat = nat_table[1][mapdst.s_addr % NAT_SIZE]; - for (; nat; nat = nat->nat_hnext[1]) + hv = NAT_HASH_FN(mapdst.s_addr, 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 && - flags == nat->nat_flags && (!flags || - (nat->nat_oport == sport && - nat->nat_outport == mapdport))) + (((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; } @@ -955,27 +1211,33 @@ * we're looking for a table entry, based on the source address. * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ -#ifdef __STDC__ -nat_t *nat_outlookup(void *ifp, int flags, struct in_addr src, u_short sport, struct in_addr dst, u_short dport) -#else -nat_t *nat_outlookup(ifp, flags, src, sport, dst, dport) +nat_t *nat_outlookup(ifp, flags, p, src, dst, ports) void *ifp; -register int flags; +register u_int flags, p; struct in_addr src , dst; -u_short sport, dport; -#endif +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; - nat = nat_table[0][src.s_addr % NAT_SIZE]; + hv = NAT_HASH_FN(src.s_addr, 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 && - flags == nat->nat_flags && (!flags || - (nat->nat_inport == sport && nat->nat_oport == dport))) + (((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; @@ -983,33 +1245,30 @@ /* - * Lookup a nat entry based on the mapped source ip address/port and - * real destination address/port. We use this lookup when sending a packet - * out, we're looking for a table entry, based on the source address. + * check if an ip address has already been allocated for a given mapping that + * is not doing port based translation. */ -#ifdef __STDC__ -nat_t *nat_lookupmapip(void *ifp, int flags, struct in_addr mapsrc, u_short mapsport, struct in_addr dst, u_short dport) -#else -nat_t *nat_lookupmapip(ifp, flags, mapsrc, mapsport, dst, dport) +nat_t *nat_maplookup(ifp, flags, src, dst) void *ifp; -register int flags; -struct in_addr mapsrc , dst; -u_short mapsport, dport; -#endif +register u_int flags; +struct in_addr src , dst; { register nat_t *nat; + register int oflags; + u_int hv; - flags &= IPN_TCPUDP; + hv = NAT_HASH_FN(src.s_addr, ipf_nattable_sz); + nat = nat_table[0][hv]; + for (; nat; nat = nat->nat_hnext[0]) { + oflags = (flags & IPN_TCPUDP) & nat->nat_ptr->in_flags; + if (oflags != 0) + continue; - nat = nat_table[1][mapsrc.s_addr % NAT_SIZE]; - for (; nat; nat = nat->nat_hnext[0]) if ((!ifp || ifp == nat->nat_ifp) && - nat->nat_oip.s_addr == dst.s_addr && - nat->nat_outip.s_addr == mapsrc.s_addr && - flags == nat->nat_flags && (!flags || - (nat->nat_outport == mapsport && - nat->nat_oport == dport))) + nat->nat_inip.s_addr == src.s_addr && + nat->nat_oip.s_addr == dst.s_addr) return nat; + } return NULL; } @@ -1020,15 +1279,16 @@ 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, np->nl_inip, - np->nl_inport, np->nl_outip, - np->nl_outport))) { + 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; } @@ -1040,20 +1300,25 @@ * Packets going out on the external interface go through this. * Here, the source address requires alteration, if anything. */ -int ip_natout(ip, hlen, fin) +int ip_natout(ip, fin) ip_t *ip; -int hlen; fr_info_t *fin; { - register ipnat_t *np; + register ipnat_t *np = NULL; register u_32_t ipa; tcphdr_t *tcp = NULL; u_short nflags = 0, sport = 0, dport = 0, *csump = NULL; struct ifnet *ifp; + int natadd = 1; frentry_t *fr; + u_int hv, msk; + u_32_t iph; nat_t *nat; - int natadd = 1; + int i; + if (nat_list == NULL) + 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; @@ -1078,23 +1343,42 @@ if ((ip->ip_off & (IP_OFFMASK|IP_MF)) && (nat = ipfr_nat_knownfrag(ip, fin))) natadd = 0; - else if ((nat = nat_outlookup(ifp, nflags, ip->ip_src, sport, - ip->ip_dst, dport))) - ; - else { + 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). */ - for (np = nat_list; np; np = np->in_next) + msk = 0xffffffff; + i = 32; +maskloop: + iph = ipa & htonl(msk); + hv = NAT_HASH_FN(iph, ipf_natrules_sz); + for (np = nat_rules[hv]; np; np = np->in_mnext) + { if ((np->in_ifp == ifp) && np->in_space && - (!np->in_flags || (np->in_flags & nflags)) && + (!(np->in_flags & IPN_RF) || + (np->in_flags & nflags)) && ((ipa & np->in_inmsk) == np->in_inip) && - ((np->in_redir & NAT_MAP) || + ((np->in_redir & (NAT_MAP|NAT_MAPBLK)) || (np->in_pnext == sport))) { - if (*np->in_plabel && !ap_ok(ip, tcp, np)) + if (*np->in_plabel && !appr_ok(ip, tcp, np)) continue; /* * If it's a redirection, then we don't want to @@ -1102,84 +1386,103 @@ * Redirections are only for incoming * connections. */ - if (!(np->in_redir & NAT_MAP)) + if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK))) continue; - if ((nat = nat_new(np, ip, fin, nflags, - NAT_OUTBOUND))) + if ((nat = nat_new(np, ip, fin, (u_int)nflags, + NAT_OUTBOUND))) { + np->in_hits++; #ifdef IPFILTER_LOG - nat_log(nat, (u_short)np->in_redir); -#else - ; + nat_log(nat, (u_int)np->in_redir); #endif - break; + 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) { - if (natadd && fin->fin_fi.fi_fl & FI_FRAG) - ipfr_nat_newfrag(ip, fin, 0, nat); - ip->ip_src = nat->nat_outip; - MUTEX_ENTER(&ipf_rw); - nat->nat_age = fr_defnatage; - nat->nat_bytes += ip->ip_len; - nat->nat_pkts++; - MUTEX_EXIT(&ipf_rw); + 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(&ipf_rw); + nat->nat_age = fr_defnatage; + nat->nat_bytes += ip->ip_len; + nat->nat_pkts++; + MUTEX_EXIT(&ipf_rw); - /* - * Fix up checksums, not by recalculating them, but - * simply computing adjustments. - */ + /* + * 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); - else - fix_incksum(&ip->ip_sum, nat->nat_ipsumd); + 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_off & IP_OFFMASK) && + !(fin->fin_fi.fi_fl & FI_SHORT)) { - if (ip->ip_p == IPPROTO_TCP) { - csump = &tcp->th_sum; - MUTEX_ENTER(&ipf_rw); - fr_tcp_age(&nat->nat_age, - nat->nat_state, ip, fin,1); - /* - * Increase this because we may have - * "keep state" following this too and - * packet storms can occur if this is - * removed too quickly. - */ - if (nat->nat_age == fr_tcpclosed) - nat->nat_age = fr_tcplastack; - MUTEX_EXIT(&ipf_rw); - } else if (ip->ip_p == IPPROTO_UDP) { - udphdr_t *udp = (udphdr_t *)tcp; + if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) { + tcp->th_sport = nat->nat_outport; + fin->fin_data[0] = ntohs(tcp->th_sport); + } - if (udp->uh_sum) - csump = &udp->uh_sum; - } - if (csump) { - if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(csump, - nat->nat_sumd); - else - fix_incksum(csump, - nat->nat_sumd); - } + if (ip->ip_p == IPPROTO_TCP) { + csump = &tcp->th_sum; + MUTEX_ENTER(&ipf_rw); + fr_tcp_age(&nat->nat_age, + nat->nat_tcpstate, ip, fin, 1); + if (nat->nat_age < fr_defnaticmpage) + nat->nat_age = fr_defnaticmpage; +#ifdef LARGE_NAT + else if (nat->nat_age > DEF_NAT_AGE) + nat->nat_age = DEF_NAT_AGE; +#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(&ipf_rw); + } 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); } - (void) ap_check(ip, fin, nat); - ATOMIC_INC(nat_stats.ns_mapped[1]); - RWLOCK_EXIT(&ipf_nat); /* READ */ - return -2; } + if ((np->in_apr != NULL) && (np->in_dport == 0 || + (tcp != NULL && dport == np->in_dport))) + (void) appr_check(ip, fin, nat); + ATOMIC_INC(nat_stats.ns_mapped[1]); + RWLOCK_EXIT(&ipf_nat); /* READ */ + return 1; + } RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ return 0; } @@ -1189,18 +1492,23 @@ * Packets coming in from the external interface go through this. * Here, the destination address requires alteration, if anything. */ -int ip_natin(ip, hlen, fin) +int ip_natin(ip, fin) ip_t *ip; -int hlen; fr_info_t *fin; { - register ipnat_t *np; + 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; - int nflags = 0, natadd = 1; + u_32_t iph; + int i; + + if (nat_list == NULL) + return 0; if (!(ip->ip_off & IP_OFFMASK) && !(fin->fin_fi.fi_fl & FI_SHORT)) { if (ip->ip_p == IPPROTO_TCP) @@ -1215,6 +1523,8 @@ } in = ip->ip_dst; + /* make sure the source address is to be redirected */ + src = ip->ip_src; READ_ENTER(&ipf_nat); @@ -1223,100 +1533,133 @@ else if ((ip->ip_off & IP_OFFMASK) && (nat = ipfr_nat_knownfrag(ip, fin))) natadd = 0; - else if ((nat = nat_inlookup(fin->fin_ifp, nflags, ip->ip_src, sport, - ip->ip_dst, dport))) - ; - else { + 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). */ - for (np = nat_list; np; np = np->in_next) + msk = 0xffffffff; + i = 32; +maskloop: + iph = in.s_addr & htonl(msk); + hv = NAT_HASH_FN(iph, ipf_rdrrules_sz); + for (np = rdr_rules[hv]; np; np = np->in_rnext) if ((np->in_ifp == ifp) && (!np->in_flags || (nflags & np->in_flags)) && ((in.s_addr & np->in_outmsk) == np->in_outip) && + ((src.s_addr & np->in_srcmsk) == np->in_srcip) && (np->in_redir & NAT_REDIRECT) && - (!np->in_pmin || np->in_pmin == dport)) { + (!np->in_pmin || np->in_pmin == dport) && + (!np->in_p || np->in_p == ip->ip_p)) { if ((nat = nat_new(np, ip, fin, nflags, - NAT_INBOUND))) + NAT_INBOUND))) { + np->in_hits++; #ifdef IPFILTER_LOG - nat_log(nat, (u_short)np->in_redir); -#else - ; + nat_log(nat, (u_int)np->in_redir); #endif - break; + 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) { - if (natadd && fin->fin_fi.fi_fl & FI_FRAG) - ipfr_nat_newfrag(ip, fin, 0, nat); - (void) ap_check(ip, fin, nat); - - MUTEX_ENTER(&ipf_rw); - if (nflags != IPN_ICMPERR) - nat->nat_age = fr_defnatage; - - nat->nat_bytes += ip->ip_len; - nat->nat_pkts++; - MUTEX_EXIT(&ipf_rw); - ip->ip_dst = nat->nat_inip; - fin->fin_fi.fi_dst = nat->nat_inip; + 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))) + (void) appr_check(ip, fin, nat); - /* - * Fix up checksums, not by recalculating them, but - * simply computing adjustments. - */ + MUTEX_ENTER(&ipf_rw); + if (nflags != IPN_ICMPERR) + nat->nat_age = fr_defnatage; + + nat->nat_bytes += ip->ip_len; + nat->nat_pkts++; + MUTEX_EXIT(&ipf_rw); + ip->ip_dst = nat->nat_inip; + fin->fin_fi.fi_dst = nat->nat_inip; + + /* + * 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); - else - fix_outcksum(&ip->ip_sum, nat->nat_ipsumd); + 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 (!(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(&ipf_rw); - fr_tcp_age(&nat->nat_age, - nat->nat_state, ip, fin,0); - /* - * Increase this because we may have - * "keep state" following this too and - * packet storms can occur if this is - * removed too quickly. - */ - if (nat->nat_age == fr_tcpclosed) - nat->nat_age = fr_tcplastack; - MUTEX_EXIT(&ipf_rw); - } else if (ip->ip_p == IPPROTO_UDP) { - udphdr_t *udp = (udphdr_t *)tcp; + if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) { + tcp->th_dport = nat->nat_inport; + fin->fin_data[1] = ntohs(tcp->th_dport); + } - if (udp->uh_sum) - csump = &udp->uh_sum; - } - if (csump) { - if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(csump, - nat->nat_sumd); - else - fix_outcksum(csump, - nat->nat_sumd); - } + if (ip->ip_p == IPPROTO_TCP) { + csump = &tcp->th_sum; + MUTEX_ENTER(&ipf_rw); + fr_tcp_age(&nat->nat_age, + nat->nat_tcpstate, ip, fin, 0); + if (nat->nat_age < fr_defnaticmpage) + nat->nat_age = fr_defnaticmpage; +#ifdef LARGE_NAT + else if (nat->nat_age > DEF_NAT_AGE) + nat->nat_age = DEF_NAT_AGE; +#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(&ipf_rw); + } 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_INC(nat_stats.ns_mapped[0]); - RWLOCK_EXIT(&ipf_nat); /* READ */ - return -2; } + ATOMIC_INC(nat_stats.ns_mapped[0]); + RWLOCK_EXIT(&ipf_nat); /* READ */ + return 1; + } RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ return 0; } @@ -1331,6 +1674,23 @@ (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; + } } @@ -1367,69 +1727,69 @@ /* */ -#ifdef __STDC__ -void ip_natsync(void *ifp) -#else void ip_natsync(ifp) void *ifp; -#endif { + 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 == nat->nat_ifp) && (np = nat->nat_ptr)) - if ((np->in_outmsk == 0xffffffff) && !np->in_nip) { - /* - * Change the map-to address to be the same - * as the new one. - */ - sum1 = nat->nat_outip.s_addr; - if (nat_ifpaddr(nat, ifp, &in) == -1) - nat->nat_outip.s_addr = htonl(in.s_addr); - sum2 = nat->nat_outip.s_addr; + 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(ifp2, &in) != -1) + nat->nat_outip = in; + sum2 = nat->nat_outip.s_addr; - /* - * Readjust the checksum adjustment to take - * into account the new IP#. - * - * Do it twice - */ - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - sum2 = (sum2 & 0xffff) + (sum2 >> 16); + 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]; + } - /* Do it twice */ - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - - /* Because ~1 == -2, We really need ~1 == -1 */ - if (sum1 > sum2) - sum2--; - sumd = sum2 - sum1; - sumd = (sumd & 0xffff) + (sumd >> 16); - sumd += nat->nat_sumd; - nat->nat_sumd = (sumd & 0xffff) + (sumd >> 16); - } + for (n = nat_list; (n != NULL); n = n->in_next) + if (n->in_ifp == ifp) { + n->in_ifp = (void *)GETUNIT(n->in_ifname); + if (!n->in_ifp) + n->in_ifp = (void *)-1; + } RWLOCK_EXIT(&ipf_nat); SPL_X(s); } #ifdef IPFILTER_LOG -# ifdef __STDC__ -void nat_log(struct nat *nat, u_short type) -# else void nat_log(nat, type) struct nat *nat; -u_short type; -# endif +u_int type; { struct ipnat *np; struct natlog natl; @@ -1445,19 +1805,22 @@ 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; - if (nat->nat_ptr) { +#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, 0, items, sizes, types, 1); + (void) ipllog(IPL_LOGNAT, NULL, items, sizes, types, 1); } #endif Index: sys/netinet/ip_nat.h =================================================================== RCS file: /cvs/src/sys/netinet/ip_nat.h,v retrieving revision 1.12 retrieving revision 1.17 diff -u -r1.12 -r1.17 --- sys/netinet/ip_nat.h 1999/08/08 00:43:00 1.12 +++ sys/netinet/ip_nat.h 2000/04/05 05:35:27 1.17 @@ -1,4 +1,5 @@ -/* $OpenBSD: ip_nat.h,v 1.12 1999/08/08 00:43:00 niklas Exp $ */ +/* $OpenBSD: ip_nat.h,v 1.17 2000/04/05 05:35:27 kjell Exp $ */ + /* * Copyright (C) 1995-1998 by Darren Reed. * @@ -7,7 +8,7 @@ * to the original author and the contributors. * * @(#)ip_nat.h 1.5 2/4/96 - * $Id: ip_nat.h,v 1.12 1999/08/08 00:43:00 niklas Exp $ + * $IPFilter: ip_nat.h,v 2.1.2.4 2000/03/15 13:57:03 darrenr Exp $ */ #ifndef __IP_NAT_H__ @@ -37,18 +38,41 @@ #define SIOCCNATL _IOWR(r, 87, int) #endif -#define NAT_SIZE 367 +#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 NAT_TABLE_SZ 127 +#ifdef LARGE_NAT +#undef NAT_SIZE +#undef RDR_SIZE +#undef NAT_TABLE_SZ +#define NAT_SIZE 2047 +#define RDR_SIZE 2047 +#define NAT_TABLE_SZ 16383 +#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; + u_32_t nat_sumd[2]; u_32_t nat_ipsumd; void *nat_data; - void *nat_aps; /* proxy session */ + 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 */ @@ -58,7 +82,8 @@ u_short nat_inport; u_short nat_outport; u_short nat_use; - u_char nat_state[2]; + u_char nat_tcpstate[2]; + u_char nat_p; /* protocol for NAT */ struct ipnat *nat_ptr; /* pointer back to the rule */ struct nat *nat_next; struct nat *nat_hnext[2]; @@ -69,16 +94,22 @@ typedef struct ipnat { struct ipnat *in_next; - void *in_ifp; /* interface pointer */ - void *in_apr; /* proxy structure ptr */ - u_int in_space; + struct ipnat *in_rnext; + struct ipnat *in_mnext; + 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_flags; - u_short in_port[2]; + 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]; 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 */ @@ -93,6 +124,8 @@ #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 NAT_OUTBOUND 0 #define NAT_INBOUND 1 @@ -100,8 +133,12 @@ #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)) +#define IPN_CMPSIZ (sizeof(ipnat_t) - offsetof(ipnat_t, in_flags)) typedef struct natlookup { struct in_addr nl_inip; @@ -124,14 +161,22 @@ 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 0x00 #define IPN_TCP 0x01 #define IPN_UDP 0x02 -#define IPN_TCPUDP 0x03 +#define IPN_TCPUDP (IPN_TCP|IPN_UDP) #define IPN_DELETE 0x04 #define IPN_ICMPERR 0x08 +#define IPN_RF (IPN_TCPUDP|IPN_DELETE|IPN_ICMPERR) +#define IPN_AUTOPORTMAP 0x10 +#define IPN_RANGE 0x20 +#define IPN_USERFLAGS (IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_RANGE) typedef struct natlog { @@ -145,6 +190,7 @@ int nl_rule; U_QUAD_T nl_pkts; U_QUAD_T nl_bytes; + u_char nl_p; } natlog_t; @@ -152,33 +198,56 @@ #define NL_NEWRDR NAT_REDIRECT #define NL_EXPIRE 0xffff +#define NAT_HASH_FN(k,m) (((k) + ((k) >> 12)) % (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 void ip_natsync __P((void *)); extern u_long fr_defnatage; extern u_long fr_defnaticmpage; -extern nat_t *nat_table[2][NAT_SIZE]; +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__) extern int nat_ioctl __P((caddr_t, u_long, int)); #else extern int nat_ioctl __P((caddr_t, int, int)); #endif extern void nat_ifdetach __P((struct ifnet *)); -extern nat_t *nat_new __P((ipnat_t *, ip_t *, fr_info_t *, u_short, int)); -extern nat_t *nat_outlookup __P((void *, int, struct in_addr, u_short, - struct in_addr, u_short)); -extern nat_t *nat_inlookup __P((void *, int, struct in_addr, u_short, - struct in_addr, u_short)); +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_lookupmapip __P((void *, int, struct in_addr, u_short, - struct in_addr, u_short)); extern nat_t *nat_icmpinlookup __P((ip_t *, fr_info_t *)); -extern nat_t *nat_icmpin __P((ip_t *, fr_info_t *, int *)); +extern nat_t *nat_icmpin __P((ip_t *, fr_info_t *, u_int *)); -extern int ip_natout __P((ip_t *, int, fr_info_t *)); -extern int ip_natin __P((ip_t *, int, fr_info_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_short)); -extern void fix_incksum __P((u_short *, u_32_t)); -extern void fix_outcksum __P((u_short *, u_32_t)); +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__ */ Index: sys/netinet/ip_proxy.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_proxy.c,v retrieving revision 1.4 retrieving revision 1.9 diff -u -r1.4 -r1.9 --- sys/netinet/ip_proxy.c 1999/02/05 05:58:53 1.4 +++ sys/netinet/ip_proxy.c 2000/04/05 05:35:27 1.9 @@ -1,4 +1,5 @@ -/* $OpenBSD: ip_proxy.c,v 1.4 1999/02/05 05:58:53 deraadt Exp $ */ +/* $OpenBSD: ip_proxy.c,v 1.9 2000/04/05 05:35:27 kjell Exp $ */ + /* * Copyright (C) 1997-1998 by Darren Reed. * @@ -7,7 +8,7 @@ * to the original author and the contributors. */ #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 1.4 1999/02/05 05:58:53 deraadt Exp $"; +static const char rcsid[] = "@(#)$IPFilter: ip_proxy.c,v 2.2.2.4 2000/03/15 13:57:53 darrenr Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) @@ -19,7 +20,9 @@ #include #include #include -#include +#if !defined(__FreeBSD_version) +# include +#endif #include #include #if !defined(_KERNEL) && !defined(KERNEL) @@ -44,7 +47,9 @@ # endif #else # include -# include +# ifdef _KERNEL +# include +# endif # include # include #endif @@ -65,42 +70,54 @@ #include #include #include -#if defined(__OpenBSD__) -# include -#else -# include -#endif +#include #include #include #include #include #include +#if (__FreeBSD_version >= 300000) +# include +#endif + #ifndef MIN #define MIN(a,b) (((a)<(b))?(a):(b)) #endif -static ap_session_t *ap_new_session __P((aproxy_t *, ip_t *, - fr_info_t *, nat_t *)); +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 +#include +#include #endif ap_session_t *ap_sess_tab[AP_SESS_SIZE]; ap_session_t *ap_sess_list = NULL; aproxy_t ap_proxies[] = { #ifdef IPF_FTP_PROXY - { "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, ippr_ftp_in, ippr_ftp_out }, + { "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, NULL, + ippr_ftp_new, ippr_ftp_in, ippr_ftp_out }, +#endif +#ifdef IPF_RCMD_PROXY + { "rcmd", (char)IPPROTO_TCP, 0, 0, ippr_rcmd_init, NULL, + ippr_rcmd_new, NULL, ippr_rcmd_out }, +#endif +#ifdef IPF_RAUDIO_PROXY + { "raudio", (char)IPPROTO_TCP, 0, 0, ippr_raudio_init, NULL, + ippr_raudio_new, ippr_raudio_in, ippr_raudio_out }, #endif { "", '\0', 0, 0, NULL, NULL } }; -int ap_ok(ip, tcp, nat) +int appr_ok(ip, tcp, nat) ip_t *ip; tcphdr_t *tcp; ipnat_t *nat; @@ -108,7 +125,7 @@ aproxy_t *apr = nat->in_apr; u_short dport = nat->in_dport; - if (!apr || (apr && (apr->apr_flags & APR_DELETE)) || + if (!apr || (apr->apr_flags & APR_DELETE) || (ip->ip_p != apr->apr_p)) return 0; if ((tcp && (tcp->th_dport != dport)) || (!tcp && dport)) @@ -122,60 +139,33 @@ * relevant details. call the init function once complete, prior to * returning. */ -static ap_session_t *ap_new_session(apr, ip, fin, nat) +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; - tcphdr_t *tcp; - u_short dport; - u_int hv; - if (!apr || (apr && (apr->apr_flags & APR_DELETE)) || - (ip->ip_p != apr->apr_p)) + if (!apr || (apr->apr_flags & APR_DELETE) || (ip->ip_p != apr->apr_p)) return NULL; - - if (!(fin->fin_fi.fi_fl & FI_TCPUDP)) - tcp = NULL; - else - tcp = (tcphdr_t *)fin->fin_dp; - dport = nat->nat_ptr->in_dport; - if ((tcp && (tcp->th_dport != dport)) || (!tcp && dport)) - return NULL; - - hv = ip->ip_src.s_addr ^ ip->ip_dst.s_addr; - hv *= 651733; - if (tcp) { - hv ^= (tcp->th_sport + tcp->th_dport); - hv *= 5; - } - hv %= AP_SESS_SIZE; - - KMALLOC(aps, ap_session_t *, sizeof(*aps)); + KMALLOC(aps, ap_session_t *); if (!aps) return NULL; bzero((char *)aps, sizeof(*aps)); - aps->aps_apr = apr; - aps->aps_src = ip->ip_src; - aps->aps_dst = ip->ip_dst; aps->aps_p = ip->ip_p; - if (tcp) { - aps->aps_sport = tcp->th_sport; - aps->aps_dport = tcp->th_dport; - } aps->aps_data = NULL; + aps->aps_apr = apr; aps->aps_psiz = 0; - aps->aps_hnext = ap_sess_tab[hv]; + 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; - aps->aps_nat = nat; - aps->aps_hv = hv; - nat->nat_aps = aps; - ap_sess_tab[hv] = aps; - (void) (*apr->apr_init)(fin, ip, aps, nat); return aps; } @@ -184,7 +174,7 @@ * check to see if a packet should be passed through an active proxy routine * if one has been setup for it. */ -int ap_check(ip, fin, nat) +int appr_check(ip, fin, nat) ip_t *ip; fr_info_t *fin; nat_t *nat; @@ -195,8 +185,11 @@ u_32_t sum; int err; - if ((aps = nat->nat_aps) || - (aps = ap_new_session(nat->nat_ptr->in_apr, ip, fin, nat))) { + 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; /* @@ -204,12 +197,11 @@ * don't do anything with this packet. */ #if SOLARIS && defined(_KERNEL) - sum = fr_tcpsum(fin->fin_qfm, ip, tcp, ip->ip_len); + sum = fr_tcpsum(fin->fin_qfm, ip, tcp); #else - sum = fr_tcpsum(*(mb_t **)fin->fin_mp, - ip, tcp, ip->ip_len); + sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, tcp); #endif - if (tcp->th_sum != sum) { + if (sum != tcp->th_sum) { frstats[fin->fin_out].fr_tcpbad++; return -1; } @@ -217,22 +209,20 @@ apr = aps->aps_apr; err = 0; - if (fin->fin_out) { - if (apr->apr_outpkt) + if (fin->fin_out != 0) { + if (apr->apr_outpkt != NULL) err = (*apr->apr_outpkt)(fin, ip, aps, nat); } else { - if (apr->apr_inpkt) + if (apr->apr_inpkt != NULL) err = (*apr->apr_inpkt)(fin, ip, aps, nat); } if (tcp != NULL) { - err = ap_fixseqack(fin, ip, aps, err); + err = appr_fixseqack(fin, ip, aps, err); #if SOLARIS && defined(_KERNEL) - tcp->th_sum = fr_tcpsum(fin->fin_qfm, ip, tcp, - ip->ip_len); + tcp->th_sum = fr_tcpsum(fin->fin_qfm, ip, tcp); #else - tcp->th_sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, - tcp, ip->ip_len); + tcp->th_sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, tcp); #endif } aps->aps_bytes += ip->ip_len; @@ -243,8 +233,8 @@ } -aproxy_t *ap_match(pr, name) -u_char pr; +aproxy_t *appr_match(pr, name) +u_int pr; char *name; { aproxy_t *ap; @@ -259,7 +249,7 @@ } -void ap_free(ap) +void appr_free(ap) aproxy_t *ap; { ap->apr_ref--; @@ -270,19 +260,10 @@ ap_session_t *aps; { ap_session_t *a, **ap; - u_int hv; if (!aps) return; - hv = aps->aps_hv; - - for (ap = ap_sess_tab + hv; (a = *ap); ap = &a->aps_hnext) - if (a == aps) { - *ap = a->aps_hnext; - break; - } - for (ap = &ap_sess_list; (a = *ap); ap = &a->aps_next) if (a == aps) { *ap = a->aps_next; @@ -290,14 +271,14 @@ } if (a) { - if (aps->aps_data && aps->aps_psiz) + if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) KFREES(aps->aps_data, aps->aps_psiz); KFREE(aps); } } -int ap_fixseqack(fin, ip, aps, inc) +static int appr_fixseqack(fin, ip, aps, inc) fr_info_t *fin; ip_t *ip; ap_session_t *aps; @@ -393,4 +374,28 @@ } } 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)(); } Index: sys/netinet/ip_proxy.h =================================================================== RCS file: /cvs/src/sys/netinet/ip_proxy.h,v retrieving revision 1.3 retrieving revision 1.8 diff -u -r1.3 -r1.8 --- sys/netinet/ip_proxy.h 1999/02/05 05:58:54 1.3 +++ sys/netinet/ip_proxy.h 2000/04/05 05:35:27 1.8 @@ -1,4 +1,5 @@ -/* $OpenBSD: ip_proxy.h,v 1.3 1999/02/05 05:58:54 deraadt Exp $ */ +/* $OpenBSD: ip_proxy.h,v 1.8 2000/04/05 05:35:27 kjell Exp $ */ + /* * Copyright (C) 1997-1998 by Darren Reed. * @@ -6,7 +7,7 @@ * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * $Id: ip_proxy.h,v 1.3 1999/02/05 05:58:54 deraadt Exp $ + * $IPFilter: ip_proxy.h,v 2.1.2.3 2000/03/15 13:58:15 darrenr Exp $ */ #ifndef __IP_PROXY_H__ @@ -42,19 +43,16 @@ typedef struct ap_session { struct aproxy *aps_apr; - struct in_addr aps_src; /* source IP# */ - struct in_addr aps_dst; /* destination IP# */ - u_char aps_p; /* protocol */ union { struct ap_tcp apu_tcp; struct ap_udp apu_udp; } aps_un; - u_int aps_hv; 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; @@ -75,8 +73,10 @@ u_char apr_p; /* protocol */ int apr_ref; /* +1 per rule referencing it */ int apr_flags; - int (* apr_init) __P((fr_info_t *, ip_t *, - ap_session_t *, struct nat *)); + 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 *, @@ -86,24 +86,55 @@ #define APR_DELETE 1 +/* + * For the ftp proxy. + */ +typedef struct ftpinfo { + u_int ftp_passok; +} 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 ap_ok __P((ip_t *, tcphdr_t *, struct ipnat *)); -extern void ap_free __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 ap_check __P((ip_t *, fr_info_t *, struct nat *)); -extern aproxy_t *ap_match __P((u_char, char *)); -extern int ap_fixseqack __P((fr_info_t *, ip_t *, ap_session_t *, int inc)); - +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__ */ - - - - - - - - Index: sys/netinet/ip_raudio_pxy.c =================================================================== RCS file: ip_raudio_pxy.c diff -N ip_raudio_pxy.c --- /dev/null Wed May 24 17:02:20 2000 +++ sys/netinet/ip_raudio_pxy.c Wed May 24 17:46:35 2000 @@ -0,0 +1,303 @@ +/* $OpenBSD: ip_raudio_pxy.c,v 1.7 2000/04/05 05:35:27 kjell 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; + u_short sp, dp; + int off, dlen; + 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)); + fi.fin_dp = (char *)tcp2; + fi.fin_fr = &raudiofr; + tcp2->th_win = htons(8192); + + 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_src = swa; + ip->ip_dst = swb; + return 0; +} Index: sys/netinet/ip_rcmd_pxy.c =================================================================== RCS file: ip_rcmd_pxy.c diff -N ip_rcmd_pxy.c --- /dev/null Wed May 24 17:02:20 2000 +++ sys/netinet/ip_rcmd_pxy.c Wed May 24 17:46:35 2000 @@ -0,0 +1,158 @@ +/* $OpenBSD: ip_rcmd_pxy.c,v 1.4 2000/03/13 23:40:18 kjell 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) { + 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 */ + 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_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); +} Index: sys/netinet/ip_state.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_state.c,v retrieving revision 1.13 retrieving revision 1.22 diff -u -r1.13 -r1.22 --- sys/netinet/ip_state.c 1999/02/05 05:58:54 1.13 +++ sys/netinet/ip_state.c 2000/05/24 21:59:11 1.22 @@ -1,4 +1,5 @@ -/* $OpenBSD: ip_state.c,v 1.13 1999/02/05 05:58:54 deraadt Exp $ */ +/* $OpenBSD: ip_state.c,v 1.22 2000/05/24 21:59:11 kjell Exp $ */ + /* * Copyright (C) 1995-1998 by Darren Reed. * @@ -8,13 +9,17 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_state.c,v 1.13 1999/02/05 05:58:54 deraadt Exp $"; +static const char rcsid[] = "@(#)$IPFilter: ip_state.c,v 2.3.2.25 2000/05/22 06:57:53 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(KERNEL) && !defined(__KERNEL__) # include # include @@ -25,16 +30,19 @@ # include # endif #endif -#if defined(KERNEL) && (__FreeBSD_version >= 220000) +#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 +# include #endif #include #if defined(_KERNEL) && !defined(linux) @@ -47,14 +55,16 @@ #else # include # include -# include +# ifdef _KERNEL +# include +# endif # include # include #endif #include #ifdef sun -#include +# include #endif #include #include @@ -67,48 +77,69 @@ #endif #include #include -#if defined(__OpenBSD__) -# include -#else -# include -#endif +#include #include #include #include #include #include #include +#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)) +# define MIN(a,b) (((a)<(b))?(a):(b)) #endif #define TCP_CLOSE (TH_FIN|TH_RST) -ipstate_t *ips_table[IPSTATE_SIZE]; +ipstate_t **ips_table = NULL; int ips_num = 0; ips_stat_t ips_stats; #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) -extern KRWLOCK_T ipf_state; +extern KRWLOCK_T ipf_state, ipf_mutex; extern kmutex_t ipf_rw; #endif static int fr_matchsrcdst __P((ipstate_t *, struct in_addr, struct in_addr, - fr_info_t *, void *, u_short, u_short)); + fr_info_t *, tcphdr_t *)); +static frentry_t *fr_checkicmpmatchingstate __P((ip_t *, fr_info_t *)); static int fr_state_flush __P((int)); static ips_stat_t *fr_statetstats __P((void)); +static void fr_delstate __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 = 60, - fr_tcplastack = 20, - fr_tcptimeout = 120, + fr_tcpclosewait = 2 * TCP_MSL, + fr_tcplastack = 2 * TCP_MSL, + fr_tcptimeout = 2 * TCP_MSL, fr_tcpclosed = 1, - fr_udptimeout = 120, + fr_udptimeout = 240, fr_icmptimeout = 120; +int fr_statemax = IPSTATE_MAX, + fr_statesize = IPSTATE_SIZE; +int fr_state_doflush = 0; +int fr_stateinit() +{ + 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; + return 0; +} + + static ips_stat_t *fr_statetstats() { ips_stats.iss_active = ips_num; @@ -135,7 +166,7 @@ SPL_NET(s); WRITE_ENTER(&ipf_state); - for (i = 0; i < IPSTATE_SIZE; i++) + for (i = fr_statesize - 1; i >= 0; i--) for (isp = &ips_table[i]; (is = *isp); ) { delete = 0; @@ -145,11 +176,10 @@ delete = 1; break; case 1 : - if ((is->is_p == IPPROTO_TCP) && - (((is->is_state[0] <= TCPS_ESTABLISHED) && - (is->is_state[1] > TCPS_ESTABLISHED)) || - ((is->is_state[1] <= TCPS_ESTABLISHED) && - (is->is_state[0] > TCPS_ESTABLISHED)))) + if (is->is_p != IPPROTO_TCP) + break; + if ((is->is_state[0] != TCPS_ESTABLISHED) || + (is->is_state[1] != TCPS_ESTABLISHED)) delete = 1; break; } @@ -160,10 +190,12 @@ ips_stats.iss_fin++; else ips_stats.iss_expire++; + if (ips_table[i] == NULL) + ips_stats.iss_inuse--; #ifdef IPFILTER_LOG ipstate_log(is, ISL_FLUSH); #endif - KFREE(is); + fr_delstate(is); ips_num--; removed++; } else @@ -196,6 +228,18 @@ } 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 SIOCGIPST : IWCOPY((caddr_t)fr_statetstats(), data, sizeof(ips_stat_t)); break; @@ -206,7 +250,8 @@ #endif break; default : - return EINVAL; + error = EINVAL; + break; } return error; } @@ -215,21 +260,25 @@ /* * Create a new ipstate structure and hang it off the hash table. */ -int fr_addstate(ip, fin, pass) +ipstate_t *fr_addstate(ip, fin, flags) ip_t *ip; fr_info_t *fin; -u_int pass; +u_int flags; { - ipstate_t ips; - register ipstate_t *is = &ips; + register ipstate_t *is; register u_int hv; + ipstate_t ips; + u_int pass; if ((ip->ip_off & IP_OFFMASK) || (fin->fin_fi.fi_fl & FI_SHORT)) - return -1; - if (ips_num == IPSTATE_MAX) { + return NULL; + if (ips_num == fr_statemax) { ips_stats.iss_max++; - return -1; + fr_state_doflush = 1; + return NULL; } + is = &ips; + bzero((char *)is, sizeof(*is)); ips.is_age = 1; ips.is_state[0] = 0; ips.is_state[1] = 0; @@ -259,7 +308,7 @@ is->is_icmp.ics_type = ic->icmp_type + 1; break; default : - return -1; + return NULL; } ATOMIC_INC(ips_stats.iss_icmp); is->is_age = fr_icmptimeout; @@ -269,23 +318,34 @@ { register tcphdr_t *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. */ - hv += (is->is_dport = tcp->th_dport); - hv += (is->is_sport = tcp->th_sport); - is->is_seq = ntohl(tcp->th_seq); - is->is_ack = ntohl(tcp->th_ack); - is->is_swin = ntohs(tcp->th_win); - is->is_dwin = is->is_swin; /* start them the same */ + 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; + } + if (tcp->th_seq != 0) { + 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 + 1; + } + is->is_dend = 0; + 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. */ - if ((tcp->th_flags & (TH_SYN|TH_ACK)) == TH_SYN) - is->is_ack = 0; /* Trumpet WinSock 'ism */ MUTEX_ENTER(&ipf_rw); ips_stats.iss_tcp++; fr_tcp_age(&is->is_age, is->is_state, ip, fin, @@ -297,23 +357,33 @@ { register tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; - hv += (is->is_dport = tcp->th_dport); - hv += (is->is_sport = tcp->th_sport); + 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_INC(ips_stats.iss_udp); is->is_age = fr_udptimeout; break; } default : - return -1; + return NULL; } - KMALLOC(is, ipstate_t *, sizeof(*is)); + KMALLOC(is, ipstate_t *); if (is == NULL) { ATOMIC_INC(ips_stats.iss_nomem); - return -1; + return NULL; } bcopy((char *)&ips, (char *)is, sizeof(*is)); - hv %= IPSTATE_SIZE; + hv %= fr_statesize; + is->is_rule = fin->fin_fr; + if (is->is_rule != NULL) { + ATOMIC_INC(is->is_rule->fr_ref); + pass = is->is_rule->fr_flags; + } else + pass = fr_flags; WRITE_ENTER(&ipf_state); is->is_pass = pass; @@ -330,14 +400,20 @@ is->is_secmsk = 0xffff; is->is_auth = fin->fin_fi.fi_auth; is->is_authmsk = 0xffff; - is->is_flags = fin->fin_fi.fi_fl; - is->is_flags |= FI_OPTIONS|FI_TCPUDP|FI_SHORT; - is->is_flags |= fin->fin_fi.fi_fl << 4; + is->is_flags = fin->fin_fi.fi_fl & FI_CMP; + is->is_flags |= FI_CMP << 4; + is->is_flags |= flags & (FI_W_DPORT|FI_W_SPORT); +#ifdef _KERNEL + strncpy(is->is_ifname[fin->fin_out], IFNAME(fin->fin_ifp), IFNAMSIZ); +#endif + is->is_ifname[1 - fin->fin_out][0] = '\0'; /* * add into table. */ is->is_next = ips_table[hv]; ips_table[hv] = is; + if (is->is_next == NULL) + ips_stats.iss_inuse++; if (fin->fin_out) { is->is_ifpin = NULL; is->is_ifpout = fin->fin_ifp; @@ -352,12 +428,14 @@ ipstate_log(is, ISL_NEW); #endif RWLOCK_EXIT(&ipf_state); + fin->fin_rev = (is->is_dst.s_addr != ip->ip_dst.s_addr); if (fin->fin_fi.fi_fl & FI_FRAG) ipfr_newfrag(ip, fin, pass ^ FR_KEEPSTATE); - return 0; + 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 @@ -369,65 +447,88 @@ ip_t *ip; tcphdr_t *tcp; { - register int seqskew, ackskew; - register tcp_seq seq, ack; - u_short win; + 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 = (ip->ip_src.s_addr == is->is_src.s_addr); + fdata = &is->is_tcp.ts_data[!source]; + tdata = &is->is_tcp.ts_data[source]; seq = ntohl(tcp->th_seq); ack = ntohl(tcp->th_ack); - source = (ip->ip_src.s_addr == is->is_src.s_addr); + win = ntohs(tcp->th_win); + end = 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); - if (!(tcp->th_flags & TH_ACK)) /* Pretend an ack was sent */ - ack = source ? is->is_ack : is->is_seq; + 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 (source) { - if (!is->is_seq) - /* - * Must be an outgoing SYN-ACK in reply to a SYN. - */ - is->is_seq = seq; - seqskew = seq - is->is_seq; - ackskew = (ack - 1) - is->is_ack; - } else { - if (!is->is_ack) - /* - * Must be a SYN-ACK in reply to a SYN. - */ - is->is_ack = seq; - ackskew = seq - is->is_ack; - seqskew = (ack - 1) - is->is_seq; + if (!(tcp->th_flags & TH_ACK)) { /* Pretend an ack was sent */ + ack = tdata->td_end; + win = 1; + if ((tcp->th_flags == TH_SYN) && (tdata->td_maxwin == 0)) + tdata->td_maxwin = 1; + } 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; } - /* - * Make skew values absolute - */ - if (seqskew < 0) - seqskew = -seqskew; - if (ackskew < 0) - ackskew = -ackskew; + if (seq == end) + seq = end = fdata->td_end; - /* - * If the difference in sequence and ack numbers is within the - * window size of the connection, store these values and match - * the packet. - */ - win = ntohs(tcp->th_win); - if ((seqskew <= is->is_dwin) && (ackskew <= is->is_swin)) { - if (source) { - is->is_seq = seq; - is->is_ack = ack; - if (win != 0) - is->is_swin = win; - } else { - is->is_seq = ack; - is->is_ack = seq; - if (win != 0) - is->is_dwin = win; + 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_INC(ips_stats.iss_hits); is->is_pkts++; is->is_bytes += ip->ip_len; @@ -437,97 +538,320 @@ MUTEX_ENTER(&ipf_rw); fr_tcp_age(&is->is_age, is->is_state, ip, fin, source); MUTEX_EXIT(&ipf_rw); - return 1; + ret = 1; } - return 0; + return ret; } -static int fr_matchsrcdst(is, src, dst, fin, tcp, sp, dp) +static int fr_matchsrcdst(is, src, dst, fin, tcp) ipstate_t *is; struct in_addr src, dst; fr_info_t *fin; -void *tcp; -u_short sp, dp; +tcphdr_t *tcp; { - int ret = 0, rev, out; + int ret = 0, rev, out, flags; + u_short sp, dp; void *ifp; - rev = (is->is_dst.s_addr != dst.s_addr); + rev = fin->fin_rev = (is->is_dst.s_addr != dst.s_addr); ifp = fin->fin_ifp; out = fin->fin_out; - if (!rev) { - if (out) { - if (!is->is_ifpout) - is->is_ifpout = ifp; + if (tcp != NULL) { + flags = is->is_flags; + sp = tcp->th_sport; + dp = tcp->th_dport; + } else { + flags = 0; + sp = 0; + dp = 0; + } + + if (rev == 0) { + if (!out) { + if (is->is_ifpin == NULL || is->is_ifpin == ifp) + ret = 1; } else { - if (!is->is_ifpin) - is->is_ifpin = ifp; + if (is->is_ifpout == NULL || is->is_ifpout == ifp) + ret = 1; } } else { if (out) { - if (!is->is_ifpin) - is->is_ifpin = ifp; + if (is->is_ifpin == NULL || is->is_ifpin == ifp) + ret = 1; } else { - if (!is->is_ifpout) - is->is_ifpout = ifp; + if (is->is_ifpout == NULL || is->is_ifpout == ifp) + ret = 1; } } + if (ret == 0) + return 0; + ret = 0; - if (!rev) { - if (((out && is->is_ifpout == ifp) || - (!out && is->is_ifpin == ifp)) && - (is->is_dst.s_addr == dst.s_addr) && + if (rev == 0) { + if ((is->is_dst.s_addr == dst.s_addr) && (is->is_src.s_addr == src.s_addr) && - (!tcp || ((sp == is->is_sport) && - (dp == is->is_dport)))) { + (!tcp || ((sp == is->is_sport || flags & FI_W_SPORT) && + (dp == is->is_dport || flags & FI_W_DPORT)))) { ret = 1; } } else { - if (((out && is->is_ifpin == ifp) || - (!out && is->is_ifpout == ifp)) && - (is->is_dst.s_addr == src.s_addr) && + if ((is->is_dst.s_addr == src.s_addr) && (is->is_src.s_addr == dst.s_addr) && - (!tcp || ((sp == is->is_dport) && - (dp == is->is_sport)))) { + (!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 (ret) { - if (((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) || - ((fin->fin_fi.fi_fl & (is->is_flags & 0xf)) != - (is->is_flags >> 4))) - ret = 0; + 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); } - return ret; + + if (!rev) { + if (out) { + if (!is->is_ifpout) + is->is_ifpout = ifp; + } else { + if (!is->is_ifpin) + is->is_ifpin = ifp; + } + } else { + if (out) { + if (!is->is_ifpin) + is->is_ifpin = ifp; + } else { + if (!is->is_ifpout) + is->is_ifpout = ifp; + } + } +#ifdef _KERNEL + if (ret >= 0) { + strncpy(is->is_ifname[out], IFNAME(fin->fin_ifp), + sizeof(is->is_ifname[1])); + } +#endif + return 1; } +frentry_t *fr_checkicmpmatchingstate(ip, fin) +ip_t *ip; +fr_info_t *fin; +{ + register struct in_addr dst, src; + register ipstate_t *is, **isp; + register u_short sport, dport; + register u_char pr; + 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_hl != 5) || (ip->ip_len < ICMPERR_MINPKTLEN)) + return NULL; + ic = (struct icmp *)((char *)ip + fin->fin_hlen); + 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 *)fin->fin_dp + ICMPERR_ICMPHLEN); + if (ip->ip_len < 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); + hv += (src.s_addr = oip->ip_src.s_addr); + hv += (dst.s_addr = oip->ip_dst.s_addr); + if (icmp->icmp_type == ICMP_ECHO) { + 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_next) + if ((is->is_p == pr) && + 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 == ICMP_ECHOREPLY) && + (icmp->icmp_id == is->is_icmp.ics_id) && + (icmp->icmp_seq == is->is_icmp.ics_seq) && + (icmp->icmp_type == ICMP_ECHO)) || + (is->is_type - 1 == ic->icmp_type)) { + 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); + hv += (src.s_addr = oip->ip_src.s_addr); + hv += (dst.s_addr = oip->ip_dst.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_next) { + /* + * 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) && + 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 += ip->ip_len; + /* + * 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. */ -int fr_checkstate(ip, fin) +frentry_t *fr_checkstate(ip, fin) ip_t *ip; fr_info_t *fin; { register struct in_addr dst, src; register ipstate_t *is, **isp; register u_char pr; + u_int hv, hvm, hlen, tryagain, pass; struct icmp *ic; + frentry_t *fr; tcphdr_t *tcp; - u_int hv, hlen, pass; if ((ip->ip_off & IP_OFFMASK) || (fin->fin_fi.fi_fl & FI_SHORT)) - return 0; + return NULL; + is = NULL; hlen = fin->fin_hlen; tcp = (tcphdr_t *)((char *)ip + hlen); ic = (struct icmp *)tcp; @@ -541,104 +865,144 @@ switch (ip->ip_p) { case IPPROTO_ICMP : - hv += ic->icmp_id; - hv += ic->icmp_seq; - hv %= IPSTATE_SIZE; + if ((ic->icmp_type == ICMP_ECHO) || + (ic->icmp_type == ICMP_ECHOREPLY)) { + 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_next) if ((is->is_p == pr) && - (ic->icmp_id == is->is_icmp.ics_id) && - (ic->icmp_seq == is->is_icmp.ics_seq) && - fr_matchsrcdst(is, src, dst, fin, NULL, 0, 0)) { - if (is->is_icmp.ics_type != ic->icmp_type) + fr_matchsrcdst(is, src, dst, fin, NULL)) { + if ((is->is_type == ICMP_ECHOREPLY) && + (ic->icmp_type == ICMP_ECHO) && + (ic->icmp_id == is->is_icmp.ics_id) && + (ic->icmp_seq == is->is_icmp.ics_seq)) + ; + else if (is->is_type != ic->icmp_type) continue; - pass = is->is_pass; - RWLOCK_EXIT(&ipf_state); - if (fin->fin_fi.fi_fl & FI_FRAG) - ipfr_newfrag(ip, fin, - pass ^ FR_KEEPSTATE); - WRITE_ENTER(&ipf_state); is->is_age = fr_icmptimeout; - is->is_bytes += ip->ip_len; - ips_stats.iss_hits++; - is->is_pkts++; - RWLOCK_EXIT(&ipf_state); - return pass; + break; } + if (is != NULL) + break; RWLOCK_EXIT(&ipf_state); + /* + * No matching icmp state entry. Perhaps this is a + * response to another state entry. + */ + fr = fr_checkicmpmatchingstate(ip, fin); + if (fr) + return fr; break; case IPPROTO_TCP : { register u_short dport = tcp->th_dport, sport = tcp->th_sport; - hv += dport; - hv += sport; - hv %= IPSTATE_SIZE; + tryagain = 0; +retry_tcp: + hvm = hv % fr_statesize; WRITE_ENTER(&ipf_state); - for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next) + for (isp = &ips_table[hvm]; (is = *isp); + isp = &is->is_next) if ((is->is_p == pr) && - fr_matchsrcdst(is, src, dst, fin, tcp, - sport, dport)) { + fr_matchsrcdst(is, src, dst, fin, tcp)) { if (fr_tcpstate(is, fin, ip, tcp)) { - pass = is->is_pass; -#ifdef _KERNEL - RWLOCK_EXIT(&ipf_state); -#else - +#ifndef _KERNEL if (tcp->th_flags & TCP_CLOSE) { *isp = is->is_next; - isp = &ips_table[hv]; - KFREE(is); + isp = &ips_table[hvm]; + if (ips_table[hvm] == NULL) + ips_stats.iss_inuse--; + ips_num--; } #endif - if (fin->fin_fi.fi_fl & FI_FRAG) - ipfr_newfrag(ip, fin, - pass ^ FR_KEEPSTATE); - return pass; + 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; - hv += dport; - hv += sport; - hv %= IPSTATE_SIZE; + 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[hv]; is; is = is->is_next) + for (is = ips_table[hvm]; is; is = is->is_next) if ((is->is_p == pr) && - fr_matchsrcdst(is, src, dst, fin, - tcp, sport, dport)) { - pass = is->is_pass; - MUTEX_ENTER(&ipf_rw); - is->is_bytes += ip->ip_len; + fr_matchsrcdst(is, src, dst, fin, tcp)) { is->is_age = fr_udptimeout; - ips_stats.iss_hits++; - is->is_pkts++; - MUTEX_EXIT(&ipf_rw); - RWLOCK_EXIT(&ipf_state); - if (fin->fin_fi.fi_fl & FI_FRAG) - ipfr_newfrag(ip, fin, - pass ^ FR_KEEPSTATE); - return pass; + break; } + if (is != NULL) + break; RWLOCK_EXIT(&ipf_state); + hv += dport; + hv += sport; + if (tryagain == 0) { + tryagain = 1; + goto retry_udp; + } break; } default : break; } - ATOMIC_INC(ips_stats.iss_miss); - return 0; + if (is == NULL) { + ATOMIC_INC(ips_stats.iss_miss); + return NULL; + } + MUTEX_ENTER(&ipf_rw); + is->is_bytes += ip->ip_len; + ips_stats.iss_hits++; + is->is_pkts++; + MUTEX_EXIT(&ipf_rw); + 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; } +static void fr_delstate(is) +ipstate_t *is; +{ + frentry_t *fr; + + fr = is->is_rule; + if (fr != NULL) { + ATOMIC_DEC(fr->fr_ref); + if (fr->fr_ref == 0) + KFREE(fr); + } + KFREE(is); +} + + /* * Free memory in use by all state info. kept. */ @@ -648,13 +1012,17 @@ register ipstate_t *is, **isp; WRITE_ENTER(&ipf_state); - for (i = 0; i < IPSTATE_SIZE; i++) + for (i = fr_statesize - 1; i >= 0; i--) for (isp = &ips_table[i]; (is = *isp); ) { *isp = is->is_next; - KFREE(is); + fr_delstate(is); + ips_num--; } + ips_stats.iss_inuse = 0; ips_num = 0; RWLOCK_EXIT(&ipf_state); + KFREES(ips_table, fr_statesize * sizeof(ipstate_t *)); + ips_table = NULL; } @@ -672,7 +1040,7 @@ SPL_NET(s); WRITE_ENTER(&ipf_state); - for (i = 0; i < IPSTATE_SIZE; i++) + for (i = fr_statesize - 1; i >= 0; i--) for (isp = &ips_table[i]; (is = *isp); ) if (is->is_age && !--is->is_age) { *isp = is->is_next; @@ -680,15 +1048,21 @@ ips_stats.iss_fin++; else ips_stats.iss_expire++; + if (ips_table[i] == NULL) + ips_stats.iss_inuse--; #ifdef IPFILTER_LOG ipstate_log(is, ISL_EXPIRE); #endif - KFREE(is); + fr_delstate(is); ips_num--; } 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; + } } @@ -726,23 +1100,29 @@ switch(state[dir]) { - case TCPS_FIN_WAIT_2: 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: - if ((flags & (TH_FIN|TH_ACK)) == TH_ACK) { - state[dir] = TCPS_ESTABLISHED; - *age = fr_tcpidletimeout; - } - break; 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: @@ -753,8 +1133,10 @@ *age = fr_tcplastack; else *age = fr_tcpclosewait; - } else - *age = fr_tcpidletimeout; + } else { + if (ostate < TCPS_CLOSE_WAIT) + *age = fr_tcpidletimeout; + } break; case TCPS_CLOSE_WAIT: if ((flags & TH_FIN) && !(flags & TH_PUSH) && !dlen && @@ -783,7 +1165,7 @@ #ifdef IPFILTER_LOG void ipstate_log(is, type) struct ipstate *is; -u_short type; +u_int type; { struct ipslog ipsl; void *items[1]; @@ -814,6 +1196,30 @@ sizes[0] = sizeof(ipsl); types[0] = 0; - (void) ipllog(IPL_LOGSTATE, 0, items, sizes, types, 1); + (void) ipllog(IPL_LOGSTATE, NULL, items, sizes, types, 1); } #endif + + +void ip_statesync(ifp) +void *ifp; +{ + register ipstate_t *is; + register int i; + + WRITE_ENTER(&ipf_state); + for (i = fr_statesize - 1; i >= 0; i--) + for (is = ips_table[i]; is != NULL; is = is->is_next) { + if (is->is_ifpin == ifp) { + is->is_ifpin = GETUNIT(is->is_ifname[0]); + if (!is->is_ifpin) + is->is_ifpin = (void *)-1; + } + if (is->is_ifpout == ifp) { + is->is_ifpout = GETUNIT(is->is_ifname[1]); + if (!is->is_ifpout) + is->is_ifpout = (void *)-1; + } + } + RWLOCK_EXIT(&ipf_state); +} Index: sys/netinet/ip_state.h =================================================================== RCS file: /cvs/src/sys/netinet/ip_state.h,v retrieving revision 1.9 retrieving revision 1.14 diff -u -r1.9 -r1.14 --- sys/netinet/ip_state.h 1999/02/05 05:58:54 1.9 +++ sys/netinet/ip_state.h 2000/04/13 17:13:42 1.14 @@ -1,4 +1,5 @@ -/* $OpenBSD: ip_state.h,v 1.9 1999/02/05 05:58:54 deraadt Exp $ */ +/* $OpenBSD: ip_state.h,v 1.14 2000/04/13 17:13:42 kjell Exp $ */ + /* * Copyright (C) 1995-1998 by Darren Reed. * @@ -7,13 +8,18 @@ * to the original author and the contributors. * * @(#)ip_state.h 1.3 1/12/96 (C) 1995 Darren Reed - * $Id: ip_state.h,v 1.9 1999/02/05 05:58:54 deraadt Exp $ + * $IPFilter: ip_state.h,v 2.1.2.4 2000/02/23 15:23:27 darrenr Exp $ */ #ifndef __IP_STATE_H__ #define __IP_STATE_H__ -#define IPSTATE_SIZE 257 -#define IPSTATE_MAX 2048 /* Maximum number of states held */ +#ifndef IPSTATE_SIZE +# define IPSTATE_SIZE 257 +#endif + +#ifndef IPSTATE_MAX +# define IPSTATE_MAX 2048 /* Maximum number of states held */ +#endif #define PAIRS(s1,d1,s2,d2) ((((s1) == (s2)) && ((d1) == (d2))) ||\ (((s1) == (d2)) && ((d1) == (s2)))) @@ -32,13 +38,16 @@ 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; - u_long ts_seq; - u_long ts_ack; - u_short ts_swin; - u_short ts_dwin; + tcpdata_t ts_data[2]; u_char ts_state[2]; } tcpstate_t; @@ -50,35 +59,49 @@ U_QUAD_T is_bytes; void *is_ifpin; void *is_ifpout; + frentry_t *is_rule; struct in_addr is_src; struct in_addr is_dst; - u_char is_p; - u_char is_flags; - u_32_t is_opt; - u_32_t is_optmsk; - u_short is_sec; - u_short is_secmsk; - u_short is_auth; - u_short is_authmsk; + u_char is_p; /* Protocol */ + 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]; } ipstate_t; #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_seq is_tcp.ts_seq -#define is_ack is_tcp.ts_ack -#define is_dwin is_tcp.ts_dwin -#define is_swin is_tcp.ts_swin +#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 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 ipslog { @@ -88,7 +111,7 @@ struct in_addr isl_dst; u_char isl_p; u_char isl_flags; - u_char isl_state[2]; + u_char isl_state[2]; u_short isl_type; union { u_short isl_filler[2]; @@ -119,6 +142,7 @@ u_long iss_active; u_long iss_logged; u_long iss_logfail; + u_long iss_inuse; ipstate_t **iss_table; } ips_stat_t; @@ -130,13 +154,15 @@ extern u_long fr_tcpclosed; extern u_long fr_udptimeout; extern u_long fr_icmptimeout; +extern int fr_stateinit __P((void)); extern int fr_tcpstate __P((ipstate_t *, fr_info_t *, ip_t *, tcphdr_t *)); -extern int fr_addstate __P((ip_t *, fr_info_t *, u_int)); -extern int fr_checkstate __P((ip_t *, fr_info_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 *, ip_t *, fr_info_t *, int)); extern void fr_stateunload __P((void)); -extern void ipstate_log __P((struct ipstate *, u_short)); +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 Index: sbin/ipf/Makefile =================================================================== RCS file: /cvs/src/sbin/ipf/Makefile,v retrieving revision 1.5 retrieving revision 1.9 diff -u -r1.5 -r1.9 --- sbin/ipf/Makefile 1999/02/07 00:48:28 1.5 +++ sbin/ipf/Makefile 2000/04/26 21:03:59 1.9 @@ -1,7 +1,7 @@ -# $OpenBSD: Makefile,v 1.5 1999/02/07 00:48:28 deraadt Exp $ +# $OpenBSD: Makefile,v 1.9 2000/04/26 21:03:59 deraadt Exp $ PROG= ipf MAN= ipf.8 ipf.4 ipf.5 -SRCS= ipf.c parse.c opt.c +SRCS= ipf.c parse.c opt.c facpri.c ifaddr.c .include Index: sbin/ipf/ipf.c =================================================================== RCS file: /cvs/src/sbin/ipf/ipf.c,v retrieving revision 1.19 retrieving revision 1.24 diff -u -r1.19 -r1.24 --- sbin/ipf/ipf.c 1999/07/06 19:06:42 1.19 +++ sbin/ipf/ipf.c 2000/04/12 21:51:48 1.24 @@ -1,4 +1,5 @@ -/* $OpenBSD: ipf.c,v 1.19 1999/07/06 19:06:42 kjell Exp $ */ +/* $OpenBSD: ipf.c,v 1.24 2000/04/12 21:51:48 kjell Exp $ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -35,20 +36,17 @@ #include #include #include -#if defined(__OpenBSD__) -# include -#else -# include -#endif +#include #include +#include #include "ipf.h" +#include #if !defined(lint) static const char sccsid[] = "@(#)ipf.c 1.23 6/5/96 (C) 1993-1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipf.c,v 1.19 1999/07/06 19:06:42 kjell Exp $"; +static const char rcsid[] = "@(#)$IPFilter: ipf.c,v 2.2.2.1 2000/02/16 14:40:39 darrenr Exp $"; #endif -static void frsync __P((void)); #if SOLARIS static void blockunknown __P((void)); #endif @@ -60,6 +58,7 @@ extern int optind; extern int optreset; +void frsync __P((void)); void zerostats __P((void)); int main __P((int, char *[])); @@ -74,24 +73,28 @@ static void closedevice __P((void)); static char *getline __P((char *, size_t, FILE *)); static char *ipfname = IPL_NAME; +static void usage __P((void)); +static void showversion __P((void)); +static int get_flags __P((void)); #if SOLARIS -#define OPTS "AdDEf:F:Il:noPrsUvyzZ" +#define OPTS "AdDEf:F:Il:noPrsUvVyzZ" #else -#define OPTS "AdDEf:F:Il:noPrsvyzZ" +#define OPTS "AdDEf:F:Il:noPrsvVyzZ" #endif -void usage() +static void usage() { #if SOLARIS - fprintf(stderr, "usage: ipf [-AdDEInorsUvyzZ] [-l block|pass|nomatch] " + fprintf(stderr, "usage: ipf [-AdDEInoPrsUvVyzZ] %s %s %s\n", #else - fprintf(stderr, "usage: ipf [-AdDEInorsvyzZ] [-l block|pass|nomatch] " + fprintf(stderr, "usage: ipf [-AdDEInoPrsvVyzZ] %s %s %s\n", #endif - "[-F i|o|a|s|S] [-f filename]\n"); + "[-l block|pass|nomatch]", "[-F i|o|a|s|S]", "[-f filename]"); exit(1); } + int main(argc,argv) int argc; char *argv[]; @@ -154,6 +157,9 @@ case 'v' : opts |= OPT_VERBOSE; break; + case 'V' : + showversion(); + break; case 'y' : frsync(); break; @@ -198,6 +204,18 @@ } +static int get_flags() +{ + int i; + + if ((opendevice(ipfname) != -2) && (ioctl(fd, SIOCGETFF, &i) == -1)) { + perror("SIOCFRENB"); + return 0; + } + return i; +} + + static void set_state(enable) u_int enable; { @@ -213,13 +231,17 @@ FILE *fp; char line[513], *s; struct frentry *fr; - u_int add = SIOCADAFR, del = SIOCRMAFR; + u_int add, del; + int linenum = 0; (void) opendevice(ipfname); if (opts & OPT_INACTIVE) { add = SIOCADIFR; del = SIOCRMIFR; + } else { + add = SIOCADAFR; + del = SIOCRMAFR; } if (opts & OPT_DEBUG) printf("add %x del %x\n", add, del); @@ -235,6 +257,7 @@ } while (getline(line, sizeof(line), fp)) { + linenum++; /* * treat CR as EOL. LF is converted to NUL by getline(). */ @@ -252,7 +275,7 @@ if (opts & OPT_VERBOSE) (void)fprintf(stderr, "[%s]\n", line); - fr = parse(line); + fr = parse(line, linenum); (void)fflush(stdout); if (fr) { @@ -339,13 +362,12 @@ static void packetlogon(opt) char *opt; { - int err, flag = 0; - - if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { - if ((err = ioctl(fd, SIOCGETFF, &flag))) - perror("ioctl(SIOCGETFF)"); + int flag, err; - printf("log flag is currently %#x\n", flag); + flag = get_flags(); + if (flag != 0) { + if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) + printf("log flag is currently %#x\n", flag); } flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK); @@ -370,9 +392,7 @@ perror("ioctl(SIOCSETFF)"); if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { - if ((err = ioctl(fd, SIOCGETFF, &flag))) - perror("ioctl(SIOCGETFF)"); - + flag = get_flags(); printf("log flag is now %#x\n", flag); } } @@ -434,7 +454,7 @@ } -static void frsync() +void frsync() { int frsyn = 0; @@ -495,17 +515,14 @@ #if SOLARIS static void blockunknown() { - int flag; + u_32_t flag; if (opendevice(ipfname) == -1) return; - - if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { - if (ioctl(fd, SIOCGETFF, &flag)) - perror("ioctl(SIOCGETFF)"); + flag = get_flags(); + if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) printf("log flag is currently %#x\n", flag); - } flag ^= FF_BLOCKNONIP; @@ -520,3 +537,54 @@ } } #endif + + +static void showversion() +{ + struct friostat fio; + u_32_t flags; + char *s; + + printf("ipf: %s (%d)\n", IPL_VERSION, sizeof(frentry_t)); + + if (opendevice(ipfname) != -2 && ioctl(fd, SIOCGETFS, &fio)) { + perror("ioctl(SIOCGETFS"); + return; + } + flags = get_flags(); + + printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version), + (int)sizeof(fio.f_version), fio.f_version); + printf("Running: %s\n", fio.f_running ? "yes" : "no"); + printf("Log Flags: %#x = ", flags); + s = ""; + if (flags & FF_LOGPASS) { + printf("pass"); + s = ", "; + } + if (flags & FF_LOGBLOCK) { + printf("%sblock", s); + s = ", "; + } + if (flags & FF_LOGNOMATCH) { + printf("%snomatch", s); + s = ", "; + } + if (flags & FF_BLOCKNONIP) { + printf("%snonip", s); + s = ", "; + } + if (!*s) + printf("none set"); + putchar('\n'); + + printf("Default: "); + if (fio.f_defpass & FR_PASS) + s = "pass"; + else if (fio.f_defpass & FR_BLOCK) + s = "block"; + else + s = "nomatch -> block"; + printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un"); + printf("Active list: %d\n", fio.f_active); +} Index: sbin/ipf/ipf.h =================================================================== RCS file: /cvs/src/sbin/ipf/ipf.h,v retrieving revision 1.10 retrieving revision 1.14 diff -u -r1.10 -r1.14 --- sbin/ipf/ipf.h 1999/07/05 20:12:43 1.10 +++ sbin/ipf/ipf.h 2000/03/13 23:40:19 1.14 @@ -1,4 +1,5 @@ -/* $OpenBSD: ipf.h,v 1.10 1999/07/05 20:12:43 kjell Exp $ */ +/* $OpenBSD: ipf.h,v 1.14 2000/03/13 23:40:19 kjell Exp $ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -7,7 +8,7 @@ * to the original author and the contributors. * * @(#)ipf.h 1.12 6/5/96 - * $Id: ipf.h,v 1.10 1999/07/05 20:12:43 kjell Exp $ + * $IPFilter: ipf.h,v 2.1.2.1 1999/10/05 12:59:25 darrenr Exp $ */ #ifndef __IPF_H__ @@ -16,26 +17,28 @@ #ifndef SOLARIS #define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #endif -#define OPT_REMOVE 0x00001 -#define OPT_DEBUG 0x00002 -#define OPT_OUTQUE FR_OUTQUE /* 0x0004 */ -#define OPT_INQUE FR_INQUE /* 0x0008 */ -#define OPT_LOG FR_LOG /* 0x0010 */ -#define OPT_SHOWLIST 0x00020 -#define OPT_VERBOSE 0x00040 -#define OPT_DONOTHING 0x00080 -#define OPT_HITS 0x00100 -#define OPT_BRIEF 0x00200 +#define OPT_REMOVE 0x000001 +#define OPT_DEBUG 0x000002 +#define OPT_OUTQUE FR_OUTQUE /* 0x00004 */ +#define OPT_INQUE FR_INQUE /* 0x00008 */ +#define OPT_LOG FR_LOG /* 0x00010 */ +#define OPT_SHOWLIST 0x000020 +#define OPT_VERBOSE 0x000040 +#define OPT_DONOTHING 0x000080 +#define OPT_HITS 0x000100 +#define OPT_BRIEF 0x000200 #define OPT_ACCNT FR_ACCOUNT /* 0x0400 */ #define OPT_FRSTATES FR_KEEPFRAG /* 0x0800 */ #define OPT_IPSTATES FR_KEEPSTATE /* 0x1000 */ #define OPT_INACTIVE FR_INACTIVE /* 0x2000 */ -#define OPT_SHOWLINENO 0x04000 -#define OPT_PRINTFR 0x08000 -#define OPT_ZERORULEST 0x10000 -#define OPT_SAVEOUT 0x20000 -#define OPT_AUTHSTATS 0x40000 -#define OPT_RAW 0x80000 +#define OPT_SHOWLINENO 0x004000 +#define OPT_PRINTFR 0x008000 +#define OPT_ZERORULEST 0x010000 +#define OPT_SAVEOUT 0x020000 +#define OPT_AUTHSTATS 0x040000 +#define OPT_RAW 0x080000 +#define OPT_NAT 0x100000 +#define OPT_GROUPS 0x200000 #ifndef __P # ifdef __STDC__ @@ -49,11 +52,11 @@ extern char *strdup __P((char *)); #endif -extern struct frentry *parse __P((char *)); +extern struct frentry *parse __P((char *, int)); extern void printfr __P((struct frentry *)); extern void binprint __P((struct frentry *)), initparse __P((void)); -extern int portnum __P((char *, u_short *)); +extern int portnum __P((char *, u_short *, int)); struct ipopt_names { @@ -65,8 +68,8 @@ extern u_32_t buildopts __P((char *, char *, int)); -extern u_32_t hostnum __P((char *, int *)); -extern u_32_t optname __P((char ***, u_short *)); +extern u_32_t hostnum __P((char *, int *, int)); +extern u_32_t optname __P((char ***, u_short *, int)); extern void printpacket __P((ip_t *)); #if SOLARIS extern int inet_aton __P((const char *, struct in_addr *)); @@ -74,11 +77,11 @@ extern void sync __P((void)); #endif -#ifdef sun -#define STRERROR(x) sys_errlist[x] +#if defined(sun) && !SOLARIS +# define STRERROR(x) sys_errlist[x] extern char *sys_errlist[]; #else -#define STRERROR(x) strerror(x) +# define STRERROR(x) strerror(x) #endif #ifndef MIN Index: sbin/ipf/opt.c =================================================================== RCS file: /cvs/src/sbin/ipf/opt.c,v retrieving revision 1.10 retrieving revision 1.14 diff -u -r1.10 -r1.14 --- sbin/ipf/opt.c 1999/02/05 05:58:42 1.10 +++ sbin/ipf/opt.c 2000/03/13 23:40:19 1.14 @@ -1,4 +1,5 @@ -/* $OpenBSD: opt.c,v 1.10 1999/02/05 05:58:42 deraadt Exp $ */ +/* $OpenBSD: opt.c,v 1.14 2000/03/13 23:40:19 kjell Exp $ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -21,18 +22,14 @@ #include #include #include -#if defined(__OpenBSD__) -# include -#else -# include -#endif +#include #include #include #include "ipf.h" #if !defined(lint) static const char sccsid[] = "@(#)opt.c 1.8 4/10/96 (C) 1993-1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: opt.c,v 1.10 1999/02/05 05:58:42 deraadt Exp $"; +static const char rcsid[] = "@(#)$IPFilter: opt.c,v 2.1 1999/08/04 17:30:15 darrenr Exp $"; #endif extern int opts; Index: sbin/ipf/parse.c =================================================================== RCS file: /cvs/src/sbin/ipf/parse.c,v retrieving revision 1.26 retrieving revision 1.34 diff -u -r1.26 -r1.34 --- sbin/ipf/parse.c 1999/07/06 04:38:11 1.26 +++ sbin/ipf/parse.c 2000/04/05 05:35:28 1.34 @@ -1,4 +1,5 @@ -/* $OpenBSD: parse.c,v 1.26 1999/07/06 04:38:11 deraadt Exp $ */ +/* $OpenBSD: parse.c,v 1.34 2000/04/05 05:35:28 kjell Exp $ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -6,8 +7,6 @@ * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ -#include -#include #include #if !defined(__SVR4) && !defined(__svr4__) #include @@ -16,51 +15,64 @@ #endif #include #include -#include -#include -#include #include #include #include #include #include #include +#if __FreeBSD_version >= 300000 +# include +#endif +#include +#include +#include +#include +#include +#include #include #include #include #include #include +#include #include #include #include "ipf.h" +#include "facpri.h" #if !defined(lint) -static const char sccsid[] ="@(#)parse.c 1.44 6/5/96 (C) 1993-1996 Darren Reed"; -static const char rcsid[] = "@(#)$Id: parse.c,v 1.26 1999/07/06 04:38:11 deraadt Exp $"; +static const char sccsid[] = "@(#)parse.c 1.44 6/5/96 (C) 1993-1996 Darren Reed"; +static const char rcsid[] = "@(#)$IPFilter: parse.c,v 2.1.2.12 2000/03/08 11:43:55 darrenr Exp $"; #endif extern struct ipopt_names ionames[], secclass[]; extern int opts; -int portnum __P((char *, u_short *)); -u_char tcp_flags __P((char *, u_char *)); -int addicmp __P((char ***, struct frentry *)); -int extras __P((char ***, struct frentry *)); +int portnum __P((char *, u_short *, int)); +u_char tcp_flags __P((char *, u_char *, int)); +int addicmp __P((char ***, struct frentry *, int)); +int extras __P((char ***, struct frentry *, int)); char ***seg; u_long *sa, *msk; u_short *pp, *tp; u_char *cp; int hostmask __P((char ***, u_32_t *, u_32_t *, u_short *, u_char *, - u_short *)); -int ports __P((char ***, u_short *, u_char *, u_short *)); -int icmpcode __P((char *)), addkeep __P((char ***, struct frentry *)); -int to_interface __P((frdest_t *, char *)); + u_short *, int)); +int ports __P((char ***, u_short *, u_char *, u_short *, int)); +int icmpcode __P((char *)), addkeep __P((char ***, struct frentry *, int)); +int to_interface __P((frdest_t *, char *, int)); void print_toif __P((char *, frdest_t *)); -void optprint __P((u_short, u_short, u_long, u_long)); +void optprint __P((u_short *, u_long, u_long)); int countbits __P((u_32_t)); char *portname __P((int, int)); int ratoi __P((char *, int *, int, int)); +int loglevel __P((char **, u_short *, int)); +void printlog __P((frentry_t *)); +#if defined(__OpenBSD__) +extern int if_addr __P((char *, struct in_addr *)); +#endif char *proto = NULL; @@ -69,6 +81,7 @@ static char thishost[MAXHOSTNAMELEN]; + void initparse() { gethostname(thishost, sizeof(thishost)); @@ -79,14 +92,15 @@ * * parse a line read from the input filter rule file */ -struct frentry *parse(line) +struct frentry *parse(line, linenum) char *line; +int linenum; { static struct frentry fil; struct protoent *p = NULL; char *cps[31], **cpp, *endptr; u_char ch; - int i, cnt = 1; + int i, cnt = 1, j; while (*line && isspace(*line)) line++; @@ -96,6 +110,8 @@ bzero((char *)&fil, sizeof(fil)); fil.fr_mip.fi_v = 0xf; fil.fr_ip.fi_v = 4; + fil.fr_loglevel = 0xffff; + /* * break line up into max of 20 segments */ @@ -106,7 +122,7 @@ cps[i] = NULL; if (cnt < 3) { - (void)fprintf(stderr, "not enough segments in line\n"); + fprintf(stderr, "%d: not enough segments in line\n", linenum); return NULL; } @@ -117,18 +133,34 @@ if (!strcasecmp("block", *cpp)) { fil.fr_flags |= FR_BLOCK; - if (!strncasecmp(*(cpp+1), "return-icmp", 11)) { + if (!strncasecmp(*(cpp+1), "return-icmp-as-dest", 19) && + (i = 19)) + fil.fr_flags |= FR_FAKEICMP; + else if (!strncasecmp(*(cpp+1), "return-icmp", 11) && (i = 11)) fil.fr_flags |= FR_RETICMP; + if (fil.fr_flags & FR_RETICMP) { cpp++; - if (*(*cpp + 11) == '(') { - i = icmpcode(*cpp + 12); - if (i == -1) { + if (strlen(*cpp) == i) { + if (*(cpp + 1) && **(cpp +1) == '(') { + cpp++; + i = 0; + } else + i = -1; + } + + /* + * The ICMP code is not required to follow in ()'s + */ + if ((i >= 0) && (*(*cpp + i) == '(')) { + i++; + j = icmpcode(*cpp + i); + if (j == -1) { fprintf(stderr, - "unrecognised icmp code %s\n", - *cpp + 12); + "%d: unrecognised icmp code %s\n", + linenum, *cpp + 20); return NULL; } - fil.fr_icode = i; + fil.fr_icode = j; } } else if (!strncasecmp(*(cpp+1), "return-rst", 10)) { fil.fr_flags |= FR_RETRST; @@ -144,10 +176,11 @@ fil.fr_flags |= FR_PREAUTH; } else if (!strcasecmp("skip", *cpp)) { cpp++; - if (ratoi(*cpp, &i, 0, INT_MAX)) + if (ratoi(*cpp, &i, 0, USHRT_MAX)) fil.fr_skip = i; else { - (void)fprintf(stderr, "integer must follow skip\n"); + fprintf(stderr, "%d: integer must follow skip\n", + linenum); return NULL; } } else if (!strcasecmp("log", *cpp)) { @@ -160,62 +193,123 @@ fil.fr_flags |= FR_LOGFIRST; cpp++; } + if (*cpp && !strcasecmp(*(cpp+1), "or-block")) { + fil.fr_flags |= FR_LOGORBLOCK; + cpp++; + } + if (!strcasecmp(*(cpp+1), "level")) { + cpp++; + if (loglevel(cpp, &fil.fr_loglevel, linenum) == -1) + return NULL; + cpp++; + } } else { /* * Doesn't start with one of the action words */ - (void)fprintf(stderr, "unknown keyword (%s)\n", *cpp); + fprintf(stderr, "%d: unknown keyword (%s)\n", linenum, *cpp); + return NULL; + } + if (!*++cpp) { + fprintf(stderr, "%d: missing 'in'/'out' keyword\n", linenum); return NULL; } - cpp++; if (!strcasecmp("in", *cpp)) fil.fr_flags |= FR_INQUE; else if (!strcasecmp("out", *cpp)) { fil.fr_flags |= FR_OUTQUE; if (fil.fr_flags & FR_RETICMP) { - (void)fprintf(stderr, - "Can only use return-icmp with 'in'\n"); + fprintf(stderr, + "%d: Can only use return-icmp with 'in'\n", + linenum); return NULL; } else if (fil.fr_flags & FR_RETRST) { - (void)fprintf(stderr, - "Can only use return-rst with 'in'\n"); + fprintf(stderr, + "%d: Can only use return-rst with 'in'\n", + linenum); return NULL; } - } else { - (void)fprintf(stderr, - "missing 'in'/'out' keyword (%s)\n", *cpp); - return NULL; } - if (!*++cpp) + if (!*++cpp) { + fprintf(stderr, "%d: missing source specification\n", linenum); return NULL; + } if (!strcasecmp("log", *cpp)) { - cpp++; + if (!*++cpp) { + fprintf(stderr, "%d: missing source specification\n", + linenum); + return NULL; + } if (fil.fr_flags & FR_PASS) fil.fr_flags |= FR_LOGP; else if (fil.fr_flags & FR_BLOCK) fil.fr_flags |= FR_LOGB; - if (!strcasecmp(*cpp, "body")) { + if (*cpp && !strcasecmp(*cpp, "body")) { fil.fr_flags |= FR_LOGBODY; cpp++; } - if (!strcasecmp(*cpp, "first")) { + if (*cpp && !strcasecmp(*cpp, "first")) { fil.fr_flags |= FR_LOGFIRST; cpp++; } - if (!strcasecmp(*cpp, "or-block")) { + if (*cpp && !strcasecmp(*cpp, "or-block")) { if (!(fil.fr_flags & FR_PASS)) { - (void)fprintf(stderr, - "or-block must be used with pass\n"); + fprintf(stderr, + "%d: or-block must be used with pass\n", + linenum); return NULL; } fil.fr_flags |= FR_LOGORBLOCK; cpp++; } + if (*cpp && !strcasecmp(*cpp, "level")) { + int fac, pri; + char *s; + + fac = 0; + pri = 0; + if (!*++cpp) { + fprintf(stderr, "%d: %s\n", linenum, + "missing identifier after level"); + return NULL; + } + s = index(*cpp, '.'); + if (s) { + *s++ = '\0'; + fac = fac_findname(*cpp); + if (fac == -1) { + fprintf(stderr, "%d: %s %s\n", linenum, + "Unknown facility", *cpp); + return NULL; + } + pri = pri_findname(s); + if (pri == -1) { + fprintf(stderr, "%d: %s %s\n", linenum, + "Unknown priority", s); + return NULL; + } + } else { + pri = pri_findname(*cpp); + if (pri == -1) { + fprintf(stderr, "%d: %s %s\n", linenum, + "Unknown priority", *cpp); + return NULL; + } + } + fil.fr_loglevel = fac|pri; + cpp++; + } + if (*cpp && !strcasecmp(*cpp, "level")) { + if (loglevel(cpp, &fil.fr_loglevel, linenum) == -1) + return NULL; + cpp++; + cpp++; + } } - if (!strcasecmp("quick", *cpp)) { + if (*cpp && !strcasecmp("quick", *cpp)) { cpp++; fil.fr_flags |= FR_QUICK; } @@ -223,17 +317,18 @@ *fil.fr_ifname = '\0'; if (*cpp && !strcasecmp(*cpp, "on")) { if (!*++cpp) { - (void)fprintf(stderr, "interface name missing\n"); + fprintf(stderr, "%d: interface name missing\n", + linenum); return NULL; } (void)strncpy(fil.fr_ifname, *cpp, IFNAMSIZ-1); fil.fr_ifname[IFNAMSIZ-1] = '\0'; cpp++; if (!*cpp) { - if (fil.fr_flags & FR_RETRST) { - (void)fprintf(stderr, - "%s can only be used with TCP\n", - "return-rst"); + if ((fil.fr_flags & FR_RETMASK) == FR_RETRST) { + fprintf(stderr, + "%d: %s can only be used with TCP\n", + linenum, "return-rst"); return NULL; } return &fil; @@ -242,16 +337,22 @@ if (*cpp) { if (!strcasecmp(*cpp, "dup-to") && *(cpp + 1)) { cpp++; - if (to_interface(&fil.fr_dif, *cpp)) + if (to_interface(&fil.fr_dif, *cpp, linenum)) return NULL; cpp++; } - if (!strcasecmp(*cpp, "to") && *(cpp + 1)) { + if (*cpp && !strcasecmp(*cpp, "to") && *(cpp + 1)) { cpp++; - if (to_interface(&fil.fr_tif, *cpp)) + if (to_interface(&fil.fr_tif, *cpp, linenum)) return NULL; cpp++; - } else if (!strcasecmp(*cpp, "fastroute")) { + } else if (*cpp && !strcasecmp(*cpp, "fastroute")) { + if (!(fil.fr_flags & FR_INQUE)) { + fprintf(stderr, + "can only use %s with 'in'\n", + "fastroute"); + return NULL; + } fil.fr_flags |= FR_FASTROUTE; cpp++; } @@ -259,7 +360,7 @@ } if (*cpp && !strcasecmp(*cpp, "tos")) { if (!*++cpp) { - (void)fprintf(stderr, "tos missing value\n"); + fprintf(stderr, "%d: tos missing value\n", linenum); return NULL; } fil.fr_tos = strtol(*cpp, NULL, 0); @@ -269,13 +370,15 @@ if (*cpp && !strcasecmp(*cpp, "ttl")) { if (!*++cpp) { - (void)fprintf(stderr, "ttl missing hopcount value\n"); + fprintf(stderr, "%d: ttl missing hopcount value\n", + linenum); return NULL; } if (ratoi(*cpp, &i, 0, 255)) fil.fr_ttl = i; else { - (void)fprintf(stderr, "invalid ttl (%s)\n", *cpp); + fprintf(stderr, "%d: invalid ttl (%s)\n", + linenum, *cpp); return NULL; } fil.fr_mip.fi_ttl = 0xff; @@ -288,44 +391,39 @@ proto = NULL; if (*cpp && !strcasecmp(*cpp, "proto")) { if (!*++cpp) { - (void)fprintf(stderr, "protocol name missing\n"); + fprintf(stderr, "%d: protocol name missing\n", linenum); return NULL; } - if (!strcasecmp(*cpp, "tcp/udp")) { + proto = *cpp++; + if (!strcasecmp(proto, "tcp/udp")) { fil.fr_ip.fi_fl |= FI_TCPUDP; fil.fr_mip.fi_fl |= FI_TCPUDP; } else { - if (!(p = getprotobyname(*cpp)) && !isdigit(**cpp)) { - (void)fprintf(stderr, - "unknown protocol (%s)\n", *cpp); + if (!(p = getprotobyname(proto)) && !isdigit(*proto)) { + fprintf(stderr, + "%d: unknown protocol (%s)\n", + linenum, proto); return NULL; } if (p) fil.fr_proto = p->p_proto; - else if (isdigit(**cpp)) { - i = (int)strtol(*cpp, &endptr, 0); + else if (isdigit(*proto)) { + i = (int)strtol(proto, &endptr, 0); if (*endptr != '\0' || i < 0 || i > 255) { - (void)fprintf(stderr, - "unknown protocol (%s)\n", *cpp); + fprintf(stderr, + "%d: unknown protocol (%s)\n", + linenum, proto); return NULL; } fil.fr_proto = i; } fil.fr_mip.fi_p = 0xff; } - proto = *cpp; - if (fil.fr_proto != IPPROTO_TCP && fil.fr_flags & FR_RETRST) { - (void)fprintf(stderr, - "%s can only be used with TCP\n", - "return-rst"); - return NULL; - } - if (!*++cpp) - return &fil; } - if (fil.fr_proto != IPPROTO_TCP && fil.fr_flags & FR_RETRST) { - (void)fprintf(stderr, "%s can only be used with TCP\n", - "return-rst"); + if ((fil.fr_proto != IPPROTO_TCP) && + ((fil.fr_flags & FR_RETMASK) == FR_RETRST)) { + fprintf(stderr, "%d: %s can only be used with TCP\n", + linenum, "return-rst"); return NULL; } @@ -334,7 +432,7 @@ */ if (!*cpp) { - fprintf(stderr, "missing source specification\n"); + fprintf(stderr, "%d: missing source specification\n", linenum); return NULL; } if (!strcasecmp(*cpp, "all")) { @@ -343,12 +441,13 @@ return &fil; } else { if (strcasecmp(*cpp, "from")) { - (void)fprintf(stderr, - "unexpected keyword (%s) - from\n", *cpp); + fprintf(stderr, "%d: unexpected keyword (%s) - from\n", + linenum, *cpp); return NULL; } if (!*++cpp) { - (void)fprintf(stderr, "missing host after from\n"); + fprintf(stderr, "%d: missing host after from\n", + linenum); return NULL; } ch = 0; @@ -358,12 +457,12 @@ } if (hostmask(&cpp, (u_32_t *)&fil.fr_src, (u_32_t *)&fil.fr_smsk, &fil.fr_sport, &ch, - &fil.fr_stop)) { + &fil.fr_stop, linenum)) { return NULL; } fil.fr_scmp = ch; if (!*cpp) { - (void)fprintf(stderr, "missing to fields\n"); + fprintf(stderr, "%d: missing to fields\n", linenum); return NULL; } @@ -371,12 +470,12 @@ * do the same for the to field (destination host) */ if (strcasecmp(*cpp, "to")) { - (void)fprintf(stderr, - "unexpected keyword (%s) - to\n", *cpp); + fprintf(stderr, "%d: unexpected keyword (%s) - to\n", + linenum, *cpp); return NULL; } if (!*++cpp) { - (void)fprintf(stderr, "missing host after to\n"); + fprintf(stderr, "%d: missing host after to\n", linenum); return NULL; } ch = 0; @@ -386,7 +485,7 @@ } if (hostmask(&cpp, (u_32_t *)&fil.fr_dst, (u_32_t *)&fil.fr_dmsk, &fil.fr_dport, &ch, - &fil.fr_dtop)) { + &fil.fr_dtop, linenum)) { return NULL; } fil.fr_dcmp = ch; @@ -398,11 +497,12 @@ */ if (fil.fr_proto && (fil.fr_dcmp || fil.fr_scmp) && fil.fr_proto != IPPROTO_TCP && fil.fr_proto != IPPROTO_UDP) { - (void)fprintf(stderr, "port operation on non tcp/udp\n"); + fprintf(stderr, "%d: port operation on non tcp/udp\n", linenum); return NULL; } if (fil.fr_icmp && fil.fr_proto != IPPROTO_ICMP) { - (void)fprintf(stderr, "icmp comparisons on wrong protocol\n"); + fprintf(stderr, "%d: icmp comparisons on wrong protocol\n", + linenum); return NULL; } @@ -411,10 +511,10 @@ if (*cpp && !strcasecmp(*cpp, "flags")) { if (!*++cpp) { - (void)fprintf(stderr, "no flags present\n"); + fprintf(stderr, "%d: no flags present\n", linenum); return NULL; } - fil.fr_tcpf = tcp_flags(*cpp, &fil.fr_tcpfm); + fil.fr_tcpf = tcp_flags(*cpp, &fil.fr_tcpfm, linenum); cpp++; } @@ -422,7 +522,7 @@ * extras... */ if (*cpp && (!strcasecmp(*cpp, "with") || !strcasecmp(*cpp, "and"))) - if (extras(&cpp, &fil)) + if (extras(&cpp, &fil, linenum)) return NULL; /* @@ -430,12 +530,12 @@ */ if (*cpp && !strcasecmp(*cpp, "icmp-type")) { if (fil.fr_proto != IPPROTO_ICMP) { - (void)fprintf(stderr, - "icmp with wrong protocol (%d)\n", - fil.fr_proto); + fprintf(stderr, + "%d: icmp with wrong protocol (%d)\n", + linenum, fil.fr_proto); return NULL; } - if (addicmp(&cpp, &fil)) + if (addicmp(&cpp, &fil, linenum)) return NULL; fil.fr_icmp = htons(fil.fr_icmp); fil.fr_icmpm = htons(fil.fr_icmpm); @@ -445,7 +545,7 @@ * Keep something... */ while (*cpp && !strcasecmp(*cpp, "keep")) - if (addkeep(&cpp, &fil)) + if (addkeep(&cpp, &fil, linenum)) return NULL; /* @@ -453,13 +553,14 @@ */ if (*cpp && !strcasecmp(*cpp, "head")) { if (!*++cpp) { - (void)fprintf(stderr, "head without group #\n"); + fprintf(stderr, "%d: head without group #\n", linenum); return NULL; } if (ratoi(*cpp, &i, 0, USHRT_MAX)) fil.fr_grhead = i; else { - (void)fprintf(stderr, "invalid group (%s)\n", *cpp); + fprintf(stderr, "%d: invalid group (%s)\n", + linenum, *cpp); return NULL; } cpp++; @@ -470,15 +571,17 @@ */ if (*cpp && !strcasecmp(*cpp, "group")) { if (!*++cpp) { - (void)fprintf(stderr, "group without group #\n"); + fprintf(stderr, "%d: group without group #\n", + linenum); return NULL; } if (ratoi(*cpp, &i, 0, USHRT_MAX)) fil.fr_group = i; else { - (void)fprintf(stderr, "invalid group (%s)\n", *cpp); - return NULL; - } + fprintf(stderr, "%d: invalid group (%s)\n", + linenum, *cpp); + return NULL; + } cpp++; } @@ -486,10 +589,10 @@ * leftovers...yuck */ if (*cpp && **cpp) { - fprintf(stderr, "unknown words at end: ["); + fprintf(stderr, "%d: unknown words at end: [", linenum); for (; *cpp; cpp++) - (void)fprintf(stderr, "%s ", *cpp); - (void)fprintf(stderr, "]\n"); + fprintf(stderr, "%s ", *cpp); + fprintf(stderr, "]\n"); return NULL; } @@ -497,7 +600,7 @@ * lazy users... */ if ((fil.fr_tcpf || fil.fr_tcpfm) && fil.fr_proto != IPPROTO_TCP) { - (void)fprintf(stderr, "TCP protocol not specified\n"); + fprintf(stderr, "%d: TCP protocol not specified\n", linenum); return NULL; } if (!(fil.fr_ip.fi_fl & FI_TCPUDP) && (fil.fr_proto != IPPROTO_TCP) && @@ -506,26 +609,73 @@ fil.fr_ip.fi_fl |= FI_TCPUDP; fil.fr_mip.fi_fl |= FI_TCPUDP; } else { - (void)fprintf(stderr, - "port comparisons for non-TCP/UDP\n"); + fprintf(stderr, + "%d: port comparisons for non-TCP/UDP\n", + linenum); return NULL; } } /* if ((fil.fr_flags & FR_KEEPFRAG) && (!(fil.fr_ip.fi_fl & FI_FRAG) || !(fil.fr_ip.fi_fl & FI_FRAG))) { - (void)fprintf(stderr, - "must use 'with frags' with 'keep frags'\n"); + fprintf(stderr, + "%d: must use 'with frags' with 'keep frags'\n", + linenum); return NULL; } */ return &fil; } + +int loglevel(cpp, facpri, linenum) +char **cpp; +u_short *facpri; +int linenum; +{ + int fac, pri; + char *s; + + fac = 0; + pri = 0; + if (!*++cpp) { + fprintf(stderr, "%d: %s\n", linenum, + "missing identifier after level"); + return -1; + } + + s = index(*cpp, '.'); + if (s) { + *s++ = '\0'; + fac = fac_findname(*cpp); + if (fac == -1) { + fprintf(stderr, "%d: %s %s\n", linenum, + "Unknown facility", *cpp); + return -1; + } + pri = pri_findname(s); + if (pri == -1) { + fprintf(stderr, "%d: %s %s\n", linenum, + "Unknown priority", s); + return -1; + } + } else { + pri = pri_findname(*cpp); + if (pri == -1) { + fprintf(stderr, "%d: %s %s\n", linenum, + "Unknown priority", *cpp); + return -1; + } + } + *facpri = fac|pri; + return 0; +} -int to_interface(fdp, to) + +int to_interface(fdp, to, linenum) frdest_t *fdp; char *to; +int linenum; { int r = 0; char *s; @@ -534,7 +684,7 @@ fdp->fd_ifp = NULL; if (s) { *s++ = '\0'; - fdp->fd_ip.s_addr = hostnum(s, &r); + fdp->fd_ip.s_addr = hostnum(s, &r, linenum); if (r == -1) return -1; } @@ -548,10 +698,10 @@ char *tag; frdest_t *fdp; { - (void)printf("%s %s%s", tag, fdp->fd_ifname, + printf("%s %s%s", tag, fdp->fd_ifname, (fdp->fd_ifp || (long)fdp->fd_ifp == -1) ? "" : "(!)"); if (fdp->fd_ip.s_addr) - (void)printf(":%s", inet_ntoa(fdp->fd_ip)); + printf(":%s", inet_ntoa(fdp->fd_ip)); putchar(' '); } @@ -561,11 +711,12 @@ * found in the line segments, there is an error processing this information, * or there is an error processing ports information. */ -int hostmask(seg, sa, msk, pp, cp, tp) +int hostmask(seg, sa, msk, pp, cp, tp, linenum) char ***seg; u_32_t *sa, *msk; u_short *pp, *tp; u_char *cp; +int linenum; { char *s, *endptr; int bits = -1, resolved; @@ -577,12 +728,11 @@ if ((s = index(**seg, '/')) || (s = index(**seg, ':'))) { *s++ = '\0'; if (index(s, '.') || index(s, 'x')) { - /* - * Netmask possibly of the form xxx.xxx.xxx.xxx - * or 0xYYYYYYYY - */ + /* possibly of the form xxx.xxx.xxx.xxx + * or 0xYYYYYYYY */ if (inet_aton(s, &maskaddr) == 0) { - (void)fprintf(stderr, "bad mask (%s)\n", s); + fprintf(stderr, "%d: bad mask (%s)\n", + linenum, s); return -1; } *msk = maskaddr.s_addr; @@ -592,7 +742,8 @@ */ bits = (int)strtol(s, &endptr, 0); if (*endptr != '\0' || bits > 32 || bits < 0) { - (void)fprintf(stderr, "bad mask (/%s)\n", s); + fprintf(stderr, "%d: bad mask (/%s)\n", + linenum, s); return -1; } if (bits == 0) @@ -600,48 +751,48 @@ else *msk = htonl(0xffffffff << (32 - bits)); } - *sa = hostnum(**seg, &resolved) & *msk; + *sa = hostnum(**seg, &resolved, linenum) & *msk; if (resolved == -1) { - (void)fprintf(stderr, "bad host (%s)\n", **seg); + fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg); return -1; } (*seg)++; - return ports(seg, pp, cp, tp); + return ports(seg, pp, cp, tp, linenum); } /* * look for extra segments if "mask" found in right spot */ if (*(*seg+1) && *(*seg+2) && !strcasecmp(*(*seg+1), "mask")) { - *sa = hostnum(**seg, &resolved); + *sa = hostnum(**seg, &resolved, linenum); if (resolved == -1) { - (void)fprintf(stderr, "bad host (%s)\n", **seg); + fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg); return -1; } (*seg)++; (*seg)++; if (inet_aton(**seg, &maskaddr) == 0) { - (void)fprintf(stderr, "bad mask (%s)\n", **seg); + fprintf(stderr, "%d: bad mask (%s)\n", linenum, **seg); return -1; } *msk = maskaddr.s_addr; (*seg)++; *sa &= *msk; - return ports(seg, pp, cp, tp); + return ports(seg, pp, cp, tp, linenum); } if (**seg) { - *sa = hostnum(**seg, &resolved); + *sa = hostnum(**seg, &resolved, linenum); if (resolved == -1) { - (void)fprintf(stderr, "bad host (%s)\n", **seg); + fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg); return -1; } (*seg)++; *msk = (*sa ? inet_addr("255.255.255.255") : 0L); *sa &= *msk; - return ports(seg, pp, cp, tp); + return ports(seg, pp, cp, tp, linenum); } - (void)fprintf(stderr, "bad host (%s)\n", **seg); + fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg); return -1; } @@ -649,26 +800,38 @@ * returns an ip address as a long var as a result of either a DNS lookup or * straight inet_addr() call */ -u_32_t hostnum(host, resolved) +u_32_t hostnum(host, resolved, linenum) char *host; int *resolved; +int linenum; { struct hostent *hp; struct netent *np; - struct in_addr addr; + struct in_addr ip; +#if defined(__OpenBSD__) + struct in_addr addr; +#endif *resolved = 0; if (!strcasecmp("any", host)) - return 0L; - if (inet_aton(host, &addr)) - return addr.s_addr; + return 0; + if (isdigit(*host) && inet_aton(host, &ip)) + return ip.s_addr; + if (!strcasecmp("", host)) host = thishost; +#if defined(__OpenBSD__) + /* attempt a map from interface name to address */ + if (if_addr(host, &addr)) + return (u_32_t)addr.s_addr; +#endif + if (!(hp = gethostbyname(host))) { if (!(np = getnetbyname(host))) { *resolved = -1; - fprintf(stderr, "can't resolve hostname: %s\n", host); + fprintf(stderr, "%d: can't resolve hostname: %s\n", + linenum, host); return 0; } return htonl(np->n_net); @@ -679,10 +842,11 @@ /* * check for possible presence of the port fields in the line */ -int ports(seg, pp, cp, tp) +int ports(seg, pp, cp, tp, linenum) char ***seg; u_short *pp, *tp; u_char *cp; +int linenum; { int comp = -1; @@ -691,7 +855,7 @@ if (!strcasecmp(**seg, "port") && *(*seg + 1) && *(*seg + 2)) { (*seg)++; if (isdigit(***seg) && *(*seg + 2)) { - if (portnum(**seg, pp) == 0) + if (portnum(**seg, pp, linenum) == 0) return -1; (*seg)++; if (!strcmp(**seg, "<>")) @@ -699,16 +863,18 @@ else if (!strcmp(**seg, "><")) comp = FR_INRANGE; else { - fprintf(stderr, "unknown range operator (%s)\n", - **seg); + fprintf(stderr, + "%d: unknown range operator (%s)\n", + linenum, **seg); return -1; } (*seg)++; if (**seg == NULL) { - fprintf(stderr, "missing 2nd port value\n"); + fprintf(stderr, "%d: missing 2nd port value\n", + linenum); return -1; } - if (portnum(**seg, tp) == 0) + if (portnum(**seg, tp, linenum) == 0) return -1; } else if (!strcmp(**seg, "=") || !strcasecmp(**seg, "eq")) comp = FR_EQUAL; @@ -723,13 +889,13 @@ else if (!strcmp(**seg, ">=") || !strcasecmp(**seg, "ge")) comp = FR_GREATERTE; else { - (void)fprintf(stderr, "unknown comparator (%s)\n", - **seg); + fprintf(stderr, "%d: unknown comparator (%s)\n", + linenum, **seg); return -1; } if (comp != FR_OUTRANGE && comp != FR_INRANGE) { (*seg)++; - if (portnum(**seg, pp) == 0) + if (portnum(**seg, pp, linenum) == 0) return -1; } *cp = comp; @@ -742,9 +908,10 @@ * find the port number given by the name, either from getservbyname() or * straight atoi(). Return 1 on success, 0 on failure */ -int portnum(name, port) +int portnum(name, port, linenum) char *name; u_short *port; +int linenum; { struct servent *sp, *sp2; u_short p1 = 0; @@ -754,7 +921,7 @@ *port = (u_short)i; return 1; } - (void)fprintf(stderr, "unknown port \"%s\"\n", name); + fprintf(stderr, "%d: unknown port \"%s\"\n", linenum, name); return 0; } if (proto != NULL && strcasecmp(proto, "tcp/udp") != 0) { @@ -763,7 +930,7 @@ *port = ntohs(sp->s_port); return 1; } - (void) fprintf(stderr, "unknown service \"%s\".\n", name); + fprintf(stderr, "%d: unknown service \"%s\".\n", linenum, name); return 0; } sp = getservbyname(name, "tcp"); @@ -771,14 +938,14 @@ p1 = sp->s_port; sp2 = getservbyname(name, "udp"); if (!sp || !sp2) { - (void) fprintf(stderr, "unknown tcp/udp service \"%s\".\n", - name); + fprintf(stderr, "%d: unknown tcp/udp service \"%s\".\n", + linenum, name); return 0; } if (p1 != sp2->s_port) { - (void) fprintf(stderr, "%s %d/tcp is a different port to ", - name, p1); - (void) fprintf(stderr, "%s %d/udp\n", name, sp->s_port); + fprintf(stderr, "%d: %s %d/tcp is a different port to ", + linenum, name, p1); + fprintf(stderr, "%d: %s %d/udp\n", linenum, name, sp->s_port); return 0; } *port = ntohs(p1); @@ -786,9 +953,10 @@ } -u_char tcp_flags(flgs, mask) +u_char tcp_flags(flgs, mask, linenum) char *flgs; u_char *mask; +int linenum; { u_char tcpf = 0, tcpfm = 0, *fp = &tcpf; char *s, *t; @@ -799,7 +967,7 @@ continue; } if (!(t = index(flagset, *s))) { - (void)fprintf(stderr, "unknown flag (%c)\n", *s); + fprintf(stderr, "%d: unknown flag (%c)\n", linenum, *s); return 0; } *fp |= flags[t - flagset]; @@ -814,9 +982,10 @@ /* * deal with extra bits on end of the line */ -int extras(cp, fr) +int extras(cp, fr, linenum) char ***cp; struct frentry *fr; +int linenum; { u_short secmsk; u_long opts; @@ -850,18 +1019,20 @@ goto nextopt; } else if (***cp == 'o' || ***cp == 'O') { if (!*(*cp + 1)) { - (void)fprintf(stderr, - "opt missing arguements\n"); + fprintf(stderr, + "%d: opt missing arguements\n", + linenum); return -1; } (*cp)++; - if (!(opts = optname(cp, &secmsk))) + if (!(opts = optname(cp, &secmsk, linenum))) return -1; oflags = FI_OPTIONS; } else if (***cp == 's' || ***cp == 'S') { if (fr->fr_tcpf) { - (void) fprintf(stderr, - "short cannot be used with TCP flags\n"); + fprintf(stderr, + "%d: short cannot be used with TCP flags\n", + linenum); return -1; } @@ -874,13 +1045,15 @@ if (!notopt || !opts) fr->fr_mip.fi_fl |= oflags; - if (notopt) - if (!secmsk) + if (notopt) { + if (!secmsk) { fr->fr_mip.fi_optmsk |= opts; - else + } else { fr->fr_mip.fi_optmsk |= (opts & ~0x0100); - else + } + } else { fr->fr_mip.fi_optmsk |= opts; + } fr->fr_mip.fi_secmsk |= secmsk; if (notopt) { @@ -903,9 +1076,10 @@ } -u_32_t optname(cp, sp) +u_32_t optname(cp, sp, linenum) char ***cp; u_short *sp; +int linenum; { struct ipopt_names *io, *so; u_long msk = 0; @@ -920,7 +1094,8 @@ break; } if (!io->on_name) { - fprintf(stderr, "unknown IP option name %s\n", s); + fprintf(stderr, "%d: unknown IP option name %s\n", + linenum, s); return 0; } if (!strcasecmp(s, "sec-class")) @@ -928,7 +1103,8 @@ } if (sec && !*(*cp + 1)) { - fprintf(stderr, "missing security level after sec-class\n"); + fprintf(stderr, "%d: missing security level after sec-class\n", + linenum); return 0; } @@ -941,8 +1117,9 @@ break; } if (!so->on_name) { - fprintf(stderr, "no such security level: %s\n", - s); + fprintf(stderr, + "%d: no such security level: %s\n", + linenum, s); return 0; } } @@ -954,13 +1131,14 @@ #ifdef __STDC__ -void optprint(u_short secmsk, u_short secbits, u_long optmsk, u_long optbits) +void optprint(u_short *sec, u_long optmsk, u_long optbits) #else -void optprint(secmsk, secbits, optmsk, optbits) -u_short secmsk, secbits; +void optprint(sec, optmsk, optbits) +u_short *sec; u_long optmsk, optbits; #endif { + u_short secmsk = sec[0], secbits = sec[1]; struct ipopt_names *io, *so; char *s; int secflag = 0; @@ -1036,9 +1214,10 @@ /* * set the icmp field to the correct type if "icmp" word is found */ -int addicmp(cp, fp) +int addicmp(cp, fp, linenum) char ***cp; struct frentry *fp; +int linenum; { char **t; int i; @@ -1050,8 +1229,9 @@ fp->fr_proto = IPPROTO_ICMP; if (isdigit(***cp)) { if (!ratoi(**cp, &i, 0, 255)) { - (void)fprintf(stderr, - "Invalid icmp-type (%s) specified\n", **cp); + fprintf(stderr, + "%d: Invalid icmp-type (%s) specified\n", + linenum, **cp); return -1; } } else { @@ -1066,8 +1246,9 @@ break; } if (i == -1) { - (void)fprintf(stderr, - "Invalid icmp-type (%s) specified\n", **cp); + fprintf(stderr, + "%d: Invalid icmp-type (%s) specified\n", + linenum, **cp); return -1; } } @@ -1082,8 +1263,9 @@ (*cp)++; if (isdigit(***cp)) { if (!ratoi(**cp, &i, 0, 255)) { - (void)fprintf(stderr, - "Invalid icmp code (%s) specified\n", **cp); + fprintf(stderr, + "%d: Invalid icmp code (%s) specified\n", + linenum, **cp); return -1; } fp->fr_icmp |= (u_short)i; @@ -1091,17 +1273,19 @@ (*cp)++; return 0; } - (void)fprintf(stderr, "Invalid icmp code (%s) specified\n", **cp); + fprintf(stderr, "%d: Invalid icmp code (%s) specified\n", + linenum, **cp); return -1; } -#define MAX_ICMPCODE 12 +#define MAX_ICMPCODE 15 char *icmpcodes[] = { "net-unr", "host-unr", "proto-unr", "port-unr", "needfrag", "srcfail", "net-unk", "host-unk", "isolate", "net-prohib", "host-prohib", - "net-tos", "host-tos", NULL }; + "net-tos", "host-tos", "filter-prohib", "host-preced", "preced-cutoff", + NULL }; /* * Return the number for the associated ICMP unreachable code. */ @@ -1132,20 +1316,28 @@ /* * set the icmp field to the correct type if "icmp" word is found */ -int addkeep(cp, fp) +int addkeep(cp, fp, linenum) char ***cp; struct frentry *fp; +int linenum; { if (fp->fr_proto != IPPROTO_TCP && fp->fr_proto != IPPROTO_UDP && fp->fr_proto != IPPROTO_ICMP && !(fp->fr_ip.fi_fl & FI_TCPUDP)) { - (void)fprintf(stderr, "Can only use keep with UDP/ICMP/TCP\n"); + fprintf(stderr, "%d: Can only use keep with UDP/ICMP/TCP\n", + linenum); return -1; } (*cp)++; + if (!**cp) { + fprintf(stderr, "%d: Missing state/frag after keep\n", + linenum); + return -1; + } + if (**cp && strcasecmp(**cp, "state") && strcasecmp(**cp, "frags")) { - (void)fprintf(stderr, "Unrecognised state keyword \"%s\"\n", - **cp); + fprintf(stderr, "%d: Unrecognised state keyword \"%s\"\n", + linenum, **cp); return -1; } @@ -1195,17 +1387,17 @@ struct servent *sv = NULL, *sv1 = NULL; if (pr == -1) { - if ((sv = getservbyport(port, "tcp"))) { + if ((sv = getservbyport(htons(port), "tcp"))) { strncpy(buf, sv->s_name, sizeof(buf)-1); buf[sizeof(buf)-1] = '\0'; - sv1 = getservbyport(port, "udp"); + sv1 = getservbyport(htons(port), "udp"); sv = strncasecmp(buf, sv->s_name, strlen(buf)) ? NULL : sv1; } if (sv) return buf; } else if (pr && (p = getprotobynumber(pr))) { - if ((sv = getservbyport(port, p->p_name))) { + if ((sv = getservbyport(htons(port), p->p_name))) { strncpy(buf, sv->s_name, sizeof(buf)-1); buf[sizeof(buf)-1] = '\0'; return buf; @@ -1229,141 +1421,137 @@ int ones = 0, pr; char *s; u_char *t; + u_short sec[2]; if (fp->fr_flags & FR_PASS) - (void)printf("pass"); + printf("pass"); else if (fp->fr_flags & FR_BLOCK) { - (void)printf("block"); + printf("block"); if (fp->fr_flags & FR_RETICMP) { - (void)printf(" return-icmp"); - if (fp->fr_icode) + if ((fp->fr_flags & FR_RETMASK) == FR_FAKEICMP) + printf(" return-icmp-as-dest"); + else if ((fp->fr_flags & FR_RETMASK) == FR_RETICMP) + printf(" return-icmp"); + if (fp->fr_icode) { if (fp->fr_icode <= MAX_ICMPCODE) printf("(%s)", icmpcodes[(int)fp->fr_icode]); else printf("(%d)", fp->fr_icode); - } - if (fp->fr_flags & FR_RETRST) - (void)printf(" return-rst"); + } + } else if ((fp->fr_flags & FR_RETMASK) == FR_RETRST) + printf(" return-rst"); } else if ((fp->fr_flags & FR_LOGMASK) == FR_LOG) { - (void)printf("log"); - if (fp->fr_flags & FR_LOGBODY) - (void)printf(" body"); - if (fp->fr_flags & FR_LOGFIRST) - (void)printf(" first"); + printlog(fp); } else if (fp->fr_flags & FR_ACCOUNT) - (void)printf("count"); + printf("count"); else if (fp->fr_flags & FR_AUTH) - (void)printf("auth"); + printf("auth"); else if (fp->fr_flags & FR_PREAUTH) - (void)printf("preauth"); + printf("preauth"); else if (fp->fr_skip) - (void)printf("skip %d", fp->fr_skip); + printf("skip %hu", fp->fr_skip); if (fp->fr_flags & FR_OUTQUE) - (void)printf(" out "); + printf(" out "); else - (void)printf(" in "); + printf(" in "); if (((fp->fr_flags & FR_LOGB) == FR_LOGB) || ((fp->fr_flags & FR_LOGP) == FR_LOGP)) { - (void)printf("log "); - if (fp->fr_flags & FR_LOGBODY) - (void)printf("body "); - if (fp->fr_flags & FR_LOGFIRST) - (void)printf("first "); - if (fp->fr_flags & FR_LOGORBLOCK) - (void)printf("or-block "); + printlog(fp); + putchar(' '); } if (fp->fr_flags & FR_QUICK) - (void)printf("quick "); + printf("quick "); if (*fp->fr_ifname) { - (void)printf("on %s%s ", fp->fr_ifname, + printf("on %s%s ", fp->fr_ifname, (fp->fr_ifa || (long)fp->fr_ifa == -1) ? "" : "(!)"); if (*fp->fr_dif.fd_ifname) print_toif("dup-to", &fp->fr_dif); if (*fp->fr_tif.fd_ifname) print_toif("to", &fp->fr_tif); if (fp->fr_flags & FR_FASTROUTE) - (void)printf("fastroute "); + printf("fastroute "); } if (fp->fr_mip.fi_tos) - (void)printf("tos %#x ", fp->fr_tos); + printf("tos %#x ", fp->fr_tos); if (fp->fr_mip.fi_ttl) - (void)printf("ttl %d ", fp->fr_ttl); + printf("ttl %d ", fp->fr_ttl); if (fp->fr_ip.fi_fl & FI_TCPUDP) { - (void)printf("proto tcp/udp "); + printf("proto tcp/udp "); pr = -1; } else if ((pr = fp->fr_mip.fi_p)) { if ((p = getprotobynumber(fp->fr_proto))) - (void)printf("proto %s ", p->p_name); + printf("proto %s ", p->p_name); else - (void)printf("proto %d ", fp->fr_proto); + printf("proto %d ", fp->fr_proto); } printf("from %s", fp->fr_flags & FR_NOTSRCIP ? "!" : ""); - if (!fp->fr_src.s_addr & !fp->fr_smsk.s_addr) - (void)printf("any "); + if (!fp->fr_src.s_addr && !fp->fr_smsk.s_addr) + printf("any "); else { - (void)printf("%s", inet_ntoa(fp->fr_src)); + printf("%s", inet_ntoa(fp->fr_src)); if ((ones = countbits(fp->fr_smsk.s_addr)) == -1) - (void)printf("/%s ", inet_ntoa(fp->fr_smsk)); + printf("/%s ", inet_ntoa(fp->fr_smsk)); else - (void)printf("/%d ", ones); + printf("/%d ", ones); } - if (fp->fr_scmp) + if (fp->fr_scmp) { if (fp->fr_scmp == FR_INRANGE || fp->fr_scmp == FR_OUTRANGE) - (void)printf("port %d %s %d ", fp->fr_sport, + printf("port %d %s %d ", fp->fr_sport, pcmp1[fp->fr_scmp], fp->fr_stop); else - (void)printf("port %s %s ", pcmp1[fp->fr_scmp], + printf("port %s %s ", pcmp1[fp->fr_scmp], portname(pr, fp->fr_sport)); + } printf("to %s", fp->fr_flags & FR_NOTDSTIP ? "!" : ""); - if (!fp->fr_dst.s_addr & !fp->fr_dmsk.s_addr) - (void)printf("any"); + if (!fp->fr_dst.s_addr && !fp->fr_dmsk.s_addr) + printf("any"); else { - (void)printf("%s", inet_ntoa(fp->fr_dst)); + printf("%s", inet_ntoa(fp->fr_dst)); if ((ones = countbits(fp->fr_dmsk.s_addr)) == -1) - (void)printf("/%s", inet_ntoa(fp->fr_dmsk)); + printf("/%s", inet_ntoa(fp->fr_dmsk)); else - (void)printf("/%d", ones); + printf("/%d", ones); } if (fp->fr_dcmp) { if (fp->fr_dcmp == FR_INRANGE || fp->fr_dcmp == FR_OUTRANGE) - (void)printf(" port %d %s %d", fp->fr_dport, + printf(" port %d %s %d", fp->fr_dport, pcmp1[fp->fr_dcmp], fp->fr_dtop); else - (void)printf(" port %s %s", pcmp1[fp->fr_dcmp], + printf(" port %s %s", pcmp1[fp->fr_dcmp], portname(pr, fp->fr_dport)); } if ((fp->fr_ip.fi_fl & ~FI_TCPUDP) || (fp->fr_mip.fi_fl & ~FI_TCPUDP) || fp->fr_ip.fi_optmsk || fp->fr_mip.fi_optmsk || fp->fr_ip.fi_secmsk || fp->fr_mip.fi_secmsk) { - (void)printf(" with"); + printf(" with"); if (fp->fr_ip.fi_optmsk || fp->fr_mip.fi_optmsk || - fp->fr_ip.fi_secmsk || fp->fr_mip.fi_secmsk) - optprint(fp->fr_mip.fi_secmsk, - fp->fr_ip.fi_secmsk, - fp->fr_mip.fi_optmsk, - fp->fr_ip.fi_optmsk); - else if (fp->fr_mip.fi_fl & FI_OPTIONS) { + fp->fr_ip.fi_secmsk || fp->fr_mip.fi_secmsk) { + sec[0] = fp->fr_mip.fi_secmsk; + sec[1] = fp->fr_ip.fi_secmsk; + optprint(sec, + fp->fr_mip.fi_optmsk, fp->fr_ip.fi_optmsk); + } else if (fp->fr_mip.fi_fl & FI_OPTIONS) { if (!(fp->fr_ip.fi_fl & FI_OPTIONS)) - (void)printf(" not"); - (void)printf(" ipopt"); + printf(" not"); + printf(" ipopt"); } if (fp->fr_mip.fi_fl & FI_SHORT) { if (!(fp->fr_ip.fi_fl & FI_SHORT)) - (void)printf(" not"); - (void)printf(" short"); + printf(" not"); + printf(" short"); } if (fp->fr_mip.fi_fl & FI_FRAG) { if (!(fp->fr_ip.fi_fl & FI_FRAG)) - (void)printf(" not"); - (void)printf(" frag"); + printf(" not"); + printf(" frag"); } } if (fp->fr_proto == IPPROTO_ICMP && fp->fr_icmpm) { @@ -1372,16 +1560,16 @@ type = ntohs(fp->fr_icmp); code = type & 0xff; type /= 256; - if (type < (sizeof(icmptypes) / sizeof(char *)) && + if (type < (sizeof(icmptypes) / sizeof(char *) - 1) && icmptypes[type]) - (void)printf(" icmp-type %s", icmptypes[type]); + printf(" icmp-type %s", icmptypes[type]); else - (void)printf(" icmp-type %d", type); + printf(" icmp-type %d", type); if (code) - (void)printf(" code %d", code); + printf(" code %d", code); } if (fp->fr_proto == IPPROTO_TCP && (fp->fr_tcpf || fp->fr_tcpfm)) { - (void)printf(" flags "); + printf(" flags "); for (s = flagset, t = flags; *s; s++, t++) if (fp->fr_tcpf & *t) (void)putchar(*s); @@ -1412,14 +1600,45 @@ for (s = (u_char *)fp; i; i--, s++) { j++; - (void)printf("%02x ", *s); + printf("%02x ", *s); if (j == 16) { - (void)printf("\n"); + printf("\n"); j = 0; } } putchar('\n'); (void)fflush(stdout); +} + + +void printlog(fp) +frentry_t *fp; +{ + char *s, *u; + + printf("log"); + if (fp->fr_flags & FR_LOGBODY) + printf(" body"); + if (fp->fr_flags & FR_LOGFIRST) + printf(" first"); + if (fp->fr_flags & FR_LOGORBLOCK) + printf(" or-block"); + if (fp->fr_loglevel != 0xffff) { + printf(" level "); + if (fp->fr_loglevel & LOG_FACMASK) { + s = fac_toname(fp->fr_loglevel); + if (s == NULL) + s = "!!!"; + } else + s = ""; + u = pri_toname(fp->fr_loglevel); + if (u == NULL) + u = "!!!"; + if (*s) + printf("%s.%s", s, u); + else + printf("%s", u); + } } Index: sbin/ipf/facpri.h =================================================================== RCS file: facpri.h diff -N facpri.h --- /dev/null Wed May 24 17:02:20 2000 +++ sbin/ipf/facpri.h Wed May 24 17:46:36 2000 @@ -0,0 +1,44 @@ +/* $OpenBSD: facpri.h,v 1.4 2000/03/13 23:40:19 kjell Exp $ */ + +/* + * Copyright (C) 1999 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. + * $IPFilter: facpri.h,v 1.2 1999/08/01 11:10:46 darrenr Exp $ + */ + +#ifndef __FACPRI_H__ +#define __FACPRI_H__ + +#ifndef __P +# define P_DEF +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif + +extern char *fac_toname __P((int)); +extern int fac_findname __P((char *)); + +extern char *pri_toname __P((int)); +extern int pri_findname __P((char *)); + +#ifdef P_DEF +# undef __P +# undef P_DEF +#endif + +#if LOG_CRON == (9<<3) +# define LOG_CRON1 LOG_CRON +# define LOG_CRON2 (15<<3) +#endif +#if LOG_CRON == (15<<3) +# define LOG_CRON1 (9<<3) +# define LOG_CRON2 LOG_CRON +#endif + +#endif /* __FACPRI_H__ */ Index: sbin/ipf/facpri.c =================================================================== RCS file: facpri.c diff -N facpri.c --- /dev/null Wed May 24 17:02:20 2000 +++ sbin/ipf/facpri.c Wed May 24 17:46:36 2000 @@ -0,0 +1,148 @@ +/* $OpenBSD: facpri.c,v 1.4 2000/03/13 23:40:19 kjell Exp $ */ + +/* + * Copyright (C) 1993-1998 by Darren Reed. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and due credit is given + * to the original author and the contributors. + */ +#include +#include +#include +#include +#if !defined(__SVR4) && !defined(__svr4__) +#include +#endif +#include +#include +#include +#include +#include "facpri.h" + +#if !defined(lint) +static const char rcsid[] = "@(#)$IPFilter: facpri.c,v 1.2 1999/08/01 11:10:45 darrenr Exp $"; +#endif + +typedef struct table { + char *name; + int value; +} table_t; + +table_t facs[] = { + { "kern", LOG_KERN }, { "user", LOG_USER }, + { "mail", LOG_MAIL }, { "daemon", LOG_DAEMON }, + { "auth", LOG_AUTH }, { "syslog", LOG_SYSLOG }, + { "lpr", LOG_LPR }, { "news", LOG_NEWS }, + { "uucp", LOG_UUCP }, +#if LOG_CRON == LOG_CRON2 + { "cron2", LOG_CRON1 }, +#else + { "cron", LOG_CRON1 }, +#endif +#ifdef LOG_FTP + { "ftp", LOG_FTP }, +#endif +#ifdef LOG_AUTHPRIV + { "authpriv", LOG_AUTHPRIV }, +#endif +#ifdef LOG_AUDIT + { "audit", LOG_AUDIT }, +#endif +#ifdef LOG_LFMT + { "logalert", LOG_LFMT }, +#endif +#if LOG_CRON == LOG_CRON1 + { "cron", LOG_CRON2 }, +#else + { "cron2", LOG_CRON2 }, +#endif + { "local0", LOG_LOCAL0 }, { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, { "local7", LOG_LOCAL7 }, + { NULL, 0 } +}; + + +/* + * map a facility number to its name + */ +char * +fac_toname(facpri) + int facpri; +{ + int i, j, fac; + + fac = facpri & LOG_FACMASK; + j = fac >> 3; + if (j < 24) { + if (facs[j].value == fac) + return facs[j].name; + for (i = 0; facs[i].name; i++) + if (fac == facs[i].value) + return facs[i].name; + } + + return NULL; +} + + +/* + * map a facility name to its number + */ +int +fac_findname(name) + char *name; +{ + int i; + + for (i = 0; facs[i].name; i++) + if (!strcmp(facs[i].name, name)) + return facs[i].value; + return -1; +} + + +table_t pris[] = { + { "emerg", LOG_EMERG }, { "alert", LOG_ALERT }, + { "crit", LOG_CRIT }, { "err", LOG_ERR }, + { "warn", LOG_WARNING }, { "notice", LOG_NOTICE }, + { "info", LOG_INFO }, { "debug", LOG_DEBUG }, + { NULL, 0 } +}; + + +/* + * map a priority name to its number + */ +int +pri_findname(name) + char *name; +{ + int i; + + for (i = 0; pris[i].name; i++) + if (!strcmp(pris[i].name, name)) + return pris[i].value; + return -1; +} + + +/* + * map a priority number to its name + */ +char * +pri_toname(facpri) + int facpri; +{ + int i, pri; + + pri = facpri & LOG_PRIMASK; + if (pris[pri].value == pri) + return pris[pri].name; + for (i = 0; pris[i].name; i++) + if (pri == pris[i].value) + return pris[i].name; + return NULL; +} Index: sbin/ipf/ifaddr.c =================================================================== RCS file: ifaddr.c diff -N ifaddr.c --- /dev/null Wed May 24 17:02:20 2000 +++ sbin/ipf/ifaddr.c Wed May 24 17:46:36 2000 @@ -0,0 +1,76 @@ +/* $OpenBSD: ifaddr.c,v 1.5 2000/04/05 05:35:28 kjell Exp $ */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "ifaddr.h" + + +/* + * if_addr(): + * given a string containing an interface name (e.g. "ppp0") + * return the IP address it represents + * + * The OpenBSD community considers this feature to be quite useful and + * suggests inclusion into other platforms. The closest alternative is + * to define /etc/networks with suitable values. + */ +int if_addr(name, ap) +char *name; +struct in_addr *ap; +{ + struct ifconf ifc; + struct ifreq ifreq, *ifr; + char *inbuf = NULL; + int s, i, len = 8192; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + warn("socket"); + return 0; + } + + while (1) { + ifc.ifc_len = len; + ifc.ifc_buf = inbuf = realloc(inbuf, len); + if (inbuf == NULL) + err(1, "malloc"); + if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { + warn("SIOCGIFCONF"); + goto if_addr_lose; + } + if (ifc.ifc_len + sizeof(ifreq) < len) + break; + len *= 2; + } + ifr = ifc.ifc_req; + ifreq.ifr_name[0] = '\0'; + for (i = 0; i < ifc.ifc_len; ) { + ifr = (struct ifreq *)((caddr_t)ifc.ifc_req + i); + i += sizeof(ifr->ifr_name) + + (ifr->ifr_addr.sa_len > sizeof(struct sockaddr) + ? ifr->ifr_addr.sa_len + : sizeof(struct sockaddr)); + ifreq = *ifr; + if (ioctl(s, SIOCGIFADDR, (caddr_t)ifr) < 0) + continue; + if (ifr->ifr_addr.sa_family != AF_INET) + continue; + if (!strcmp(name, ifr->ifr_name)) { + struct sockaddr_in *sin; + close(s); + free(inbuf); + sin = (struct sockaddr_in *)&ifr->ifr_addr; + *ap = sin->sin_addr; + return (1); + } + } + +if_addr_lose: + close(s); + free(inbuf); + return 0; +} Index: sbin/ipf/ifaddr.h =================================================================== RCS file: ifaddr.h diff -N ifaddr.h --- /dev/null Wed May 24 17:02:20 2000 +++ sbin/ipf/ifaddr.h Wed May 24 17:46:36 2000 @@ -0,0 +1,8 @@ +/* $OpenBSD: ifaddr.h,v 1.5 2000/04/05 05:35:28 kjell Exp $ */ + +#ifndef __IFADDR_H__ +#define __IFADDR_H__ + +int if_addr __P((char *, struct in_addr *)); + +#endif Index: sbin/ipf/HISTORY =================================================================== RCS file: HISTORY diff -N HISTORY --- /dev/null Wed May 24 17:02:20 2000 +++ sbin/ipf/HISTORY Wed May 24 17:46:36 2000 @@ -0,0 +1,1462 @@ +# $OpenBSD: HISTORY,v 1.8 2000/05/24 21:59:11 kjell Exp $ +# +# NOTE: Quite a few patches and suggestions come from other sources, to whom +# I'm greatly indebted, even if no names are mentioned. +# +# Thanks to the Coombs Computing Unit at the ANU for their continued support +# in providing a very available location for the IP Filter home page and +# distribution center. +# +# Thanks to Tel.Net Media for allowing me to maintain and further develop +# IP Filter as part of my job and supplying Sun equipment for testing the +# move to 64bits and Gigabit Ethernet. +# +# Thanks to BSDI for providing object files for BSD/OS 3.1 and the means +# to further support development of IP Filter under BSDI. +# +# Thanks to Craig Bishop of connect.com.au and Sun Microsystems for the +# loan of a machine to work on a Solaris 2.x port of this software. +# +# Thanks also to all those who have contributed patches and other code, +# and especially those who have found the time to port IP Filter to new +# platforms. +# +3.3.16 23/05/2000 - Released + +don't add TCP state if it is an RST packet and (attempt) to send out +RST/ICMP packets in a manner that bypasses IP Filter. + +add patch to work with 4.0_STABLE delayed checksums + +3.3.15 20/05/2000 - Released + +fix destination being 0/32 in NAT map rules + +fix ipmon -F + +3.3.14 10/05/2000 - Released + +Fix bug in dealing with "hlen == 1 and opt > 1" - Itojun + +ignore previous NAT mappings for 0/0 and 0/32 rules + +struct friostat got too big for SunOS4 + +3.3.13 26/04/2000 - Released + +Fix parsing of "range" with "portmap" + +Relax checking of ftp replies, slightly. + +Fix NAT timeouts for ICMP packets + +SunOS4 patches for ICMP redirects from Jurgen Keil (jk@tools.de) + +3.3.12 16/03/2000 - Released + +tighten up ftp proxy behaviour. sigh. yuck. hate. + +fix bug in range check for NAT where the last IP# was not used. + +fix problem with icmp codes > 127 in filter rules caused bad things to +happen and in particular, where #18 caused the rule to be printed +erroneously. + +fix bug with the spl level not being reset when returning EIO from +iplioctl due to ipfilter not being initialized yet. + +3.3.11 04/03/2000 - Released + +make "or-block" work with lines that start with "log" + +fix up parsing and printing of rules with syslog levels in them + +fix from Cy Schubert for calling of apr_fini only if non-null + +3.3.10 24/02/2000 - Released + +* fix back from guido for state tracking interfaces + +* update for NetBSD pfil interface changes + +* if attaching fails and we can abort, then cleanup when doing so. + +Julian Yip (julian@computer.org): +* solaris.c (fr_precheck): After calling freemsg on mt, set it point to *mp. +* ipf.c (packetlogon): use flag to store the return value from get_flags. +* ipmon.c (init_tabs): Generate cleanup so we do not have to cast + an int s->s_port to u_int port and try to check if the u_int port + is less than zero. + +3.3.9 15/02/2000 - Released + +fix scheduling of bad locking in fr_addstate() used when we attach onto +a filter rule. + +fix up ip_statesync() with storing interface names in ipstate_t + +fix fr_running for LKM's - Eugene Polovnikov + +junk using pullupmsg() for solaris - it's next to useless for what we +need to do here anyway - and implement what we require. + +don't call fr_delstate() in fr_checkstate(), when compiled for a user +program, early but when we're finished with it (got fr & pass) + +ipnat(5) fix from Guido + +on solaris2, copy message and use that with filter if there is another +copy if it being used (db_ref > 1). bad for performance, but better +than causing a crash. + +patch for solaris8-fcs compile from Casper Dik + +3.3.8 01/02/2000 - Released + +fix state handling of SYN packets. + +add parsing recognition of extra icmp types/codes and fix handling of +icmp time stamps and mask requests - Frank volf + +3.3.7 25/01/2000 - Released + +sync on state information as well as NAT information when required + +record nat protocol in all nat log records + +don't reuse the IP# from an active NAT session if the IP# in the rule +has changed dynamically. + +lookup the protocol for NAT log information in ipmon and pass that to +portname. + +fix the bug with changing the outbound interface of a packet where it +would lead to a panic. + +use fr_running instead of ipl_inited. (sysctl name change on freebsd) + +return EIO if someone attempts an ioctl on state/nat if ipfilter is not +enabled. + +fix rule insertion bug + +make state flushing clean anything that's not fully established (4/4) + +call fr_state_flush() after we've released ipf_state so we don't generate +a recursive mutex acquisition panic + +fix parsing of icmp code after return-icmp/return-icmp-as-dest and add +some patches to enhance parsing strength + +3.3.6 28/12/1999 - Released + +add in missing rwlock release in fr_checkicmpmatchingstate() and fix check +for ICMP_ECHO to only be for packet, not state entry which we don't have yet. + +handle SIOCIPFFB in nat_ioctl() and fr_state_ioctl() + +fix size of friostat for SunOS4 + +fix bug in running off the end of a buffer in real audio proxy + +3.3.5 11/12/1999 - Released + +fix parsing of "log level" and printing it back out too + + is only present on Solaris2.6/7/8 + +use send_icmp_err rather than icmp_error to send back a frag-needed error +when doing PMTU + +do not use -b with add_drv on Solaris unless $BASEDIR is set. + +fix problem where source address in icmp replies is reversed + +fix yet another problem with real audio. + +3.3.4 4/12/1999 - Released + +patches from Guido: fix panic in ip_state:fr_checkicmpmatchingstate(), fix +byte order problem in ip_id (host order when called from ip_input(), vs +network byte order when called from ip_output()) and fix a problem where the +fragment cache was never timedout early. + +fix up the real audio proxy to properly setup state information and NAT +entries, thanks to Laine Stump for testing/advice/fixes. + +fix ipfr_fastroute to set dst->sin_addr (Sean Farley - appears to prevent +FreeBSD 3.3 from panic'ing) as this had been removed in prior hacks to this +routine. + +fix kinstall for BSDI + +support ICMP errors being allowed through for ICMP packets going out with +keep state enabled + +support hardware checksumming (gigabit ethernet cards) on Solaris thanks to +Tel.Net Media for providing hardware for testing. + +patched from Frank Volf for ipmon (ICMP & fragmented packets) and allowing +ICMP responses to ICMP packets in the keep state table. + +add in patches for hardware checksumming under solaris + +Solaris install scripts now use $BASEDIR as appropriate. + +add Solaris8 support + +fix "ipf -y" on solaris so that it rescans rules also for changes in +interface pointers + +let ipmon become a daemon with -D if it is using syslog + +fix parsing of return-icmp-as-dest(foo) + +add reference to ipfstat -g to ipfstat.8 + +ipf_mutex needs to be declared for irix in ip_fil.c + +3.3.3 22/10/1999 - Released + +add -g command line option to ipfstat to show groups still define. + +fix problem with fragment table not recording rule pointer when called +from state functions (fin_fr not set). + +fixup fastroute problems with keep state rules. + +load rules into inactive set first, so we don't disable things like NIS +lookups half way through processing - found by Kevin Littlejohn + +fix handling of unaligned ip pointer for solaris + +patch for fr_newauth from Rudi Sluijtman + +fixed htons() bug in fr_tcpsum() where ip_p wasn't cast to u_short + +3.3.2 23/09/1999 - Released + +patches from Scott Presnell to fix rcmd proxy + +patches from Greg to fix Solaris detachment of interfaces + +add openbsd compatibility fixes + +fix free'ing already freed memory in ipfr_slowtimer() + +fix for deferencing invalid memory in cleaning up after a device disappears + +3.3.1 14/8/1999 - Released + +remove include file sys/user.h for irix + +prevent people from running buildsunos directly + +fix up some problems with the saving of rule pointers so that NAT saves +that information in case it should need to call fr_addstate() from a proxy. + +fix up scanning for the end of FTP messages + +don't remove /etc/opt/ipf in postremove + +attempt to prevent people running buildsolaris script without doing a +"make solaris" + +fix timeout losing on freebsd3 + +3.3 7/8/1999 - Released + +NAT: information (rules, mappings) are stored in hash tables; setup some +basic NAT regression testing. + +display version name of installed kernel code when initializing. + +add -V command line option to ipf, showing version (program and kernel +module) as well as the run-status of the kernel code. + +fix problem with "log" rules actually affecting result of filtering. + +automatically use SUNWspro if available and on a 64bit Solaris system for +compiling. + +add kernel proxies for rcmd(3) and RealAudio (PNA) + +use timeout/untimeout on SunOS4/BSD platforms too rather than hijacking +ip_slowtimo + +fix IP headers generated through parsing of text information + +fix NAT rules to be in the correct order again. + +make keep-state work with to/fastroute keywords and enforce usage of those +interfaces. + +update keep-state code with new algorithm from Guido + +add FreeBSD-3 support + +add return-icmp-as-dest option to retrun an ICMP packet using the original +destination as the source rather than a local IP address + +add "level [facility.]" option to filter language + +add changes from Guido to state code. + +add code to return EPERM if the device is opened for writing and we're +in securelevel 2 or greater. + +authentication code patches from Guido + +fix real audio proxy + +fix ipmon rule printing of interfaces and add IN/OUT to the end of ipmon +log output. + +fix bimap rules with hash tables + +update addresses used in NAT mappings for 0/32 rules for any protocol but TCP +if it changes on the interface - check every ip_natexpire() + +add redirect regression test + +count buckets used in the state hash table. + +fix sending of RST's with return-rst to use the ack number provided in +the packet being replied to in addition to the sequence number. + +fix to compile as a 64bit application on solaris7-64bit + +add NAT IP mapping to ranges of IP addresses that aren't CIDR specified + +fix calculation of in_space parameter for NAT + +fix `wrapping' when incrementing the next ip address for use in NAT + +fix free'ing of kernel memory in ip_natunload on solaris + +fix -l/-U command line options from interfering with each other + +fix fastroute under solaris2 and cleanup compilation for solaris7 + +add install scripts and compile cleanly on BSD/OS 4.0 + +safely open files in /tmp for writing device output when testing. + +fix uninitialized pointer bug in NAT + +fix SIOCZRLST (zero list rule stats) bug with groups + +change some usage of u_short to u_int in function calling + +fix compilation for Solaris7 (SUNWspro) + +change solaris makefiles to build for either sparc or i386 rather than +per-cpu (sun4u, etc). + +fixed bug in ipllog + +add patches from George Michaelson for FreeBSD 3.0 + +add patch from Guido to provide ICMP checking for known state in the same +manner as is done for NAT. + +enable FTP PASV proxying and enable wildcarding in NAT/state code for ports +for better PORT/PASV support with FTP. + +bring into main tree static nat features: map-block and "auto" portmapping. + +add in source host filtering for redirects (alan jones) + +3.2.10 22/11/98 - Released + +3.2.10beta9 17/11/98 - Released + +fix fr_tcpsum problems in handling mbufs with an odd number of bytes +and/or split across an mbuf boundary + +fix NAT list entry comparisons and allow multiple entries for the same +proxy (but on different ports). + +don't create duplicate NAT entries for repeated PORT commands. + +3.2.10beta8 14/11/98 - Released + +always exit an rwlock before expecting to enter it again on solaris + +fix loop in nat_new for pre-existing nat + +don't setup state for an ftp connection if creating nat fails. + +3.2.10beta7 05/11/98 - Released + +set fake window in ipft_tx.c to ensure code passes tests. + +cleaned up/enhanced ipnat -l/ipnat -lv output + +fixed NAT handling of non-TCP/UDP packets, esp. for ICMP errors returned. + +Solaris recusive mutex on icmp-error/tcp-reset - requires rwlock's rather +than mutexes. + +3.2.10beta6 03/11/98 - Released + +fix mixed use of krwlock_t and kmutex_t on Solaris2 + +fix FTP proxy back up, splitting pasv code out of port code. + +3.2.10beta5 02/11/98 - Released + +fixed port translation in ICMP reply handling + +3.2.10beta4 01/11/98 - Released + +increase useful statistic collection on solaris + +filter DL_UNITDATA_REQ as well as DL_UNITDATA_IND on solaris + +disable PASV reply translation for now + +fail with an error if we try to load a NAT rule with a non-existant + proxy name - Guido + +fix portmap usage with 0/0 and 0/32 map rules + +remove ap_unload/ap_expire - automatically done when NAT is cleaned up + +print "STATE:CLOSED" from ipmon if the connection progresses past established + rather than "STATE:EXPIRED" + +3.2.10beta3 26/10/98 - Released + +fixed traceroute/nat problem + +rewrote nat/proxy interface + +ipnat now lists associated proxy sessions for each NAT where applicable + +3.2.10beta2 13/10/98 - Released + +use KRWLOCK_T in place of krwlock_t for solaris as well as irix + +disable use of read-write lock acquisition by default + +add in mb_t for linux, non-kernel + +some changes to progress compilation on linux with glibc + +change PASV as well as PORT when passed through kernel ftp proxy. + +don't allow window to become 0 in tcp state code + +make ipmon compile cleaner + +irix patches + +3.2.10beta 11/09/98 - Released + +stop fr_tcpsum() thinking it has run out of data when it hasn't. + +stop solaris panics due to fin_dp being something wild. + +revisit usage of ATOMIC_*() + +log closing state of TCP connection in "keep state" + +fix fake-arp table code for ipsend. + +ipmon now writes pid to a file. + +fix "ipmon -a" to actually activate all logging devices. + +add patches for BSDOS4. + +perl scripts for log analysis donated. + +3.2.9 22/06/98 - Released + +fix byte order for ICMP packets generated on Solaris + +fix some locking problems. + +fix malloc bug in NAT (introduced in 3.2.8). + +patch from guido for state connections that get fragmented + +3.2.8 08/06/98 - Released + +use readers/writers locks in Solaris2 in place of some mutexes. + +Solaris2 installation enhancements - Martin Forssen (maf@carlstedt.se) + +3.2.7 24/05/98 - Released + +u_long -> u_32_t conversions + +patches from Bernd Ernesti for NetBSD + +fixup ipmon to actually handle HUP's. + +Linux fixes from Michael H. Warfield (mhw@wittsend.com) + +update for keep state patch (not security related) - Guido + +dumphex() uses stdout rather than log + +3.2.6 18/05/98 - Released + +fix potential security loop hole in keep state code. + +update examples. + +3.2.5 09/05/98 - Released + +BSD/OS 3.1 .o files added for the kernel. + +fix sequence # skew vs window size check. + +fix minimum ICMP header size check. + +remove references to Cybersource. + +fix my email address. + +remove ntohl in ipnat - Thomas Tornblom + +3.2.4 09/04/98 - Released + +add script to make devices for /dev on BSD boxes + +fixup building into the kernel for FreeBSD 2.2.5 + +add -D command line option to ipmon to make it a daemon and SIGHUP causes +it to close and reopen the logfile + +fixup make clean and make package for SunOS5 - Marc Boucher + +postinstall keeps adding "minor=ipf ipl" - George Ross + +protected by IP Filter gif - Sergey Solyanik + +3.2.3 10/11/97 - Released + +fix some iplang bugs + +fix tcp checksum data overrun, sgi #define changes, +avoid infinite loop when nat'ing to single IP# - Marc Boucher + +fixup DEVFS usage for FreeBSD + +fix sunos5 "make clean" cleaning up too much + +3.2.2 28/11/97 - Released + +change packet matching to return actual error, if bad packet, to facilitate +ECONNRESET for TCP. + +allow ip:netmask in grammar too now - Guido + +assume IRIX has u_int32_t in sys/types.h (needed for R10000) + +rewrite parts of command line options for ipmon + +fix TCP urgent packet & offset testing and add LAND attack test for iptest + +fix grammar error in yacc grammar for iplang + +redirect (rdr) destination port bytes-wapped when it shouldn't be. + +general: fr_check now returns error code, such as EHOSTUNREACH or +ECONNRESET (attempt to make ECONNRESET work for locally outbound +packets). + +linux: enable return-rst, need to filter tcp retransmits which are sent + separately from normal packets + +memory leak plugged in ip_proxy.c + +BSDI compatibility patches from Guido + +tcp checksum fix - Marc Boucher + +recursive mutex and ioctl param fix - Marc Boucher + +3.2.1 12/11/97 - Released + +port to BSD/OS 3.0 + +port to Linux 2.0.31 + +patches to make "map a/m -> 0/0" work with ftp proxying properly - Marc Boucher + +add "ipf -F s" and "ipf -F S" to flush state table entries. + +announce if logging is on or off when ip filter initializes. + +"ipf -F a" doesn't flush groups properly for Solaris. + +3.2 30/10/97 - Released + +ipnat doesn't successfully remove proxy mappings with "-rf" - +Alexander Romanyu + +use K&R C function style for solaris kernel code + +use m_adj() to decrease packet size in ftp proxy + +use mbufchainlen rather than msgdsize, +IRIX update - Marc Boucher + +fix NetBSD modunload bug (pfil_add_hook done twice) + +patches for OpenBSD 2.1 - Craig Bevins + +3.2beta10 24/10/97 - Released + +fix fragment table entries allocated for NAT. + +fix tcp checksum calculations over mbuf/mblk boundaries + +fix panic for blen < 0 in ftp kernel proxy - marc boucher + +fix flushing of rules which have been grouped. + +3.2beta9 20/10/97 - Released + +some nit picking on solaris2 with SUNWspro - Michael Lyle + +ftp kernel proxy patches from Marc Boucher + +3.2beta8 13/10/97 - Released + +add support for passing ICMP errors back through NAT. + +IRIX port update - Marc Boucher + +calculate correct MIN size of packet to log for UDP - Marc Boucher + +need htons(ETHERTYPE_x) on little endian BSD boxes - Dave Huang + +copyright header fixups + +3.2beta7 23/09/97 - Released + +fickup problems introduced by prior merges & changes. + +3.2beta6 23/09/97 - Released + +patch for spin-reading race condition - Marc Boucher. + +IRIX port by Marc Boucher. + +compatibility updates for Linux to ipsend + +3.2beta5 13/09/97 - Released + +patches from Bernd Ernesti for NetBSD integration (mostly prototyping and +compiler warning things) + +ipf -y will resync IP#'s allocated with 0/32 in NAT to match interface if it +changes. + +update manual pages and other documentation updates. + +3.2beta4 27/8/97 - Released + +enable setting IP and TCP options for iplang/ + +Solaris2 patches from Marc Boucher. + +add groups for filter rules. + +3.2beta3 21/8/97 - Released + +patches for Solaris2 (interface panic solution ?): fix FIONREAD and +replacing q_qinfo points - Marc Boucher + +change ipsend/* and ipsd/* copyright notices to be the same as ip filter's + +patch for SYN-ACK skew testing fix from Eric V. Smith + +3.2beta2 6/8/97 - Released + +make it load on Solaris 2.3 + +rewrote logging to remove solaris errors, introduced checking to see if the +same packet is logged successively. + +fix filter cache to work when there are no rules loaded. + +add "raw" option to ipresend to send entire ethernet frames. + +nat list corruption bug - NetBSD - Klaus Klein + +3.2beta1 5/7/97 - Released + +patches from Jason Thorpe fixing: UNSIGNED_CHAR lossage, off_t being 64bits +lossage, and other NetBSD bits. + +NetBSD 1.2G update. + +fixup fwtk patches and add protocol field for SIOCGNATL. + +rdr bugs reported by Alexander Romanyu (alexr@aix.krid.crimea.ua), with +fixes: +* rdr matched all packets of a given protocol (ignored ports). +* severe bug in nat_delete which caused system crash/freeze. + +change Makefile so that CC isn't passed on for FreeBSD/NetBSD (will use +the default CC - cc, not gcc) + +3.2alpha9 16/6/97 - Released + +added "skip" keyword. + +implement preauthentication of packets, as outlined by Guido. + +Make it compile as cleanly as possible with -Wall & general code cleanup + +getopt returns int, not char. Bernd Ernesti + +3.2alpha8 13/6/97 - Released + +code added to support "auth" rules which require a user program to allow them +through. First revision and much of the code came from Guido. + +hex output from ipmon doesn't goto syslog when recovering from out of sync +error. Luke Mewburn (lukem@connect.com.au) + +fix solaris2.6 lookup of destination ire's. + +ipnat doesn't throw away unused bits (after masking), causing it to +behave incorrectly. Carson Gaspar + +NAT code doesn't include inteface name when matching - Alexey Mavrin + + +replace old SunOS tcpip.h with new tcpip.h (from 4.4BSD) - Jason Thorpe. + +update install procedures to include ip_proxy.c + +mask out unused bits in NAT/RDR rules. + +use a generic type (u_32_t) for 32bit variables, rather than rely on +u_long being such - Jason Thorpe. + +create a local "netinet" directory and include from ~netinet/*" rather than +just "*" to make keeping the code working on ports easier. + +add an m_copydata and m_copyback for SunOS4 (based on 4.4BSD-Lite versions) + +documentation updates. + +NetBSD update from Jason Thorpe + +allow RST's through with a matching SEQ # and 0 ACK. Guido Van Rooij + +ipmon uses excessive amounts of CPU on Solaris2 - Reinhard Bertram + + +3.2alpha7 25/5/97 - Released + +add strlen for pre-2.2 kernels - Doug Kite + +setup bits and pieces for compiling into a FreeBSD-2.2 kernel. + +split up "bsd" targets. Now a separate netbsd/freebsd/bsd target. +mln_ipl.c has been split up into itself and mlf_ipl.c (for freebsd). + +fix (negative) host matching in filtering. + +add sysctl interface for some variables when compiled into FreeBSD-2.2 kernels +or later. + +make all the candidates for kernel compiling include "netinet/..." and build +a subdirectory "netinet" when compiling and symlink all .h files into this. + +add install make target to Makefile.ipsend + +3.2alpha6 8/5/97 - Released + +Add "!" (not) to hostname/ip matching. + +Automatically add packet info to the fragment cache if it is a fragment +and we're translating addreses for. + +Automatically add packet info to the fragment cache if it is a fragment +and we're "keeping state" for the packet. + +Solaris2 patches - Anthony Baxter (arb@connect.com.au) + +change install procedure for FreeBSD 2.2 to allow building to a kernel +which is different to the running kernel. + +add FIONREAD for Solaris2! + +when expiring NAT table entries, if we would set a time to fr_tcpclosed +(which is 1), make it fr_tcplaskack(20) so that the state tables have a +chance to clear up. + +3.2alpha5 + +add proxying skeleton support and sample ftp transparent proxy code. + +add printfs at startup to tell user what is happening. + +add packets & bytes for EXPIRE NAT log records. + +fix the "install-bsd" target in the root Makefile. Chris Williams + + +Fixes for FreeBSD 2.2 (and later revs) to prevent panics. Julian Assange. + +3.2alpha4 2/4/97 - Released + +Some compiler warnings cleaned up. + +FreeBSD-2.2 patches for LKM completed. + +3.2alpha3 31/3/97 - Released + +ipmon changes: -N for reading NAT logfile, -S for reading state logfile. +-a for reading all. -n now toggles hostname resolution. + +Add logging of new state entries and expiration of old state entries. +count log successes and failures. + +Add logging of new NAT entries and expiration of old NAT entries. +count log successes and failures. + +Use u_quad_t for records of bytes & packets where kept +(IP Accounting: fr_hits, fr_bytes; IP state: is_pkts, is_bytes). + +Fixup use of CPU and DCPU in Makefiles. + +Fix broken 0/32 NAT mapping. Carl Makin + +3.2alpha2 + +Implement mapping to 0/32 as being an alias for automatically using the +interface's first IP address. + +Implement separate minor devices for both NAT and IP state code. + +Fully prototype all functions. + +Fix Makefile problem due to attempt to fix Sun compiling problems. + +3.1.10 23/3/97 - Released + +ipfstat -a requires a -i or -o command line option too. Print an error +when not present rather than attempt to do something. + +patch updates for SunOS4 for kernel compiling. +patch for ipmon -s (flush's syslog file which isn't good). Andrew J. Schorr + + +too many people hit their heads hard when compiling code into the kernel +that doesn't let any packets through. (fil.c - IPF_NOMATCH) + +icmp-type parsing doesn't return any errors when it isn't constructed +correctly. Neil Readwin + +Using "-conf" with modload on SunOS4 doesn't work. +Timothy Demarest + +Need to define ARCH in makefile for SunOS4 building. "make sunos4" +in INSTALL.SunOS is incorrect. James R Grinter +[all SunOS targets now run buildsunos] + +NAT lookups are still incorrect, matching non-TCP/UDP with TCP/UDP +information. ArkanoiD + +Need to check for __FreeBSD_version being 199511 rather than 199607 +in mln_ipl.c. Eric Feillant + +3.1.9 8/3/97 - Released + +fixed incorrect lookup of active NAT entries. + +patch for ip_deq() wrong for pre 2.1.6 FreeBSD. +fyeung@fyeung8.netific.com (Francis Yeung) + +check for out with return-rst/return-icmp at wrong place - Erkki Ritoniemi +(erkki@vlsi.fi) + +text_readip returns the interface pointer pointing to text on stack - +Neil Readwin + +fix from Pradeep Krishnan for printout rules "with not opt sec". + +3.1.8 18/2/97 - Released + +Diffs for ip_output.c and ip_input.c updated to fix bug with fastroute and +compiling warnings about reuse of m0. + +prevent use of return-rst and return-icmp with rules blocking packets going +out, preventing panics in certain situations. + +loop forms in frag cache table - Yury Pshenychny + +should use SPLNET/SPLX around expire routines in NAT/frag/state code. + +redeclared malloc in 44arp.c - + +3.1.7 8/2/97 - Released + +Macros used for ntohs/htons supplied with gcc don't always work very well +when the assignment is the same variable being converted. + +Filter matching doesn't not match rule which checks tcp flags on packets +which are fragments - David Wilson + +3.1.7beta 30/1/97 - Released + +Fix up NAT bugs introduced in last major change (now tested), including +nat_delete(), nat_lookupredir(), checksum changes, etc. + +3.1.7alpha 30/1/97 - Released + +Many changes to NAT code, including contributions from Laurent Joncheray + + +Use "NO_SLEEP" when allocating memory under SunOS. + +Make kernel printf's nicer for BSD/SunOS4 + +Always do a checksum for packets being filtered going out and being +processed by fastroute. + +Leave kernel to play with cdevsw on *BSD systems with LKM's. + +ipnat.1 man page fixes. + +3.1.6 21/1/97 - Released + +Allow NAT to work on BSD systems in conjunction with "pass .. to ifname" + +Memory leak introduced in 3.1.3 in NAT lists, clearing of NAT table tried +to free memory twice. + +NAT recalculates IP header checksum based on difference between IP#'s and +port numbers - should be just IP#'s (Solaris2 only) + +3.1.5 13/1/97 - Released + +fixed setting of NAT timeouts and use different timeouts for concurrent +TCP sessions using the same IP# mapping (when port mapping isn't used) + +multiple loading/unloading of LKM's doesn't clean up cdevsw properly for +*BSD systems. + +3.1.4 10/1/97 - Released + +add command line options -C and -F to ipnat to flush NAT list and table + +ipnat -l loops on output - Neil Readwin (nreadwin@nysales.micrognosis.com) + +NetBSD/FreeBSD kernel malloc changes - Daniel Carosone + +3.1.3 10/1/97 - Released + +NAT chains not constructed correctly in hash tables - Antony Y.R Lu +(antony@hawk.ee.ncku.edu.tw) + +Updated INSTALL.NetBSD, INSTALL.FreeBSD and INSTALL.Sol2 + +man page update (ipf.5) from Daniel Carosone (dan@geek.com.au) + +ICMP header checksum update now included in NAT. + +Solaris2 needs to modify IP header checksums in ip_natin and ip_natout. + +3.1.2 4/12/96 - Released + +ipmon doesn't use syslog all the time when given -s option + +fixed mclput panic in ip_input.c and replace ntohs() with NTOHS() macro + +check the results of hostname resolution in ipnat + +"make *install" fixed for subdirectories. + +problems with "ARCH:=" and gnu make resolved + +parser reports an error for lines with whitespaces only rather than skipping +them. D.Carosone@abm.com.au (Daniel Carosone) + +patches for integration into NetBSD-current (post 1.2). + +add an option to allow non-IP packets going up/down the stream on Solaris2 +to be dropped. John Bass. + +3.1.2beta 21/11/96 - Released + +make ipsend compile on Linux 2.0.24 + +changes to TCP kept state algorithm, making it watch state on TCP +connections in both directions. Also use the same algorithm for NAT TCP. + +-Wall cleanup - Bernd Ernesti + +added "or-block" for "pass .. log or-block" after a suggestion from +David Oppenheim (davido@optimation.com.au) + +added subdirectories for building IP Filter in SunOS5/BSD for different +cpu architecures + +Solaris2 fixes to logging and pre-filtering packet processing - 3.1.1p2 + +mbuf logging not using mtod(), remove iplbusy - 3.1.1p1 1/11/96 + +3.1.1 28/10/96 - Released + +Installation script fixes and deinstall scripts for IP Filter on: +SunOS4/FreeBSD/NetBSD + +Man page fixes - Paul Dubois (dubois@primate.wisc.edu) + +Fix use of SOLARIS macro in ipmon, rewrote ipllog() (again!) + +parsing isn't completely case insensitive - David Wilson +(davidw@optimation.com.au) + +Release ipl_mutex across uiomove() calls + +print entire rule entries out for "ipf -z" when zero'ing per-rule stats. + +ipfstat returns same output for "hits" in "ipfstat -aio" - Terletsky Slavik +(ts@polynet.lviv.ua) + +New algorithm for setting timeouts for TCP connection (more closely follow +TCP FSM) - Pradeep Krishnan (pkrishna@netcom.com) + +Track both window sizes for TCP connections through "keep state". + +Solaris2 doesn't like _KERNEL defined in stdargs.h - Jos van Wezel +(wezel@bio.vu.nl) + +3.1.1-beta2 6/10/96 - Released + +Solaris2 fastroute/dup-to/to now works + +ipmon `record' reading rewritten + +Added post-NetBSD1.2 packet filter patches - Mathew Green (mrg@eterna.com.au) + +Attempt to use in_proto.c.diff, not "..diffs" for SunOS4 - David Wilson +(davidw@optimation.com.au) + +Michael Ryan (mike@NetworX.ie) reports the following: +* The Trumpet WinSock under Windows always sends its SYN packet with an ACK + value of 1, unlike any other implementation I've seen, which would set it + to zero. The "keep state" feature of IP Filter doesn't work when receiving + non-zero ACK values on new connection requests. +* */Makefile install rule doesn't install all the binaries/man pages +* Make ipnat use "tcp/udp" instead of "tcpudp" +* Print out "tcp/udp" properly +* ipnat "portmap tcp" matches "portmap udp" when adding/removing +* NAT dest. ip# increased by one on mask of 0xffffffff when it shouldn't + +3.1.1-beta 1/9/96 - Released + +add better detection of TCP connections closing to TCP state monitoring. + +fr_addstate() not called correctly for fragments. "keep state" and +"keep frag" code don't work together 100% - Songqing Cai +(songqing_cai@sterling.com) + +call to fr_addstate() incorrect for adding state in combination with keeping +fragment information - Songqing Cai (songqing_cai@sterling.com) + +KFREE() passed fp (incorrect) and not fr (correct) in ip_frag.c - John Hood +(cgull@smoke.marlboro.vt.us) + +make ipf parser recognise '\\' as a `continued line' marker - Dima Ruban +(dima@best.net) + +3.1.1-alpha 23/8/96 - Released + +kernel panic's when ICMP packets go through NAT code + +stats aren't zero'd properly with ipf -Z + +ipnat doesn't show port numbers correctly all the time and also add the +protocol (tcp/udp/tcpudp) to rdr output - Carson Gaspar (carson@lehman.com) + +fast checksum fixing not 100% - backout patch - Bill Dorsey (dorsey@lila.com) + +NetBSD-1.2 patches from - VaX#n8 + +Usage() call error in fils.c - Ajay Shekhawat (ajay@cedar.buffalo.edu) + +ip_optcopy() staticly defined in ip_output.c in SunOS4 - Nick Hall +(nrh@tardis.ed.ac.uk) + +3.1.0 7/7/96 - Released + +Reformatted ipnat output to be compatible with it's input, so that +"ipnat -l | ipnat -rf -" is possible. + +3.1.0beta 30/6/96 - Released + +NetBSD-1.2 patches from Greg Woods (woods@most.weird.com) + +kernel module must not be installed stripped (Solaris2), as created by +"make package" for Solaris2 - Peter Heimann +(peter@i3.informatik.rwth-aachen.de) + +3.1.0alpha 5/6/96 - Released + +include examples in package for solaris2 + +patches for removing an extra ip header checksum (FreeBSD/NetBSD/SunOS) + +removed trailing space from printouts of rules in ipf. + +ipresend supports the same range of inputs that ipftest does. + +sending a duplicate copy of a packet to another network devices is now +supported. ("dup-to") + +sending a packet to an arbitary interface is now supported, irrespective +of its actual route, with no ttl decrement. Can also be routed without +the ttl being decremented. ("to" and "fastroute"). + +"call" option added to support calling a generic function if a packet is +matched. + +show all (upto 4) recorded bytes from the interface name in logging from +ipmon. + +support for using unix file permissions for read/write access on the device +is now in place. + +recursive mutex in nat_new() for Solaris 2.x - Per L. Hagen + +ipftest doesn't call initparse() for THISHOST - Catherine Allen +(cla@connect.com.au) + +Man page corrections from Rex Bona (rex@pengo.comsmiths.com.au) + +3.0.4 10/4/96 - Released + +looop in `parsing' IP packets with optlen 0 for ip options. + +rule number not initialized and resulted in unexpected results for state +maching. + +option parsing and printing bugs - Pradeep Krishnan + +3.0.4beta 25/3/96 - Released + +wouldn't parse "keep flags keep state" correctly. + +SunOS4.1.x ip_input.c doesn't recognise all 1s broadcast address - Nigel Verdon + +patches for BSDI's BSD/OS 2.1 and libpcap reader on little endian systems +from Thorsten Lockert + +b* functions in fil.c on Solaris 2.4 + +3.0.3 17/3/96 - Released + +added patches to support IP Filter initialisation when compiled into the +kernel. + +added -x option to ipmon to display hex dumps of logged packets. + +added -H option to ipftest to allow ascii-hex formatted input to specify +arbitary IP packets. + +Sending TCP RSTs as a response now work for Solaris2 x86 + +add patches to make IP Filter compile into NetBSD kernels properly. + +patch to stop SunOS 4.1.x kernels panicing with "data traps". + +ipfboot script unloads and reloads ipf module on Solaris2 if it is already +loaded into the kernel. + +Installation of IP Filter as a Solaris2 package is now supported. + +Man pages for ipnat.4, ipnat.5 added. + +added some more regression tests and fixed up IP Filter to pass the new tests +(previous versions failed some of the tests in set 12). + +IP option filter processing has changed so that saying "with opt lsrr" will +check only for that one, but not mask out other options, so a packet with +strict source routing, along with loose source routing will match all of +"with opt lsrr", "with opt ssrr" and "with opt lsrr,ssrr". + +IPL_NAME needed in ipnat.c - Kelly (kelly@count04.mry.scruznet.com) + +patches for clean NetBSD compilation from Bernd Ernesti (bernd@arresum.inka.de) + +make install is incorrect - Julian Briggs (julian@lightwork.co.uk) + +strtol() returns 0x7fffffff for all negative numbers, +printfr() generates incorrect output for "opt sec-class *", +handling of "not opt xxx opt yyy" incorrect. +- Minh Tonthat (minht@sbei.com)/Pradeep Krishnan (pradeepk@sbei.com) + +m_pullup() called only for input and not output; caused problems +with filtering icmp - Nigel Verdon (verdenn@gb.swissbank.com) + +parsing problem for "port 1" and NetBSD patches incorrect - +Andreas Gustafsson (gson@guava.araneus.fi) + +3.0.2 4/2/96 - Released + +Corrected bug where NAT recalculates checksums for fragments. + +make NAT recalculate UDP checksums (rather than setting them to 0), +if they're non-zero. + +DNS patches - Real Page (Real.Page@Matrox.com) + +alteration of checksum recalculations in NAT code and addition of +redirection with NAT - Mike Neuman + +core dump, if tcp/udp is used with a port number and not service name, +in ipf - Mike Neuman (mcn@engarde.com) + +initparse() call, missing to prime "" hook - Craig Bishop + +3.0.1 14/1/96 - Released + +miscellaneous patches for Solaris2 + +3.0 14/1/96 - Released + +Patch included for FDDI, from Richard Ohnemus +(Richard_Ohnemus@dallas.csd.sterling.com) + +Code cleanup for release. + +3.0beta4 10/1/96 + +recursive mutex in ipfr_slowtimer fixed, reported by Craig Bishop + +recursive mutex in sending TCP RSTs fixed, reported by Tony Becker + +3.0beta3 9/1/96 + +FIxup for Solaris2.5 install and interface name bug in ipftest from +Julian Briggs (julian@lightwork.co.uk) + +Byte order patches for ipmon from Tony Becker (tony@mcrsys.com) + +3.0beta2 7/1/96 + +Added the (somewhat warped) IP accounting as it exists in ipfw on FreeBSD. +Note, this isn't really what one would call IP account, when compared to +process accounting, sigh. + +Split up ipresend into iptest/ipresend/ipsend + +Added another m_pullup() inside fr_check() for BSD style kernels and +added some checks to ipllog() to not log more than is present (for short +packets). + +Fixed bug where failed hostname/netname resolution goes undetecte and +becomes 0.0.0.0 (any) (reported Guido van Rooij) + +3.0beta 11/11/95 - Released + +Rewrote the way rule testing is done, reducing the number of files needed and +generated. + +SIOCIPFFL was incorrectly affected by IPFILTER_LOG (Mathew Green) + +Patches from Guido van Rooij to fix sending back TCP RSTs on Net-2/Net-3 +BSD based Unixes (panic'd) + +Patches for FreeBSD/i86 ipmon from Riku Kalinen +(I think someone else already told me about these but they got lost :-/) + +Changed Makefile structure to build object files for different operating +systems in separate directories by default. + +BSDI has ef0 for first ethernet interface + +Allow for a "not" operator before optional keywords. + +The "rule number" was being incorrectly incremented every time it went through +the loop rather than when it matched a rule. + +2.8.2 24/10/95 - Released + +Fixed up problems with "textip" for doing lots of testing. + +Fixed bug in detection of "short" tcp/ip packets (all reported as being short). + +Solaris 2.4 port now works 100%. + +Man page errors reported and fixed. + +Removed duplicate entry in etc/services for login on port 49 (Craig Bishop). + +Fixed ipmon output to put a space after the log-letter. + +Patch from Guido van Rooij to fix parsing problem. + +2.8.1 15/10/95 - Released + +Added ttl and tos filtering. + +Patches for fixing up compilation and port problems (little endian) +from Guido van Rooij . + +Man page problems reported and fixed by Carson Gaspar . + +ipsend doesn't compile properly on Solaris2.4 + +Lots of work done for Solaris2.4 to make it MT/MP safe and work. + +2.8 15/9/95 - Released + +ipmon can now send messages to syslogd (-s) and use names instead of +numbers (-N). + +IP packets are now "compiled" into a structure only containing filterable +bits. + +Added regression testing in the test/ subdirectory, using a new option +(-b) with the ipftest program. + +Added "nomatch" return to filter results. These are counted and show +up in reports from ipfstat. + +Moved filter code out of ip_fil.c and into fil.c - there is now only one +instance of it in the package. + +Added Solaris 2.4 support. + +Added IPSO basic security option filtering. + +Added name support for filtering on all 19 named IP options. + +Patches from Ivan Brawley to log packet contents as well as packet headers. + +Update for sun/conf.c.diff from Ivan Brawley + +Added patches for FreeBSD 1, and added two new switches (-E, -D) to ipf, +along with a new ioctl, SIOCFRENB. +From: Dieter Dworkin Muller + +2.7.3 31/7.95 - Released + +Didn't compile cleanly without IPFILTER_LOG defined (Mathew Green). + +ipftest now deals with tcpdump3 binary output files (from libpcap) with -P. + +Brought ipftest program upto date with actual filter code. + +Filter would cause a match to occur when it wasn't meant to if the packet +had short headers and was missing portions that should have been there. +Err, it would rightly not match on them, but their absence caused a match +when it shouldn't have been. + +2.7.2 26/7/95 - Released + +Problem with filtering just SYN flagged packets reported by +Dieter Dworkin Muller . To solve this +problem, added support for masking TCP flags for comparison "flags X/Y". + +2.7.1 9/7/95 - Released + +Added ip_dirbroadcast support for Sun ip_input.c + +Fixed up the install scripts for FreeBSD/NetBSD to recognise where they are +better. + +2.7 7/7/95 - Released + +Added "return-rst" to return TCP RST's to TCP packets. + +Actually ported it to FreeBSD-i386 2.0.0, so it works there properly now. + +Added insertion of filter rules. Use "@<#>" at the beginning of a filter +to insert a rule at row #. + +Filter keeps track of how many times each rule is matched. + +Changed compile time things to match kernel option (IPFILTER_LKM & +IPFILTER_LOG). + +Updated ip_input.c and ip_output.c with paches for 3.5 Multicast IP. +(No change required for 3.6) + +Now includes TCP fragments which start inside the TCP header as being short. +Added counting the number of times each rule is matched. + + +2.6 11/5/95 - Released + +Added -n option to ipf: when supplied, no changes are made to the kernel. + +Added installation scripts for SunOS 4.1.x and NetBSD/FreeBSD/BSDI. + +Rewrote filtering to use a more generic mask & match procedure for +checking if a packet matches a rule. + +2.5.2 27/4/95 - Released + +"tcp/udp" and a non-initialised pointer caused the "proto" to become +a `random' value; added "ip#/dotted.mask" notation to the BNF. +From Adam W. Feigin + +2.5.1 22/3/95 - Released + +"tcp/udp" had a strange effect (undesired) on getserv*() functions, +causing protocol/service lookups to fail. Reported by Matthew Green. + +2.5 17/3/95 - Released + +Added a new keyword "all" to BNF and parsing of tcpdump/etherfind/snoop +output through the ipftest program. Suggestions from: +Michael Ciavarella (mikec@phyto.apana.org.au) + +Conflicts occur when "general" filter rules are used for ports and the +lack of a "proto" when used with "port" matches other packets when only +TCP/UDP are implied. +Reported Matthew Green (mrg@fulcom.com.au); +reported & fixed 6-8/3/95 + +Added filtering of short TCP packets using "with short" 28/2/95 +(These can possibly slip by checks for the various flags). Short UDP +or ICMP are dropped to the floor and logged. + +Added filtering of fragmented packets using "with frag" 24/2/95 + +Port to NetBSD-current completed 20/2/95, using LKM. + +Added logging of the rule # which caused the logging to happen and the +interface on which the packet is currently as suggested by +Andreas Greulich (greulich@math-stat.unibe.ch) 10/2/95 + +2.4 9/2/95 - Released +Fixed saving of IP headers in ICMP packets. + +2.3 29/1/95 +Added ipf -F [in|out|all] to flush filter rule sets (SIOCIPFFL). +Fixed iplread() and iplsave() with help from Marc Huber. + +2.2 7/1/95 - Released +Added code from Marc Huber to allow it to allocate +its own major char number dynamically when modload'ing. Fixed up +use of <, >, <=, >= and >< for ports. + +2.1 21/12/94 - Released +repackaged to include the correct ip_output.c and ip_input.c *goof* + +2.0 18/12/94 - Released +added code to check for port ranges - complete. +rewrote to work as a loadable kernel module - complete. + +1.1 +added code for ouput filtering as well as input filtering and added support for logging to a simple character device of packet headers. + +1.0 22/04/93 - Released +First release cut. Index: sbin/ipnat/Makefile =================================================================== RCS file: /cvs/src/sbin/ipnat/Makefile,v retrieving revision 1.5 retrieving revision 1.9 diff -u -r1.5 -r1.9 --- sbin/ipnat/Makefile 1999/02/07 00:48:29 1.5 +++ sbin/ipnat/Makefile 2000/04/26 21:04:00 1.9 @@ -1,9 +1,9 @@ -# $OpenBSD: Makefile,v 1.5 1999/02/07 00:48:29 deraadt Exp $ +# $OpenBSD: Makefile,v 1.9 2000/04/26 21:04:00 deraadt Exp $ PROG= ipnat MAN= ipnat.8 ipnat.4 ipnat.5 -SRCS= ipnat.c kmem.c -.PATH: ${.CURDIR}/../ipfstat -CFLAGS+=-I${.CURDIR}/../../sbin/ipfstat +SRCS= ipnat.c kmem.c natparse.c ifaddr.c +.PATH: ${.CURDIR}/../ipfstat ${.CURDIR}/../ipf +CFLAGS+=-I${.CURDIR}/../../sbin/ipfstat -I${.CURDIR}/../ipf .include Index: sbin/ipnat/ipnat.c =================================================================== RCS file: /cvs/src/sbin/ipnat/ipnat.c,v retrieving revision 1.31 retrieving revision 1.36 diff -u -r1.31 -r1.36 --- sbin/ipnat/ipnat.c 1999/07/25 19:14:43 1.31 +++ sbin/ipnat/ipnat.c 2000/03/13 23:40:19 1.36 @@ -1,4 +1,5 @@ -/* $OpenBSD: ipnat.c,v 1.31 1999/07/25 19:14:43 hugh Exp $ */ +/* $OpenBSD: ipnat.c,v 1.36 2000/03/13 23:40:19 kjell Exp $ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -7,15 +8,6 @@ * to the original author and the contributors. * * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) - * - * Broken still: - * Displaying the nat with redirect entries is way confusing - * - * Example redirection line: - * rdr le1 0.0.0.0/0 port 79 -> 199.165.219.129 port 9901 - * - * Will redirect all incoming packets on le1 to any machine, port 79 to - * host 199.165.219.129, port 9901 */ #include #include @@ -43,16 +35,15 @@ #include #include #include +#if __FreeBSD_version >= 300000 +# include +#endif #include #include #include #include #include -#if defined(__OpenBSD__) -# include -#else -# include -#endif +#include #include #include #include @@ -67,7 +58,7 @@ #if !defined(lint) static const char sccsid[] ="@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipnat.c,v 1.31 1999/07/25 19:14:43 hugh Exp $"; +static const char rcsid[] = "@(#)$IPFilter: ipnat.c,v 2.1.2.2 1999/12/04 02:09:30 darrenr Exp $"; #endif @@ -77,19 +68,23 @@ extern char *optarg; char *nlistf = NULL, *memf = NULL; +extern ipnat_t *natparse __P((char *, int)); +extern void natparsefile __P((int, char *, int)); +extern void printnat __P((ipnat_t *, int, void *)); + +#if defined(__OpenBSD__) +extern int if_addr __P((char *, struct in_addr *)); +#endif -ipnat_t *parse __P((char *)); -u_32_t hostnum __P((char *, int *)); +u_32_t hostnum __P((char *, int *, int)); u_32_t hostmask __P((char *)); -u_short portnum __P((char *, char *)); void dostats __P((int, int)), flushtable __P((int, int)); -void printnat __P((ipnat_t *, int, void *)); -void printaps __P((ap_session_t *, int )); -void parsefile __P((int, char *, int)); void usage __P((char *)); int countbits __P((u_32_t)); char *getnattype __P((ipnat_t *)); int main __P((int, char*[])); +void printaps __P((ap_session_t *, int)); +char *getsumd __P((u_32_t)); #define OPT_REM 1 #define OPT_NODO 2 @@ -98,24 +93,38 @@ #define OPT_VERBOSE 16 #define OPT_FLUSH 32 #define OPT_CLEAR 64 +#define OPT_HITS 128 void usage(name) char *name; { - fprintf(stderr, "%s: [-CFlnrsv] [-f filename]\n", name); + fprintf(stderr, "%s: [-CFhlnrsv] [-f filename]\n", name); exit(1); } +char *getsumd(sum) +u_32_t sum; +{ + static char sumdbuf[17]; + + if (sum & NAT_HW_CKSUM) + sprintf(sumdbuf, "hw(%#0x)", sum & 0xffff); + else + sprintf(sumdbuf, "%#0x", sum); + return sumdbuf; +} + + int main(argc, argv) int argc; char *argv[]; { char *file = NULL; - int fd = -1, opts = 1, c; + int fd = -1, opts = 0, c; - while ((c = getopt(argc, argv, "CFf:lnrsv")) != -1) + while ((c = getopt(argc, argv, "CFf:hlnrsv")) != -1) switch (c) { case 'C' : @@ -127,6 +136,9 @@ case 'F' : opts |= OPT_FLUSH; break; + case 'h' : + opts |=OPT_HITS; + break; case 'l' : opts |= OPT_LIST; break; @@ -134,7 +146,7 @@ opts |= OPT_NODO; break; case 'r' : - opts &= ~OPT_REM; + opts |= OPT_REM; break; case 's' : opts |= OPT_STAT; @@ -156,7 +168,7 @@ if (opts & (OPT_FLUSH|OPT_CLEAR)) flushtable(fd, opts); if (file) - parsefile(fd, file, opts); + natparsefile(fd, file, opts); if (opts & (OPT_LIST|OPT_STAT)) dostats(fd, opts); return 0; @@ -192,120 +204,13 @@ } -void printnat(np, verbose, ptr) -ipnat_t *np; -int verbose; -void *ptr; -{ - struct protoent *pr; - struct servent *sv; - int bits; - - switch (np->in_redir) - { - case NAT_REDIRECT : - printf("rdr "); - break; - case NAT_MAP : - printf("map "); - break; - case NAT_BIMAP : - printf("bimap "); - break; - default : - fprintf(stderr, "unknown value for in_redir: %#x\n", - np->in_redir); - break; - } - - if (np->in_redir == NAT_REDIRECT) { - printf("%s %s", np->in_ifname, inet_ntoa(np->in_out[0])); - bits = countbits(np->in_out[1].s_addr); - if (bits != -1) - printf("/%d ", bits); - else - printf("/%s ", inet_ntoa(np->in_out[1])); - if (np->in_pmin) - printf("port %d ", ntohs(np->in_pmin)); - printf("-> %s", inet_ntoa(np->in_in[0])); - if (np->in_pnext) - printf(" port %d", ntohs(np->in_pnext)); - if ((np->in_flags & IPN_TCPUDP) == IPN_TCPUDP) - printf(" tcp/udp"); - else if ((np->in_flags & IPN_TCP) == IPN_TCP) - printf(" tcp"); - else if ((np->in_flags & IPN_UDP) == IPN_UDP) - printf(" udp"); - printf("\n"); - if (verbose) - printf("\t%p %u %x %u %p %d\n", np->in_ifp, - np->in_space, np->in_flags, np->in_pnext, np, - np->in_use); - } else { - np->in_nextip.s_addr = htonl(np->in_nextip.s_addr); - printf("%s %s/", np->in_ifname, inet_ntoa(np->in_in[0])); - bits = countbits(np->in_in[1].s_addr); - if (bits != -1) - printf("%d ", bits); - else - printf("%s", inet_ntoa(np->in_in[1])); - printf(" -> %s/", inet_ntoa(np->in_out[0])); - bits = countbits(np->in_out[1].s_addr); - if (bits != -1) - printf("%d ", bits); - else - printf("%s", inet_ntoa(np->in_out[1])); - if (*np->in_plabel) { - pr = getprotobynumber(np->in_p); - printf(" proxy port"); - if (np->in_dport != 0) { - if (pr != NULL) - sv = getservbyport(np->in_dport, - pr->p_name); - else - sv = getservbyport(np->in_dport, NULL); - if (sv != NULL) - printf(" %s", sv->s_name); - else - printf(" %hu", ntohs(np->in_dport)); - } - printf(" %.*s/", (int)sizeof(np->in_plabel), - np->in_plabel); - if (pr != NULL) - fputs(pr->p_name, stdout); - else - printf("%d", np->in_p); - } else if (np->in_pmin || np->in_pmax) { - printf(" portmap"); - if ((np->in_flags & IPN_TCPUDP) == IPN_TCPUDP) - printf(" tcp/udp"); - else if (np->in_flags & IPN_TCP) - printf(" tcp"); - else if (np->in_flags & IPN_UDP) - printf(" udp"); - printf(" %d:%d", ntohs(np->in_pmin), - ntohs(np->in_pmax)); - } - printf("\n"); - if (verbose) { - printf("\tifp %p space %u nextip %s pnext %d", - np->in_ifp, np->in_space, - inet_ntoa(np->in_nextip), np->in_pnext); - printf(" flags %x use %u\n", - np->in_flags, np->in_use); - } - } -} - - void printaps(aps, opts) ap_session_t *aps; int opts; { ap_session_t ap; aproxy_t apr; - ap_tcp_t apt; - ap_udp_t apu; + raudio_t ra; if (kmemcpy((char *)&ap, (long)aps, sizeof(ap))) return; @@ -313,25 +218,44 @@ return; printf("\tproxy %s/%d use %d flags %x\n", apr.apr_label, apr.apr_p, apr.apr_ref, apr.apr_flags); - printf("\t\t%d %s -> ", ap.aps_p, inet_ntoa(ap.aps_src)); - printf("%s [%#x ", inet_ntoa(ap.aps_dst), ap.aps_flags); + printf("\t\tproto %d flags %#x bytes ", ap.aps_p, ap.aps_flags); #ifdef USE_QUAD_T - printf("%qu %qu", ap.aps_bytes, ap.aps_pkts); + printf("%qu pkts %qu", ap.aps_bytes, ap.aps_pkts); #else - printf("%lu %lu", ap.aps_bytes, ap.aps_pkts); + printf("%lu pkts %lu", ap.aps_bytes, ap.aps_pkts); #endif - printf(" %x[%d]]\n", ap.aps_data, ap.aps_psiz); + printf(" data %p psiz %d\n", ap.aps_data, ap.aps_psiz); if ((ap.aps_p == IPPROTO_TCP) && (opts & OPT_VERBOSE)) { - printf("\t\t%hu -> %hu state[%d,%d], sel[%d,%d]\n", - ap.aps_sport, ap.aps_dport, + printf("\t\tstate[%u,%u], sel[%d,%d]\n", ap.aps_state[0], ap.aps_state[1], ap.aps_sel[0], ap.aps_sel[1]); +#if (defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011)) || \ + (__FreeBSD_version >= 300000) || defined(OpenBSD) printf("\t\tseq: off %hd/%hd min %x/%x\n", ap.aps_seqoff[0], ap.aps_seqoff[1], ap.aps_seqmin[0], ap.aps_seqmin[1]); printf("\t\tack: off %hd/%hd min %x/%x\n", ap.aps_ackoff[0], ap.aps_ackoff[1], ap.aps_ackmin[0], ap.aps_ackmin[1]); +#else + printf("\t\tseq: off %hd/%hd min %lx/%lx\n", + ap.aps_seqoff[0], ap.aps_seqoff[1], + ap.aps_seqmin[0], ap.aps_seqmin[1]); + printf("\t\tack: off %hd/%hd min %lx/%lx\n", + ap.aps_ackoff[0], ap.aps_ackoff[1], + ap.aps_ackmin[0], ap.aps_ackmin[1]); +#endif + } + + if (!strcmp(apr.apr_label, "raudio") && ap.aps_psiz == sizeof(ra)) { + if (kmemcpy((char *)&ra, (long)ap.aps_data, sizeof(ra))) + return; + printf("\tReal Audio Proxy:\n"); + printf("\t\tSeen PNA: %d\tVersion: %d\tEOS: %d\n", + ra.rap_seenpna, ra.rap_version, ra.rap_eos); + printf("\t\tMode: %#x\tSBF: %#x\n", ra.rap_mode, ra.rap_sbf); + printf("\t\tPorts:pl %hu, pr %hu, sr %hu\n", + ra.rap_plport, ra.rap_prport, ra.rap_srport); } } @@ -345,8 +269,8 @@ char *which; ipnat_t ipnatbuff; - if (ipnat && kmemcpy((char *)&ipnatbuff, (long)ipnat, - sizeof(ipnatbuff))) + if (!ipnat || (ipnat && kmemcpy((char *)&ipnatbuff, (long)ipnat, + sizeof(ipnatbuff)))) return "???"; switch (ipnatbuff.in_redir) @@ -354,6 +278,9 @@ case NAT_MAP : which = "MAP"; break; + case NAT_MAPBLK : + which = "MAP-BLOCK"; + break; case NAT_REDIRECT : which = "RDR"; break; @@ -400,6 +327,8 @@ perror("kmemcpy"); break; } + if (opts & OPT_HITS) + printf("%d ", ipn.in_hits); printnat(&ipn, opts & OPT_VERBOSE, (void *)ns.ns_list); ns.ns_list = ipn.in_next; } @@ -412,81 +341,42 @@ } printf("\nList of active sessions:\n"); + + for (np = ns.ns_instances; np; np = nat.nat_next) { + if (kmemcpy((char *)&nat, (long)np, sizeof(nat))) + break; - for (i = 0; i < NAT_SIZE; i++) - for (np = nt[0][i]; np; np = nat.nat_hnext[0]) { - if (kmemcpy((char *)&nat, (long)np, - sizeof(nat))) - break; - - printf("%s %-15s %-5hu <- ->", - getnattype(nat.nat_ptr), - inet_ntoa(nat.nat_inip), - ntohs(nat.nat_inport)); - printf(" %-15s %-5hu", - inet_ntoa(nat.nat_outip), - ntohs(nat.nat_outport)); - printf(" [%s %hu]", inet_ntoa(nat.nat_oip), - ntohs(nat.nat_oport)); - if (opts & OPT_VERBOSE) { - printf("\n\tage %lu use %hu sumd %x", - nat.nat_age, nat.nat_use, - nat.nat_sumd); - printf(" bkt %d flags %x ", - i, nat.nat_flags); + printf("%s %-15s %-5hu <- ->", getnattype(nat.nat_ptr), + inet_ntoa(nat.nat_inip), ntohs(nat.nat_inport)); + printf(" %-15s %-5hu", inet_ntoa(nat.nat_outip), + ntohs(nat.nat_outport)); + printf(" [%s %hu]", inet_ntoa(nat.nat_oip), + ntohs(nat.nat_oport)); + if (opts & OPT_VERBOSE) { + printf("\n\tage %lu use %hu sumd %s/", + nat.nat_age, nat.nat_use, + getsumd(nat.nat_sumd[0])); + printf("%s pr %u bkt %d flags %x ", + getsumd(nat.nat_sumd[1]), nat.nat_p, + i, nat.nat_flags); #ifdef USE_QUAD_T - printf("bytes %qu pkts %qu", - nat.nat_bytes, nat.nat_pkts); + printf("bytes %qu pkts %qu", + nat.nat_bytes, nat.nat_pkts); #else - printf("bytes %lu pkts %lu", - nat.nat_bytes, nat.nat_pkts); + printf("bytes %lu pkts %lu", + nat.nat_bytes, nat.nat_pkts); #endif #if SOLARIS - printf(" %lx", nat.nat_ipsumd); + printf(" %lx", nat.nat_ipsumd); #endif - } - putchar('\n'); - if (nat.nat_aps) - printaps(nat.nat_aps, opts); } - free(nt[0]); - } -} - - -u_short portnum(name, proto) -char *name, *proto; -{ - struct servent *sp, *sp2; - u_short p1 = 0; + putchar('\n'); + if (nat.nat_aps) + printaps(nat.nat_aps, opts); + } - if (isdigit(*name)) - return htons((u_short)atoi(name)); - if (!proto) - proto = "tcp/udp"; - if (strcasecmp(proto, "tcp/udp")) { - sp = getservbyname(name, proto); - if (sp) - return sp->s_port; - (void) fprintf(stderr, "unknown service \"%s\".\n", name); - return 0; - } - sp = getservbyname(name, "tcp"); - if (sp) - p1 = sp->s_port; - sp2 = getservbyname(name, "udp"); - if (!sp || !sp2) { - (void) fprintf(stderr, "unknown tcp/udp service \"%s\".\n", - name); - return 0; - } - if (p1 != sp2->s_port) { - (void) fprintf(stderr, "%s %d/tcp is a different port to ", - name, p1); - (void) fprintf(stderr, "%s %d/udp\n", name, sp->s_port); - return 0; + free(nt[0]); } - return p1; } @@ -514,81 +404,14 @@ } -#if defined(__OpenBSD__) /* - * if_addr(): - * given a string containing an interface name (e.g. "ppp0") - * return the IP address it represents - * - * The OpenBSD community considers this feature to be quite useful and - * suggests inclusion into other platforms. The closest alternative is - * to define /etc/networks with suitable values. - */ -int if_addr(name, ap) -char *name; -struct in_addr *ap; -{ - struct ifconf ifc; - struct ifreq ifreq, *ifr; - char *inbuf = NULL; - int s, i, len = 8192; - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - warn("socket"); - return 0; - } - - while (1) { - ifc.ifc_len = len; - ifc.ifc_buf = inbuf = realloc(inbuf, len); - if (inbuf == NULL) - err(1, "malloc"); - if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { - warn("SIOCGIFCONF"); - goto if_addr_lose; - } - if (ifc.ifc_len + sizeof(ifreq) < len) - break; - len *= 2; - } - ifr = ifc.ifc_req; - ifreq.ifr_name[0] = '\0'; - for (i = 0; i < ifc.ifc_len; ) { - ifr = (struct ifreq *)((caddr_t)ifc.ifc_req + i); - i += sizeof(ifr->ifr_name) + - (ifr->ifr_addr.sa_len > sizeof(struct sockaddr) - ? ifr->ifr_addr.sa_len - : sizeof(struct sockaddr)); - ifreq = *ifr; - if (ioctl(s, SIOCGIFADDR, (caddr_t)ifr) < 0) - continue; - if (ifr->ifr_addr.sa_family != AF_INET) - continue; - if (!strcmp(name, ifr->ifr_name)) { - struct sockaddr_in *sin; - close(s); - free(inbuf); - sin = (struct sockaddr_in *)&ifr->ifr_addr; - *ap = sin->sin_addr; - return (1); - } - } - -if_addr_lose: - close(s); - free(inbuf); - return 0; -} -#endif - - -/* * returns an ip address as a long var as a result of either a DNS lookup or * straight inet_addr() call */ -u_32_t hostnum(host, resolved) +u_32_t hostnum(host, resolved, linenum) char *host; int *resolved; +int linenum; { struct hostent *hp; struct netent *np; @@ -599,8 +422,8 @@ *resolved = 0; if (!strcasecmp("any", host)) return 0L; - if (inet_aton(host, &addr)) - return (u_32_t)addr.s_addr; + if (isdigit(*host)) + return inet_addr(host); #if defined(__OpenBSD__) /* attempt a map from interface name to address */ @@ -610,352 +433,12 @@ if (!(hp = gethostbyname(host))) { if (!(np = getnetbyname(host))) { *resolved = -1; - fprintf(stderr, "can't resolve hostname: %s\n", host); + fprintf(stderr, "Line %d: can't resolve hostname: %s\n", linenum, host); return 0; } return htonl(np->n_net); } return *(u_32_t *)hp->h_addr; -} - - -ipnat_t *parse(line) -char *line; -{ - struct protoent *pr; - static ipnat_t ipn; - char *s, *t; - char *shost, *snetm, *dhost, *proto; - char *dnetm = NULL, *dport = NULL, *tport = NULL; - int resolved; - - bzero((char *)&ipn, sizeof(ipn)); - if ((s = strchr(line, '\n'))) - *s = '\0'; - if ((s = strchr(line, '#'))) - *s = '\0'; - if (!*line) - return NULL; - if (!(s = strtok(line, " \t"))) - return NULL; - if (!strcasecmp(s, "map")) - ipn.in_redir = NAT_MAP; - else if (!strcasecmp(s, "rdr")) - ipn.in_redir = NAT_REDIRECT; - else if (!strcasecmp(s, "bimap")) - ipn.in_redir = NAT_BIMAP; - else { - (void)fprintf(stderr, - "expected map/rdr/bimap, got \"%s\"\n", s); - return NULL; - } - - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, "missing fields (interface)\n"); - return NULL; - } - strncpy(ipn.in_ifname, s, sizeof(ipn.in_ifname) - 1); - ipn.in_ifname[sizeof(ipn.in_ifname) - 1] = '\0'; - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, "missing fields (%s)\n", - ipn.in_redir & NAT_MAP ? "source": "destination"); - return NULL; - } - shost = s; - - if (ipn.in_redir == NAT_REDIRECT) { - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, "missing fields (destination port)\n"); - return NULL; - } - - if (strcasecmp(s, "port")) { - fprintf(stderr, "missing fields (port)\n"); - return NULL; - } - - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, "missing fields (destination port)\n"); - return NULL; - } - - dport = s; - } - - - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, "missing fields (->)\n"); - return NULL; - } - if (!strcmp(s, "->")) { - snetm = strrchr(shost, '/'); - if (!snetm) { - fprintf(stderr, "missing fields (%s netmask)\n", - ipn.in_redir & NAT_MAP ? "source":"destination"); - return NULL; - } - } else { - if (strcasecmp(s, "netmask")) { - fprintf(stderr, "missing fields (netmask)\n"); - return NULL; - } - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, "missing fields (%s netmask)\n", - ipn.in_redir & NAT_MAP ? "source":"destination"); - return NULL; - } - snetm = s; - } - - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, "missing fields (%s)\n", - ipn.in_redir & NAT_MAP ? "target":"destination"); - return NULL; - } - dhost = s; - - if (ipn.in_redir & NAT_MAP) { - if (!(s = strtok(NULL, " \t"))) { - dnetm = strrchr(dhost, '/'); - if (!dnetm) { - fprintf(stderr, - "missing fields (dest netmask)\n"); - return NULL; - } - } - if (!s || !strcasecmp(s, "portmap") || - !strcasecmp(s, "proxy")) { - dnetm = strrchr(dhost, '/'); - if (!dnetm) { - fprintf(stderr, - "missing fields (dest netmask)\n"); - return NULL; - } - } else { - if (strcasecmp(s, "netmask")) { - fprintf(stderr, - "missing fields (dest netmask)\n"); - return NULL; - } - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, - "missing fields (dest netmask)\n"); - return NULL; - } - dnetm = s; - } - if (*dnetm == '/') - *dnetm++ = '\0'; - } else { - if (strrchr(dhost, '/') != NULL) { - fprintf(stderr, "No netmask supported in %s\n", - "destination host for redirect"); - return NULL; - } - /* If it's a in_redir, expect target port */ - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, "missing fields (destination port)\n"); - return NULL; - } - - if (strcasecmp(s, "port")) { - fprintf(stderr, "missing fields (port)\n"); - return NULL; - } - - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, "missing fields (destination port)\n"); - return NULL; - } - tport = s; - } - - - if (*snetm == '/') - *snetm++ = '\0'; - - if (ipn.in_redir & NAT_MAP) { - ipn.in_inip = hostnum(shost, &resolved); - if (resolved == -1) - return NULL; - ipn.in_inmsk = hostmask(snetm); - ipn.in_outip = hostnum(dhost, &resolved); - if (resolved == -1) - return NULL; - ipn.in_outmsk = hostmask(dnetm); - } else { - ipn.in_inip = hostnum(dhost, &resolved); /* Inside is target */ - if (resolved == -1) - return NULL; - ipn.in_inmsk = hostmask("255.255.255.255"); - ipn.in_outip = hostnum(shost, &resolved); - if (resolved == -1) - return NULL; - ipn.in_outmsk = hostmask(snetm); - if (!(s = strtok(NULL, " \t"))) { - ipn.in_flags = IPN_TCP; /* XXX- TCP only by default */ - proto = "tcp"; - } else { - if (!strcasecmp(s, "tcp")) - ipn.in_flags = IPN_TCP; - else if (!strcasecmp(s, "udp")) - ipn.in_flags = IPN_UDP; - else if (!strcasecmp(s, "tcp/udp")) - ipn.in_flags = IPN_TCPUDP; - else if (!strcasecmp(s, "tcpudp")) - ipn.in_flags = IPN_TCPUDP; - else { - fprintf(stderr, - "expected protocol - got \"%s\"\n", s); - return NULL; - } - proto = s; - if ((s = strtok(NULL, " \t"))) { - fprintf(stderr, - "extra junk at the end of rdr: %s\n", - s); - return NULL; - } - } - ipn.in_pmin = portnum(dport, proto); /* dest port */ - ipn.in_pmax = ipn.in_pmin; /* NECESSARY of removing nats */ - ipn.in_pnext = portnum(tport, proto); /* target port */ - s = NULL; /* That's all she wrote! */ - } - ipn.in_inip &= ipn.in_inmsk; - ipn.in_outip &= ipn.in_outmsk; - - if (!s) - return &ipn; - - if (ipn.in_redir == NAT_BIMAP) { - fprintf(stderr, "extra words at the end of bimap line: %s\n", - s); - return NULL; - } - if (!strcasecmp(s, "proxy")) { - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, "missing parameter for \"proxy\"\n"); - return NULL; - } - dport = NULL; - - if (!strcasecmp(s, "port")) { - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, - "missing parameter for \"port\"\n"); - return NULL; - } - - dport = s; - - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, - "missing parameter for \"proxy\"\n"); - return NULL; - } - } else { - fprintf(stderr, "missing keyword \"port\"\n"); - return NULL; - } - if ((proto = index(s, '/'))) { - *proto++ = '\0'; - if ((pr = getprotobyname(proto))) - ipn.in_p = pr->p_proto; - else - ipn.in_p = atoi(proto); - if (dport) - ipn.in_dport = portnum(dport, proto); - } else { - ipn.in_p = 0; - if (dport) - ipn.in_dport = portnum(dport, NULL); - } - - (void) strncpy(ipn.in_plabel, s, sizeof(ipn.in_plabel)); - if ((s = strtok(NULL, " \t"))) { - fprintf(stderr, "too many parameters for \"proxy\"\n"); - return NULL; - } - return &ipn; - - } - if (strcasecmp(s, "portmap")) { - fprintf(stderr, "expected \"portmap\" - got \"%s\"\n", s); - return NULL; - } - if (!(s = strtok(NULL, " \t"))) - return NULL; - if (!strcasecmp(s, "tcp")) - ipn.in_flags = IPN_TCP; - else if (!strcasecmp(s, "udp")) - ipn.in_flags = IPN_UDP; - else if (!strcasecmp(s, "tcpudp")) - ipn.in_flags = IPN_TCPUDP; - else if (!strcasecmp(s, "tcp/udp")) - ipn.in_flags = IPN_TCPUDP; - else { - fprintf(stderr, "expected protocol name - got \"%s\"\n", s); - return NULL; - } - proto = s; - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, "no port range found\n"); - return NULL; - } - if (!(t = strchr(s, ':'))) { - fprintf(stderr, "no port range in \"%s\"\n", s); - return NULL; - } - *t++ = '\0'; - ipn.in_pmin = portnum(s, proto); - ipn.in_pmax = portnum(t, proto); - return &ipn; -} - - -void parsefile(fd, file, opts) -int fd; -char *file; -int opts; -{ - char line[512], *s; - ipnat_t *np; - FILE *fp; - int linenum = 1; - - if (strcmp(file, "-")) { - if (!(fp = fopen(file, "r"))) { - (void) fprintf(stderr, "%s: open: %s\n", file, - STRERROR(errno)); - exit(1); - } - } else - fp = stdin; - - while (fgets(line, sizeof(line) - 1, fp)) { - line[sizeof(line) - 1] = '\0'; - if ((s = strchr(line, '\n'))) - *s = '\0'; - if (!(np = parse(line))) { - if (*line) - fprintf(stderr, "%d: syntax error in \"%s\"\n", - linenum, line); - } else { - if ((opts & OPT_VERBOSE) && np) - printnat(np, opts & OPT_VERBOSE, NULL); - if (!(opts & OPT_NODO)) { - if (opts & OPT_REM) { - if (ioctl(fd, SIOCADNAT, np) == -1) - perror("ioctl(SIOCADNAT)"); - } else if (ioctl(fd, SIOCRMNAT, np) == -1) - perror("ioctl(SIOCRMNAT)"); - } - } - linenum++; - } - if (fp != stdin) - fclose(fp); } Index: sbin/ipnat/natparse.c =================================================================== RCS file: natparse.c diff -N natparse.c --- /dev/null Wed May 24 17:02:20 2000 +++ sbin/ipnat/natparse.c Wed May 24 17:46:37 2000 @@ -0,0 +1,796 @@ +/* $OpenBSD: natparse.c,v 1.5 2000/05/01 06:16:48 kjell Exp $ */ + +/* + * Copyright (C) 1993-1998 by Darren Reed. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and due credit is given + * to the original author and the contributors. + */ +#include +#include +#include +#include +#include +#if !defined(__SVR4) && !defined(__svr4__) +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#if defined(sun) && (defined(__svr4__) || defined(__SVR4)) +# include +# include +#endif +#include +#include +#include +#include +#include +#if __FreeBSD_version >= 300000 +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(sun) && !SOLARIS2 +# define STRERROR(x) sys_errlist[x] +extern char *sys_errlist[]; +#else +# define STRERROR(x) strerror(x) +#endif + +#if !defined(lint) +static const char sccsid[] ="@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed"; +static const char rcsid[] = "@(#)$IPFilter: natparse.c,v 1.2.2.2 2000/03/25 00:37:37 darrenr Exp $"; +#endif + + +#if SOLARIS +#define bzero(a,b) memset(a,0,b) +#endif + +extern int countbits __P((u_32_t)); +extern u_32_t hostnum __P((char *, int *, int)); + +ipnat_t *natparse __P((char *, int)); +void printnat __P((ipnat_t *, int, void *)); +void natparsefile __P((int, char *, int)); +u_32_t n_hostmask __P((char *)); +u_short n_portnum __P((char *, char *, int)); +void nat_setgroupmap __P((struct ipnat *)); + +#define OPT_REM 1 +#define OPT_NODO 2 +#define OPT_STAT 4 +#define OPT_LIST 8 +#define OPT_VERBOSE 16 +#define OPT_FLUSH 32 +#define OPT_CLEAR 64 + + +void printnat(np, verbose, ptr) +ipnat_t *np; +int verbose; +void *ptr; +{ + struct protoent *pr; + struct servent *sv; + int bits; + + switch (np->in_redir) + { + case NAT_REDIRECT : + printf("rdr "); + break; + case NAT_MAP : + printf("map "); + break; + case NAT_MAPBLK : + printf("map-block "); + break; + case NAT_BIMAP : + printf("bimap "); + break; + default : + fprintf(stderr, "unknown value for in_redir: %#x\n", + np->in_redir); + break; + } + + if (np->in_redir == NAT_REDIRECT) { + printf("%s ", np->in_ifname); + if (np->in_src[0].s_addr || np->in_src[1].s_addr) { + printf("from %s",inet_ntoa(np->in_src[0])); + bits = countbits(np->in_src[1].s_addr); + if (bits != -1) + printf("/%d ", bits); + else + printf("/%s ", inet_ntoa(np->in_src[1])); + } + printf("%s",inet_ntoa(np->in_out[0])); + bits = countbits(np->in_out[1].s_addr); + if (bits != -1) + printf("/%d ", bits); + else + printf("/%s ", inet_ntoa(np->in_out[1])); + if (np->in_pmin) + printf("port %d ", ntohs(np->in_pmin)); + printf("-> %s", inet_ntoa(np->in_in[0])); + if (np->in_pnext) + printf(" port %d", ntohs(np->in_pnext)); + if ((np->in_flags & IPN_TCPUDP) == IPN_TCPUDP) + printf(" tcp/udp"); + else if ((np->in_flags & IPN_TCP) == IPN_TCP) + printf(" tcp"); + else if ((np->in_flags & IPN_UDP) == IPN_UDP) + printf(" udp"); + printf("\n"); + if (verbose) + printf("\t%p %lu %x %u %p %d\n", np->in_ifp, + np->in_space, np->in_flags, np->in_pnext, np, + np->in_use); + } else { + np->in_nextip.s_addr = htonl(np->in_nextip.s_addr); + printf("%s %s/", np->in_ifname, inet_ntoa(np->in_in[0])); + bits = countbits(np->in_in[1].s_addr); + if (bits != -1) + printf("%d ", bits); + else + printf("%s", inet_ntoa(np->in_in[1])); + printf(" -> "); + if (np->in_flags & IPN_RANGE) { + printf("range %s-", inet_ntoa(np->in_out[0])); + printf("%s", inet_ntoa(np->in_out[1])); + } else { + printf("%s/", inet_ntoa(np->in_out[0])); + bits = countbits(np->in_out[1].s_addr); + if (bits != -1) + printf("%d ", bits); + else + printf("%s", inet_ntoa(np->in_out[1])); + } + if (*np->in_plabel) { + pr = getprotobynumber(np->in_p); + printf(" proxy port"); + if (np->in_dport != 0) { + if (pr != NULL) + sv = getservbyport(np->in_dport, + pr->p_name); + else + sv = getservbyport(np->in_dport, NULL); + if (sv != NULL) + printf(" %s", sv->s_name); + else + printf(" %hu", ntohs(np->in_dport)); + } + printf(" %.*s/", (int)sizeof(np->in_plabel), + np->in_plabel); + if (pr != NULL) + fputs(pr->p_name, stdout); + else + printf("%d", np->in_p); + } else if (np->in_redir == NAT_MAPBLK) { + printf(" ports %d", np->in_pmin); + if (verbose) + printf("\n\tip modulous %d", np->in_pmax); + } else if (np->in_pmin || np->in_pmax) { + printf(" portmap"); + if (np->in_flags & IPN_AUTOPORTMAP) { + printf(" auto"); + if (verbose) + printf(" [%d:%d %d %d]", + ntohs(np->in_pmin), + ntohs(np->in_pmax), + np->in_ippip, np->in_ppip); + } else { + if ((np->in_flags & IPN_TCPUDP) == IPN_TCPUDP) + printf(" tcp/udp"); + else if (np->in_flags & IPN_TCP) + printf(" tcp"); + else if (np->in_flags & IPN_UDP) + printf(" udp"); + printf(" %d:%d", ntohs(np->in_pmin), + ntohs(np->in_pmax)); + } + } + printf("\n"); + if (verbose) { + printf("\tifp %p space %lu nextip %s pnext %d", + np->in_ifp, np->in_space, + inet_ntoa(np->in_nextip), np->in_pnext); + printf(" flags %x use %u\n", + np->in_flags, np->in_use); + } + } +} + + +void nat_setgroupmap(n) +ipnat_t *n; +{ + if (n->in_outmsk == n->in_inmsk) + n->in_ippip = 1; + else if (n->in_flags & IPN_AUTOPORTMAP) { + n->in_ippip = ~ntohl(n->in_inmsk); + if (n->in_outmsk != 0xffffffff) + n->in_ippip /= (~ntohl(n->in_outmsk) + 1); + n->in_ippip++; + if (n->in_ippip == 0) + n->in_ippip = 1; + n->in_ppip = USABLE_PORTS / n->in_ippip; + } else { + n->in_space = USABLE_PORTS * ~ntohl(n->in_outmsk); + n->in_nip = 0; + if (!(n->in_ppip = n->in_pmin)) + n->in_ppip = 1; + n->in_ippip = USABLE_PORTS / n->in_ppip; + } +} + + + +ipnat_t *natparse(line, linenum) +char *line; +int linenum; +{ + struct protoent *pr; + static ipnat_t ipn; + char *s, *t; + char *shost, *snetm, *dhost, *proto, *srchost, *srcnetm; + char *dnetm = NULL, *dport = NULL, *tport = NULL; + int resolved; + + srchost = NULL; + srcnetm = NULL; + + bzero((char *)&ipn, sizeof(ipn)); + if ((s = strchr(line, '\n'))) + *s = '\0'; + if ((s = strchr(line, '#'))) + *s = '\0'; + if (!*line) + return NULL; + if (!(s = strtok(line, " \t"))) + return NULL; + if (!strcasecmp(s, "map")) + ipn.in_redir = NAT_MAP; + else if (!strcasecmp(s, "map-block")) + ipn.in_redir = NAT_MAPBLK; + else if (!strcasecmp(s, "rdr")) + ipn.in_redir = NAT_REDIRECT; + else if (!strcasecmp(s, "bimap")) + ipn.in_redir = NAT_BIMAP; + else { + fprintf(stderr, "%d: unknown mapping: \"%s\"\n", + linenum, s); + return NULL; + } + + if (!(s = strtok(NULL, " \t"))) { + fprintf(stderr, "%d: missing fields (interface)\n", + linenum); + return NULL; + } + + strncpy(ipn.in_ifname, s, sizeof(ipn.in_ifname) - 1); + ipn.in_ifname[sizeof(ipn.in_ifname) - 1] = '\0'; + if (!(s = strtok(NULL, " \t"))) { + fprintf(stderr, "%d: missing fields (%s)\n", linenum, + ipn.in_redir ? "from source | destination" : "source"); + return NULL; + } + + if ((ipn.in_redir == NAT_REDIRECT) && !strcasecmp(s, "from")) { + if (!(s = strtok(NULL, " \t"))) { + fprintf(stderr, + "%d: missing fields (source address)\n", + linenum); + return NULL; + } + + srchost = s; + srcnetm = strrchr(srchost, '/'); + + if (srcnetm == NULL) { + if (!(s = strtok(NULL, " \t"))) { + fprintf(stderr, + "%d: missing fields (source netmask)\n", + linenum); + return NULL; + } + + if (strcasecmp(s, "netmask")) { + fprintf(stderr, + "%d: missing fields (netmask)\n", + linenum); + return NULL; + } + if (!(s = strtok(NULL, " \t"))) { + fprintf(stderr, + "%d: missing fields (source netmask)\n", + linenum); + return NULL; + } + srcnetm = s; + } + if (*srcnetm == '/') + *srcnetm++ = '\0'; + + /* re read the next word -- destination */ + if (!(s = strtok(NULL, " \t"))) { + fprintf(stderr, + "%d: missing fields (destination)\n", linenum); + return NULL; + } + + } + + shost = s; + + if (ipn.in_redir == NAT_REDIRECT) { + if (!(s = strtok(NULL, " \t"))) { + fprintf(stderr, + "%d: missing fields (destination port)\n", + linenum); + return NULL; + } + + if (strcasecmp(s, "port")) { + fprintf(stderr, "%d: missing fields (port)\n", linenum); + return NULL; + } + + if (!(s = strtok(NULL, " \t"))) { + fprintf(stderr, + "%d: missing fields (destination port)\n", + linenum); + return NULL; + } + + dport = s; + } + + + if (!(s = strtok(NULL, " \t"))) { + fprintf(stderr, "%d: missing fields (->)\n", linenum); + return NULL; + } + if (!strcmp(s, "->")) { + snetm = strrchr(shost, '/'); + if (!snetm) { + fprintf(stderr, + "%d: missing fields (%s netmask)\n", linenum, + ipn.in_redir ? "destination" : "source"); + return NULL; + } + } else { + if (strcasecmp(s, "netmask")) { + fprintf(stderr, "%d: missing fields (netmask)\n", + linenum); + return NULL; + } + if (!(s = strtok(NULL, " \t"))) { + fprintf(stderr, + "%d: missing fields (%s netmask)\n", linenum, + ipn.in_redir ? "destination" : "source"); + return NULL; + } + snetm = s; + } + + if (!(s = strtok(NULL, " \t"))) { + fprintf(stderr, "%d: missing fields (%s)\n", + linenum, ipn.in_redir ? "destination":"target"); + return NULL; + } + + if (ipn.in_redir == NAT_MAP) { + if (!strcasecmp(s, "range")) { + ipn.in_flags |= IPN_RANGE; + if (!(s = strtok(NULL, " \t"))) { + fprintf(stderr, "%d: missing fields (%s)\n", + linenum, + ipn.in_redir ? "destination":"target"); + return NULL; + } + } + } + dhost = s; + + if (ipn.in_redir & (NAT_MAP|NAT_MAPBLK)) { + if (ipn.in_flags & IPN_RANGE) { + dnetm = strrchr(dhost, '-'); + if (dnetm == NULL) { + if (!(s = strtok(NULL, " \t"))) + dnetm = NULL; + else { + if (strcmp(s, "-")) + s = NULL; + else if ((s = strtok(NULL, " \t"))) { + dnetm = s; + } + } + } else + *dnetm++ = '\0'; + if (dnetm == NULL || *dnetm == '\0') { + fprintf(stderr, + "%d: desination range not specified\n", + linenum); + return NULL; + } + } else { + dnetm = strrchr(dhost, '/'); + if (dnetm == NULL) { + if (!(s = strtok(NULL, " \t"))) + dnetm = NULL; + else if (!strcasecmp(s, "netmask")) + if ((s = strtok(NULL, " \t")) != NULL) + dnetm = s; + } + if (dnetm == NULL) { + fprintf(stderr, + "%d: missing fields (dest netmask)\n", + linenum); + return NULL; + } + if (*dnetm == '/') + *dnetm++ = '\0'; + } + s = strtok(NULL, " \t"); + } + + if (ipn.in_redir & NAT_MAPBLK) { + if (s && strcasecmp(s, "ports")) { + fprintf(stderr, + "%d: expected \"ports\" - got \"%s\"\n", + linenum, s); + return NULL; + } + if (s != NULL) { + if ((s = strtok(NULL, " \t")) == NULL) + return NULL; + ipn.in_pmin = atoi(s); + s = strtok(NULL, " \t"); + } else + ipn.in_pmin = 0; + } else if ((ipn.in_redir & NAT_BIMAP) == NAT_REDIRECT) { + if (strrchr(dhost, '/') != NULL) { + fprintf(stderr, "%d: No netmask supported in %s\n", + linenum, "destination host for redirect"); + return NULL; + } + /* If it's a in_redir, expect target port */ + if (!(s = strtok(NULL, " \t"))) { + fprintf(stderr, + "%d: missing fields (destination port)\n", + linenum); + return NULL; + } + + if (strcasecmp(s, "port")) { + fprintf(stderr, "%d: missing fields (port)\n", + linenum); + return NULL; + } + + if (!(s = strtok(NULL, " \t"))) { + fprintf(stderr, + "%d: missing fields (destination port)\n", + linenum); + return NULL; + } + tport = s; + } + if (dnetm && *dnetm == '/') + *dnetm++ = '\0'; + if (snetm && *snetm == '/') + *snetm++ = '\0'; + + if (ipn.in_redir & (NAT_MAP|NAT_MAPBLK)) { + ipn.in_inip = hostnum(shost, &resolved, linenum); + if (resolved == -1) + return NULL; + ipn.in_inmsk = n_hostmask(snetm); + ipn.in_outip = hostnum(dhost, &resolved, linenum); + if (resolved == -1) + return NULL; + if (ipn.in_flags & IPN_RANGE) { + ipn.in_outmsk = hostnum(dnetm, &resolved, linenum); + if (resolved == -1) + return NULL; + } else + ipn.in_outmsk = n_hostmask(dnetm); + if (srchost) { + ipn.in_srcip = hostnum(srchost, &resolved, linenum); + if (resolved == -1) + return NULL; + } + if (srcnetm) + ipn.in_srcmsk = n_hostmask(srcnetm); + } else { + if (srchost) { + ipn.in_srcip = hostnum(srchost, &resolved, linenum); + if (resolved == -1) + return NULL; + } + if (srcnetm) + ipn.in_srcmsk = n_hostmask(srcnetm); + ipn.in_inip = hostnum(dhost, &resolved, linenum); + if (resolved == -1) + return NULL; + ipn.in_inmsk = n_hostmask("255.255.255.255"); + ipn.in_outip = hostnum(shost, &resolved, linenum); + if (resolved == -1) + return NULL; + ipn.in_outmsk = n_hostmask(snetm); + if (!(s = strtok(NULL, " \t"))) { + ipn.in_flags |= IPN_TCP; /* XXX- TCP only by default */ + proto = "tcp"; + } else { + if (!strcasecmp(s, "tcp")) + ipn.in_flags |= IPN_TCP; + else if (!strcasecmp(s, "udp")) + ipn.in_flags |= IPN_UDP; + else if (!strcasecmp(s, "tcp/udp")) + ipn.in_flags |= IPN_TCPUDP; + else if (!strcasecmp(s, "tcpudp")) + ipn.in_flags |= IPN_TCPUDP; + else if (!strcasecmp(s, "ip")) + ipn.in_flags |= IPN_ANY; + else { + ipn.in_flags |= IPN_ANY; + if ((pr = getprotobyname(s))) + ipn.in_p = pr->p_proto; + else + ipn.in_p = atoi(s); + } + proto = s; + if ((s = strtok(NULL, " \t"))) { + fprintf(stderr, + "%d: extra junk at the end of rdr: %s\n", + linenum, s); + return NULL; + } + } + ipn.in_pmin = n_portnum(dport, proto, linenum); + ipn.in_pmax = ipn.in_pmin; + ipn.in_pnext = n_portnum(tport, proto, linenum); + s = NULL; + } + ipn.in_inip &= ipn.in_inmsk; + if ((ipn.in_flags & IPN_RANGE) == 0) + ipn.in_outip &= ipn.in_outmsk; + ipn.in_srcip &= ipn.in_srcmsk; + + if ((ipn.in_redir & NAT_MAPBLK) != 0) + nat_setgroupmap(&ipn); + + if (!s) + return &ipn; + + if (ipn.in_redir == NAT_BIMAP) { + fprintf(stderr, + "%d: extra words at the end of bimap line: %s\n", + linenum, s); + return NULL; + } + if (!strcasecmp(s, "proxy")) { + if (!(s = strtok(NULL, " \t"))) { + fprintf(stderr, + "%d: missing parameter for \"proxy\"\n", + linenum); + return NULL; + } + dport = NULL; + + if (!strcasecmp(s, "port")) { + if (!(s = strtok(NULL, " \t"))) { + fprintf(stderr, + "%d: missing parameter for \"port\"\n", + linenum); + return NULL; + } + + dport = s; + + if (!(s = strtok(NULL, " \t"))) { + fprintf(stderr, + "%d: missing parameter for \"proxy\"\n", + linenum); + return NULL; + } + } else { + fprintf(stderr, + "%d: missing keyword \"port\"\n", linenum); + return NULL; + } + if ((proto = index(s, '/'))) { + *proto++ = '\0'; + if ((pr = getprotobyname(proto))) + ipn.in_p = pr->p_proto; + else + ipn.in_p = atoi(proto); + if (dport) + ipn.in_dport = n_portnum(dport, proto, linenum); + } else { + ipn.in_p = 0; + if (dport) + ipn.in_dport = n_portnum(dport, NULL, linenum); + } + + (void) strncpy(ipn.in_plabel, s, sizeof(ipn.in_plabel)); + if ((s = strtok(NULL, " \t"))) { + fprintf(stderr, + "%d: too many parameters for \"proxy\"\n", + linenum); + return NULL; + } + return &ipn; + + } + + if (strcasecmp(s, "portmap")) { + fprintf(stderr, + "%d: expected \"portmap\" - got \"%s\"\n", linenum, s); + return NULL; + } + if (!(s = strtok(NULL, " \t"))) + return NULL; + if (!strcasecmp(s, "tcp")) + ipn.in_flags |= IPN_TCP; + else if (!strcasecmp(s, "udp")) + ipn.in_flags |= IPN_UDP; + else if (!strcasecmp(s, "tcpudp")) + ipn.in_flags |= IPN_TCPUDP; + else if (!strcasecmp(s, "tcp/udp")) + ipn.in_flags |= IPN_TCPUDP; + else { + fprintf(stderr, + "%d: expected protocol name - got \"%s\"\n", + linenum, s); + return NULL; + } + + if (!(s = strtok(NULL, " \t"))) { + fprintf(stderr, "%d: no port range found\n", linenum); + return NULL; + } + + if (!strcasecmp(s, "auto")) { + ipn.in_flags |= IPN_AUTOPORTMAP; + ipn.in_pmin = htons(1024); + ipn.in_pmax = htons(65535); + nat_setgroupmap(&ipn); + return &ipn; + } + proto = s; + if (!(t = strchr(s, ':'))) { + fprintf(stderr, "%d: no port range in \"%s\"\n", linenum, s); + return NULL; + } + *t++ = '\0'; + ipn.in_pmin = n_portnum(s, proto, linenum); + ipn.in_pmax = n_portnum(t, proto, linenum); + return &ipn; +} + + +void natparsefile(fd, file, opts) +int fd; +char *file; +int opts; +{ + char line[512], *s; + ipnat_t *np; + FILE *fp; + int linenum = 0; + + if (strcmp(file, "-")) { + if (!(fp = fopen(file, "r"))) { + fprintf(stderr, "%s: open: %s\n", file, + STRERROR(errno)); + exit(1); + } + } else + fp = stdin; + + while (fgets(line, sizeof(line) - 1, fp)) { + linenum++; + line[sizeof(line) - 1] = '\0'; + if ((s = strchr(line, '\n'))) + *s = '\0'; + + if (!(np = natparse(line, linenum))) { + if (*line) + fprintf(stderr, "%d: syntax error in \"%s\"\n", + linenum, line); + } else { + if ((opts & OPT_VERBOSE) && np) + printnat(np, opts & OPT_VERBOSE, NULL); + if (!(opts & OPT_NODO)) { + if (!(opts & OPT_REM)) { + if (ioctl(fd, SIOCADNAT, np) == -1) + perror("ioctl(SIOCADNAT)"); + } else if (ioctl(fd, SIOCRMNAT, np) == -1) + perror("ioctl(SIOCRMNAT)"); + } + } + } + if (fp != stdin) + fclose(fp); +} + + +u_32_t n_hostmask(msk) +char *msk; +{ + int bits = -1; + u_32_t mask; + + if (!isdigit(*msk)) + return (u_32_t)-1; + if (strchr(msk, '.')) + return inet_addr(msk); + if (strchr(msk, 'x')) + return (u_32_t)strtol(msk, NULL, 0); + /* + * set x most significant bits + */ + for (mask = 0, bits = atoi(msk); bits; bits--) { + mask /= 2; + mask |= ntohl(inet_addr("128.0.0.0")); + } + mask = htonl(mask); + return mask; +} + + +u_short n_portnum(name, proto, linenum) +char *name, *proto; +int linenum; +{ + struct servent *sp, *sp2; + u_short p1 = 0; + + if (isdigit(*name)) + return htons((u_short)atoi(name)); + if (!proto) + proto = "tcp/udp"; + if (strcasecmp(proto, "tcp/udp")) { + sp = getservbyname(name, proto); + if (sp) + return sp->s_port; + fprintf(stderr, "%d: unknown service \"%s\".\n", linenum, name); + return 0; + } + sp = getservbyname(name, "tcp"); + if (sp) + p1 = sp->s_port; + sp2 = getservbyname(name, "udp"); + if (!sp || !sp2) { + fprintf(stderr, "%d: unknown tcp/udp service \"%s\".\n", + linenum, name); + return 0; + } + if (p1 != sp2->s_port) { + fprintf(stderr, "%d: %s %d/tcp is a different port to ", + linenum, name, p1); + fprintf(stderr, "%d: %s %d/udp\n", linenum, name, sp->s_port); + return 0; + } + return p1; +} Index: sbin/ipfstat/Makefile =================================================================== RCS file: /cvs/src/sbin/ipfstat/Makefile,v retrieving revision 1.4 retrieving revision 1.6 diff -u -r1.4 -r1.6 --- sbin/ipfstat/Makefile 1998/09/15 09:58:33 1.4 +++ sbin/ipfstat/Makefile 1999/12/16 07:38:45 1.6 @@ -1,8 +1,8 @@ -# $OpenBSD: Makefile,v 1.4 1998/09/15 09:58:33 pattonme Exp $ +# $OpenBSD: Makefile,v 1.6 1999/12/16 07:38:45 kjell Exp $ PROG= ipfstat MAN= ipfstat.8 -SRCS= fils.c parse.c opt.c kmem.c +SRCS= fils.c parse.c opt.c kmem.c facpri.c ifaddr.c .PATH: ${.CURDIR}/../../sbin/ipf CFLAGS+=-I${.CURDIR}/../../sbin/ipf Index: sbin/ipfstat/fils.c =================================================================== RCS file: /cvs/src/sbin/ipfstat/fils.c,v retrieving revision 1.16 retrieving revision 1.20 diff -u -r1.16 -r1.20 --- sbin/ipfstat/fils.c 1999/07/08 00:05:21 1.16 +++ sbin/ipfstat/fils.c 2000/03/13 23:40:19 1.20 @@ -1,4 +1,5 @@ -/* $OpenBSD: fils.c,v 1.16 1999/07/08 00:05:21 deraadt Exp $ */ +/* $OpenBSD: fils.c,v 1.20 2000/03/13 23:40:19 kjell Exp $ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -6,11 +7,13 @@ * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ - +#ifdef __FreeBSD__ +# include +#endif #include #include #if !defined(__SVR4) && !defined(__svr4__) -#include +# include #endif #include #include @@ -28,15 +31,14 @@ #include #include #include +#if __FreeBSD_version >= 300000 +# include +#endif #include #include #include #include -#if defined(__OpenBSD__) -# include -#else -# include -#endif +#include #include #include "ipf.h" #include @@ -51,7 +53,7 @@ #if !defined(lint) static const char sccsid[] = "@(#)fils.c 1.21 4/20/96 (C) 1993-1996 Darren Reed"; -static const char rcsid[] = "@(#)$Id: fils.c,v 1.16 1999/07/08 00:05:21 deraadt Exp $"; +static const char rcsid[] = "@(#)$IPFilter: fils.c,v 2.2.2.6 2000/02/23 11:16:35 darrenr Exp $"; #endif #define F_IN 0 @@ -70,17 +72,22 @@ static void showlist __P((friostat_t *)); static void showipstates __P((int, ips_stat_t *)); static void showauthstates __P((int, fr_authstat_t *)); +static void showgroups __P((friostat_t *)); static void Usage __P((char *)); static void printlist __P((frentry_t *)); +static char *get_ifname __P((void *)); + static void Usage(name) char *name; { fprintf(stderr, - "usage: %s [-aAfhIinosv] [-d device] [-M core] [-N system]\n", name); + "usage: %s [-aAfhIinosv] [-d device] [-M core]\n", + name); exit(1); } + int main(argc,argv) int argc; char *argv[]; @@ -92,7 +99,7 @@ char *name = NULL, *device = IPL_NAME; int c, fd; - while ((c = getopt(argc, argv, "AafhIinosvd:M:")) != -1) + while ((c = getopt(argc, argv, "AafhgIinosvd:M:")) != -1) { switch (c) { @@ -108,6 +115,9 @@ case 'f' : opts |= OPT_FRSTATES; break; + case 'g' : + opts |= OPT_GROUPS; + break; case 'h' : opts |= OPT_HITS; break; @@ -202,6 +212,8 @@ showfrstates(fd, &ifrst); else if (opts & OPT_AUTHSTATS) showauthstates(fd, &frauthst); + else if (opts & OPT_GROUPS) + showgroups(&fio); else showstats(fd, &fio); } @@ -216,7 +228,7 @@ int fd; struct friostat *fp; { - int frf = 0; + u_32_t frf = 0; if (ioctl(fd, SIOCGETFF, &frf) == -1) perror("ioctl(SIOCGETFF)"); @@ -232,15 +244,19 @@ fp->f_st[0].fr_notip, fp->f_st[1].fr_notip); printf(" bad packets:\t\tin %lu\tout %lu\n", fp->f_st[0].fr_bad, fp->f_st[1].fr_bad); + printf("copied messages:\tin %lu\tout %lu\n", + fp->f_st[0].fr_copy, fp->f_st[1].fr_copy); #endif printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu", fp->f_st[0].fr_block, fp->f_st[0].fr_pass, fp->f_st[0].fr_nom); - printf(" counted %lu\n", fp->f_st[0].fr_acct); + printf(" counted %lu short %lu\n", + fp->f_st[0].fr_acct, fp->f_st[0].fr_short); printf("output packets:\t\tblocked %lu passed %lu nomatch %lu", fp->f_st[1].fr_block, fp->f_st[1].fr_pass, fp->f_st[1].fr_nom); - printf(" counted %lu\n", fp->f_st[0].fr_acct); + printf(" counted %lu short %lu\n", + fp->f_st[1].fr_acct, fp->f_st[1].fr_short); printf(" input packets logged:\tblocked %lu passed %lu\n", fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl); printf("output packets logged:\tblocked %lu passed %lu\n", @@ -374,19 +390,19 @@ printf("IP states added:\n\t%lu TCP\n\t%lu UDP\n\t%lu ICMP\n", ipsp->iss_tcp, ipsp->iss_udp, ipsp->iss_icmp); printf("\t%lu hits\n\t%lu misses\n", ipsp->iss_hits, ipsp->iss_miss); - printf("\t%lu maximum\n\t%lu no memory\n", - ipsp->iss_max, ipsp->iss_nomem); + printf("\t%lu maximum\n\t%lu no memory\n\tbuckets in use\t%lu\n", + ipsp->iss_max, ipsp->iss_nomem, ipsp->iss_inuse); printf("\t%lu active\n\t%lu expired\n\t%lu closed\n", ipsp->iss_active, ipsp->iss_expire, ipsp->iss_fin); if (kmemcpy((char *)istab, (u_long)ipsp->iss_table, sizeof(istab))) return; - for (i = 0; i < IPSTATE_SIZE; i++) + for (i = 0; i < IPSTATE_SIZE; i++) { while (istab[i]) { if (kmemcpy((char *)&ips, (u_long)istab[i], sizeof(ips)) == -1) break; printf("%s -> ", inet_ntoa(ips.is_src)); - printf("%s ttl %ld pass %d pr %d state %d/%d\n", + printf("%s ttl %ld pass %#x pr %d state %d/%d\n", inet_ntoa(ips.is_dst), ips.is_age, ips.is_pass, ips.is_p, ips.is_state[0], ips.is_state[1]); @@ -398,11 +414,20 @@ ips.is_pkts, ips.is_bytes); #endif if (ips.is_p == IPPROTO_TCP) - printf("\t%hu -> %hu %lu:%lu %hu:%hu", +#if defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011) || \ + (__FreeBSD_version >= 220000) || defined(__OpenBSD__) + printf("\t%hu -> %hu %x:%x %hu:%hu", ntohs(ips.is_sport), ntohs(ips.is_dport), - ips.is_seq, ips.is_ack, - ips.is_swin, ips.is_dwin); + ips.is_send, ips.is_dend, + ips.is_maxswin, ips.is_maxdwin); +#else + printf("\t%hu -> %hu %lx:%lx %hu:%hu", + ntohs(ips.is_sport), + ntohs(ips.is_dport), + ips.is_send, ips.is_dend, + ips.is_maxswin, ips.is_maxdwin); +#endif else if (ips.is_p == IPPROTO_UDP) printf(" %hu -> %hu", ntohs(ips.is_sport), ntohs(ips.is_dport)); @@ -417,10 +442,20 @@ printf("pass"); } else if (ips.is_pass & FR_BLOCK) { printf("block"); - if (ips.is_pass & FR_RETICMP) + switch (ips.is_pass & FR_RETMASK) + { + case FR_RETICMP : printf(" return-icmp"); - if (ips.is_pass & FR_RETRST) + break; + case FR_FAKEICMP : + printf(" return-icmp-as-dest"); + break; + case FR_RETRST : printf(" return-rst"); + break; + default : + break; + } } else if ((ips.is_pass & FR_LOGMASK) == FR_LOG) { printf("log"); if (ips.is_pass & FR_LOGBODY) @@ -435,7 +470,7 @@ else printf(" in"); - if ((ips.is_pass & (FR_LOGB|FR_LOGP)) != 0) { + if ((ips.is_pass & FR_LOG) != 0) { printf(" log"); if (ips.is_pass & FR_LOGBODY) printf(" body"); @@ -453,7 +488,8 @@ printf(" keep state"); printf("\n"); - printf("\tpkt_flags & %x = %x,\t", ips.is_flags & 0xf, + printf("\tpkt_flags & %x(%x) = %x,\t", + ips.is_flags & 0xf, ips.is_flags, ips.is_flags >> 4); printf("\tpkt_options & %x = %x\n", ips.is_optmsk, ips.is_opt); @@ -461,7 +497,12 @@ ips.is_secmsk, ips.is_sec, ips.is_authmsk, ips.is_auth); istab[i] = ips.is_next; + printf("interfaces: in %s[%p] ", + get_ifname(ips.is_ifpin), ips.is_ifpin); + printf("out %s[%p]\n", + get_ifname(ips.is_ifpout), ips.is_ifpout); } + } } @@ -470,6 +511,7 @@ ipfrstat_t *ifsp; { struct ipfr *ipfrtab[IPFT_SIZE], ifr; + frentry_t fr; int i; printf("IP fragment states:\n\t%lu new\n\t%lu expired\n\t%lu hits\n", @@ -485,10 +527,13 @@ sizeof(ifr)) == -1) break; printf("%s -> ", inet_ntoa(ifr.ipfr_src)); + if (kmemcpy((char *)&fr, (u_long)ifr.ipfr_rule, + sizeof(fr)) == -1) + break; printf("%s %d %d %d %#02x = %#x\n", inet_ntoa(ifr.ipfr_dst), ifr.ipfr_id, ifr.ipfr_ttl, ifr.ipfr_p, ifr.ipfr_tos, - ifr.ipfr_pass); + fr.fr_flags); ipfrtab[i] = ifr.ipfr_next; } } @@ -498,6 +543,8 @@ int fd; fr_authstat_t *asp; { + frauthent_t *frap, fra; + #ifdef USE_QUAD_T printf("Authorisation hits: %qd\tmisses %qd\n", asp->fas_hits, asp->fas_miss); @@ -510,4 +557,98 @@ asp->fas_sendok); printf("queok %ld\nquefail %ld\nexpire %ld\n", asp->fas_queok, asp->fas_quefail, asp->fas_expire); + + frap = asp->fas_faelist; + while (frap) { + if (kmemcpy((char *)&fra, (u_long)frap, sizeof(fra)) == -1) + break; + + printf("age %ld\t", fra.fae_age); + printfr(&fra.fae_fr); + frap = fra.fae_next; + } +} + + +static char *get_ifname(ptr) +void *ptr; +{ +#if SOLARIS + char *ifname; + ill_t ill; + + if (ptr == (void *)-1) + return "!"; + if (ptr == NULL) + return "-"; + + if (kmemcpy((char *)&ill, (u_long)ptr, sizeof(ill)) == -1) + return "X"; + ifname = malloc(ill.ill_name_length + 1); + if (kmemcpy(ifname, (u_long)ill.ill_name, + ill.ill_name_length) == -1) + return "X"; + return ifname; +#else +# if defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011) || \ + defined(__OpenBSD__) +#else + char buf[32]; + int len; +# endif + struct ifnet netif; + + if (ptr == (void *)-1) + return "!"; + if (ptr == NULL) + return "-"; + + if (kmemcpy((char *)&netif, (u_long)ptr, sizeof(netif)) == -1) + return "X"; +# if defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011) || \ + defined(__OpenBSD__) + return strdup(netif.if_xname); +# else + if (kstrncpy(buf, (u_long)netif.if_name, sizeof(buf)) == -1) + return "X"; + if (netif.if_unit < 10) + len = 2; + else if (netif.if_unit < 1000) + len = 3; + else if (netif.if_unit < 10000) + len = 4; + else + len = 5; + buf[sizeof(buf) - len] = '\0'; + sprintf(buf + strlen(buf), "%d", netif.if_unit % 10000); + return strdup(buf); +# endif +#endif +} + + +static void showgroups(fiop) +struct friostat *fiop; +{ + static char *gnames[3] = { "Filter", "Accounting", "Authentication" }; + frgroup_t *fp, grp; + int on, off, i; + + on = fiop->f_active; + off = 1 - on; + + for (i = 0; i < 3; i++) { + printf("%s groups (active):\n", gnames[i]); + for (fp = fiop->f_groups[i][on]; fp; fp = grp.fg_next) + if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp))) + break; + else + printf("%hu\n", grp.fg_num); + printf("%s groups (inactive):\n", gnames[i]); + for (fp = fiop->f_groups[i][off]; fp; fp = grp.fg_next) + if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp))) + break; + else + printf("%hu\n", grp.fg_num); + } } Index: sbin/ipfstat/kmem.c =================================================================== RCS file: /cvs/src/sbin/ipfstat/kmem.c,v retrieving revision 1.11 retrieving revision 1.15 diff -u -r1.11 -r1.15 --- sbin/ipfstat/kmem.c 1999/07/08 00:02:26 1.11 +++ sbin/ipfstat/kmem.c 2000/03/13 23:40:19 1.15 @@ -1,4 +1,5 @@ -/* $OpenBSD: kmem.c,v 1.11 1999/07/08 00:02:26 deraadt Exp $ */ +/* $OpenBSD: kmem.c,v 1.15 2000/03/13 23:40:19 kjell Exp $ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -21,7 +22,7 @@ #if !defined(lint) static const char sccsid[] = "@(#)kmem.c 1.4 1/12/96 (C) 1992 Darren Reed"; -static const char rcsid[] = "@(#)$Id: kmem.c,v 1.11 1999/07/08 00:02:26 deraadt Exp $"; +static const char rcsid[] = "@(#)$IPFilter: kmem.c,v 2.1 1999/08/04 17:30:09 darrenr Exp $"; #endif static int kmemfd = -1; @@ -68,5 +69,40 @@ buf += r; n -= r; } + return 0; +} + +int kstrncpy(buf, pos, n) +register char *buf; +long pos; +register int n; +{ + register int r; + + if (!n) + return 0; + if (kmemfd == -1) + if (openkmem(nlistf, memf) == -1) + return -1; + if (lseek(kmemfd, pos, 0) == -1) + { + perror("kmemcpy:lseek"); + return -1; + } + while (n > 0) { + r = read(kmemfd, buf, 1); + if (r <= 0) + { + perror("kmemcpy:read"); + return -1; + } + else + { + if (*buf == '\0') + break; + buf++; + n--; + } + } return 0; } Index: sbin/ipfstat/kmem.h =================================================================== RCS file: /cvs/src/sbin/ipfstat/kmem.h,v retrieving revision 1.8 retrieving revision 1.12 diff -u -r1.8 -r1.12 --- sbin/ipfstat/kmem.h 1999/07/08 00:02:26 1.8 +++ sbin/ipfstat/kmem.h 2000/03/13 23:40:19 1.12 @@ -1,11 +1,12 @@ -/* $OpenBSD: kmem.h,v 1.8 1999/07/08 00:02:26 deraadt Exp $ */ +/* $OpenBSD: kmem.h,v 1.12 2000/03/13 23:40:19 kjell Exp $ */ + /* * Copyright (C) 1993-1998 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: kmem.h,v 1.8 1999/07/08 00:02:26 deraadt Exp $ + * $IPFilter: kmem.h,v 2.1 1999/08/04 17:30:10 darrenr Exp $ */ #ifndef __KMEM_H__ @@ -20,6 +21,7 @@ #endif extern int openkmem __P((char *, char *)); extern int kmemcpy __P((char *, long, int)); +extern int kstrncpy __P((char *, long, int)); #if defined(__NetBSD__) || defined(__OpenBSD) # include Index: usr.sbin/ipmon/ipmon.c =================================================================== RCS file: /cvs/src/usr.sbin/ipmon/ipmon.c,v retrieving revision 1.18 retrieving revision 1.23 diff -u -r1.18 -r1.23 --- usr.sbin/ipmon/ipmon.c 1999/02/05 05:58:48 1.18 +++ usr.sbin/ipmon/ipmon.c 2000/03/13 23:40:20 1.23 @@ -1,4 +1,6 @@ -/* $OpenBSD: ipmon.c,v 1.18 1999/02/05 05:58:48 deraadt Exp $ +/* $OpenBSD: ipmon.c,v 1.23 2000/03/13 23:40:20 kjell Exp $ */ + +/* * Copyright (C) 1993-1998 by Darren Reed. * * Redistribution and use in source and binary forms are permitted @@ -6,8 +8,8 @@ * to the original author and the contributors. */ #if !defined(lint) -static const char sccsid[] = "@(#)ipmon.c 1.21 6/5/96 (C)1993-1997 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipmon.c,v 1.18 1999/02/05 05:58:48 deraadt Exp $"; +static const char sccsid[] = "@(#)ipmon.c 1.21 6/5/96 (C)1993-1998 Darren Reed"; +static const char rcsid[] = "@(#)$IPFilter: ipmon.c,v 2.3.2.5 2000/02/16 14:40:39 darrenr Exp $"; #endif #ifndef SOLARIS @@ -27,15 +29,18 @@ #include #include #include -#include #if !defined(__SVR4) && !defined(__svr4__) -#include -#include -#include +# if (__FreeBSD_version >= 300000) +# include +# else +# include +# endif #else -#include -#include +# include +# include #endif +#include +#include #include #include #include @@ -51,7 +56,6 @@ #include #ifndef linux # include -# include # include #endif @@ -60,11 +64,8 @@ #include #include -#if defined(__OpenBSD__) -# include -#else -# include -#endif + +#include #include #include #include @@ -120,19 +121,26 @@ static int donehup = 0; static void usage __P((char *)); static void handlehup __P((int)); -static void write_pid __P((char *)); static void flushlogs __P((char *, FILE *)); static void print_log __P((int, FILE *, char *, int)); static void print_ipflog __P((FILE *, char *, int)); static void print_natlog __P((FILE *, char *, int)); static void print_statelog __P((FILE *, char *, int)); static void dumphex __P((FILE *, u_char *, int)); -static int read_log __P((int, int *, char *, int, FILE *)); +static int read_log __P((int, int *, char *, int)); +static void write_pid __P((char *)); + char *hostname __P((int, struct in_addr)); -char *portname __P((int, char *, u_short)); +char *portname __P((int, char *, u_int)); int main __P((int, char *[])); static void logopts __P((int, char *)); +static void init_tabs __P((void)); +static char *getproto __P((u_int)); + +static char **protocols = NULL; +static char **udp_ports = NULL; +static char **tcp_ports = NULL; #define OPT_SYSLOG 0x001 @@ -145,7 +153,7 @@ #define OPT_STATE 0x100 #define OPT_FILTER 0x200 #define OPT_PORTNUM 0x400 -#define OPT_ALL (OPT_NAT|OPT_STATE|OPT_FILTER) +#define OPT_LOGALL (OPT_NAT|OPT_STATE|OPT_FILTER) #ifndef LOGFAC #define LOGFAC LOG_LOCAL0 @@ -157,16 +165,94 @@ { FILE *fp; + signal(SIGHUP, handlehup); if (logfile && (fp = fopen(logfile, "a"))) newlog = fp; + init_tabs(); donehup = 1; } + +static void init_tabs() +{ + struct protoent *p; + struct servent *s; + char *name, **tab; + int port; + + if (protocols != NULL) { + free(protocols); + protocols = NULL; + } + protocols = (char **)malloc(256 * sizeof(*protocols)); + if (protocols != NULL) { + bzero((char *)protocols, 256 * sizeof(*protocols)); + + setprotoent(1); + while ((p = getprotoent()) != NULL) + if (p->p_proto >= 0 && p->p_proto <= 255 && + p->p_name != NULL) + protocols[p->p_proto] = strdup(p->p_name); + endprotoent(); + } + + if (udp_ports != NULL) { + free(udp_ports); + udp_ports = NULL; + } + udp_ports = (char **)malloc(65536 * sizeof(*udp_ports)); + if (udp_ports != NULL) + bzero((char *)udp_ports, 65536 * sizeof(*udp_ports)); + + if (tcp_ports != NULL) { + free(tcp_ports); + tcp_ports = NULL; + } + tcp_ports = (char **)malloc(65536 * sizeof(*tcp_ports)); + if (tcp_ports != NULL) + bzero((char *)tcp_ports, 65536 * sizeof(*tcp_ports)); + + setservent(1); + while ((s = getservent()) != NULL) { + if (s->s_proto == NULL) + continue; + else if (!strcmp(s->s_proto, "tcp")) { + port = s->s_port; + name = s->s_name; + tab = tcp_ports; + } else if (!strcmp(s->s_proto, "udp")) { + port = s->s_port; + name = s->s_name; + tab = udp_ports; + } else + continue; + if ((port < 0 || port > 65535) || (name == NULL)) + continue; + tab[port] = strdup(name); + } + endservent(); +} + -static int read_log(fd, lenp, buf, bufsize, log) +static char *getproto(p) +u_int p; +{ + static char pnum[4]; + char *s; + + p &= 0xff; + s = protocols ? protocols[p] : NULL; + if (s == NULL) { + sprintf(pnum, "%u", p); + s = pnum; + } + return s; +} + + +static int read_log(fd, lenp, buf, bufsize) int fd, bufsize, *lenp; char *buf; -FILE *log; { int nr; @@ -215,18 +301,24 @@ char *portname(res, proto, port) int res; char *proto; -u_short port; +u_int port; { static char pname[8]; - struct servent *serv; + char *s; - (void) sprintf(pname, "%hu", htons(port)); + port = ntohs(port); + port &= 0xffff; + (void) sprintf(pname, "%u", port); if (!res || (opts & OPT_PORTNUM)) - return pname; - serv = getservbyport((int)port, proto); - if (!serv) return pname; - return serv->s_name; + s = NULL; + if (!strcmp(proto, "tcp")) + s = tcp_ports[port]; + else if (!strcmp(proto, "udp")) + s = udp_ports[port]; + if (s == NULL) + s = pname; + return s; } @@ -296,6 +388,7 @@ char *t = line; struct tm *tm; int res, i, len; + char *proto; nl = (struct natlog *)((char *)ipl + sizeof(*ipl)); res = (opts & OPT_RESOLVE) ? 1 : 0; @@ -322,14 +415,16 @@ sprintf(t, "Type: %d ", nl->nl_type); t += strlen(t); + proto = getproto(nl->nl_p); + (void) sprintf(t, "%s,%s <- -> ", hostname(res, nl->nl_inip), - portname(res, NULL, nl->nl_inport)); + portname(res, proto, (u_int)nl->nl_inport)); t += strlen(t); (void) sprintf(t, "%s,%s ", hostname(res, nl->nl_outip), - portname(res, NULL, nl->nl_outport)); + portname(res, proto, (u_int)nl->nl_outport)); t += strlen(t); (void) sprintf(t, "[%s,%s]", hostname(res, nl->nl_origip), - portname(res, NULL, nl->nl_origport)); + portname(res, proto, (u_int)nl->nl_origport)); t += strlen(t); if (nl->nl_type == NL_EXPIRE) { #ifdef USE_QUAD_T @@ -357,8 +452,7 @@ { struct ipslog *sl; iplog_t *ipl = (iplog_t *)buf; - struct protoent *pr; - char *t = line, *proto, pname[6]; + char *t = line, *proto; struct tm *tm; int res, i, len; @@ -380,8 +474,9 @@ if (sl->isl_type == ISL_NEW) strcpy(t, "STATE:NEW "); else if (sl->isl_type == ISL_EXPIRE) { - if (sl->isl_state[0] > TCPS_ESTABLISHED || - sl->isl_state[1] > TCPS_ESTABLISHED) + if ((sl->isl_p == IPPROTO_TCP) && + (sl->isl_state[0] > TCPS_ESTABLISHED || + sl->isl_state[1] > TCPS_ESTABLISHED)) strcpy(t, "STATE:CLOSE "); else strcpy(t, "STATE:EXPIRE "); @@ -391,21 +486,16 @@ sprintf(t, "Type: %d ", sl->isl_type); t += strlen(t); - pr = getprotobynumber((int)sl->isl_p); - if (!pr) { - proto = pname; - sprintf(proto, "%d", (u_int)sl->isl_p); - } else - proto = pr->p_name; + proto = getproto(sl->isl_p); if (sl->isl_p == IPPROTO_TCP || sl->isl_p == IPPROTO_UDP) { (void) sprintf(t, "%s,%s -> ", hostname(res, sl->isl_src), - portname(res, proto, sl->isl_sport)); + portname(res, proto, (u_int)sl->isl_sport)); t += strlen(t); (void) sprintf(t, "%s,%s PR %s", hostname(res, sl->isl_dst), - portname(res, proto, sl->isl_dport), proto); + portname(res, proto, (u_int)sl->isl_dport), proto); } else if (sl->isl_p == IPPROTO_ICMP) { (void) sprintf(t, "%s -> ", hostname(res, sl->isl_src)); t += strlen(t); @@ -487,11 +577,10 @@ char *buf; int blen; { - struct protoent *pr; tcphdr_t *tp; struct icmp *ic; struct tm *tm; - char c[3], pname[8], *t, *proto; + char *t, *proto; u_short hl, p; int i, lvl, res, len; ip_t *ipc, *ip; @@ -531,49 +620,50 @@ (defined(OpenBSD) && (OpenBSD >= 199603))) || defined(linux) len = (int)sizeof(ipf->fl_ifname); (void) sprintf(t, "%*.*s", len, len, ipf->fl_ifname); + t += strlen(t); +# if SOLARIS + if (isalpha(*(t - 1))) + *t++ = '0' + ipf->fl_unit; +# endif #else for (len = 0; len < 3; len++) - if (!ipf->fl_ifname[len]) + if (ipf->fl_ifname[len] == '\0') break; if (ipf->fl_ifname[len]) len++; (void) sprintf(t, "%*.*s%u", len, len, ipf->fl_ifname, ipf->fl_unit); -#endif t += strlen(t); +#endif (void) sprintf(t, " @%hu:%hu ", ipf->fl_group, ipf->fl_rule + 1); - pr = getprotobynumber((int)p); - if (!pr) { - proto = pname; - sprintf(proto, "%d", (u_int)p); - } else - proto = pr->p_name; + t += strlen(t); + proto = getproto(p); if (ipf->fl_flags & FF_SHORT) { - c[0] = 'S'; + *t++ = 'S'; lvl = LOG_ERR; } else if (ipf->fl_flags & FR_PASS) { if (ipf->fl_flags & FR_LOGP) - c[0] = 'p'; + *t++ = 'p'; else - c[0] = 'P'; + *t++ = 'P'; lvl = LOG_NOTICE; } else if (ipf->fl_flags & FR_BLOCK) { if (ipf->fl_flags & FR_LOGB) - c[0] = 'b'; + *t++ = 'b'; else - c[0] = 'B'; + *t++ = 'B'; lvl = LOG_WARNING; } else if (ipf->fl_flags & FF_LOGNOMATCH) { - c[0] = 'n'; + *t++ = 'n'; lvl = LOG_NOTICE; } else { - c[0] = 'L'; + *t++ = 'L'; lvl = LOG_INFO; } - c[1] = ' '; - c[2] = '\0'; - (void) strcat(line, c); - t = line + strlen(line); + if (ipf->fl_loglevel != 0xffff) + lvl = ipf->fl_loglevel; + *t++ = ' '; + *t = '\0'; if ((p == IPPROTO_TCP || p == IPPROTO_UDP) && !(ip->ip_off & IP_OFFMASK)) { @@ -581,11 +671,11 @@ if (!(ipf->fl_flags & (FI_SHORT << 16))) { (void) sprintf(t, "%s,%s -> ", hostname(res, ip->ip_src), - portname(res, proto, tp->th_sport)); + portname(res, proto, (u_int)tp->th_sport)); t += strlen(t); (void) sprintf(t, "%s,%s PR %s len %hu %hu ", hostname(res, ip->ip_dst), - portname(res, proto, tp->th_dport), + portname(res, proto, (u_int)tp->th_dport), proto, hl, ip->ip_len); t += strlen(t); @@ -596,9 +686,9 @@ *t++ = tcpfl[i].flag; if (opts & OPT_VERBOSE) { (void) sprintf(t, " %lu %lu %hu", - (u_long)tp->th_seq, - (u_long)tp->th_ack, - tp->th_win); + (u_long)(ntohl(tp->th_seq)), + (u_long)(ntohl(tp->th_ack)), + ntohs(tp->th_win)); t += strlen(t); } } @@ -610,12 +700,12 @@ hostname(res, ip->ip_dst), proto, hl, ip->ip_len); } - } else if (p == IPPROTO_ICMP) { + } else if ((p == IPPROTO_ICMP) && !(ip->ip_off & IP_OFFMASK)) { ic = (struct icmp *)((char *)ip + hl); (void) sprintf(t, "%s -> ", hostname(res, ip->ip_src)); t += strlen(t); (void) sprintf(t, "%s PR icmp len %hu %hu icmp %d/%d", - hostname(res, ip->ip_dst), hl, ntohs(ip->ip_len), + hostname(res, ip->ip_dst), hl, ip->ip_len, ic->icmp_type, ic->icmp_code); if (ic->icmp_type == ICMP_UNREACH || ic->icmp_type == ICMP_SOURCEQUENCH || @@ -625,22 +715,16 @@ ipc = &ic->icmp_ip; tp = (tcphdr_t *)((char *)ipc + hl); - p = (u_short)ipc->ip_p; - pr = getprotobynumber((int)p); - if (!pr) { - proto = pname; - (void) sprintf(proto, "%d", (int)p); - } else - proto = pr->p_name; + proto = getproto(ipc->ip_p); t += strlen(t); (void) sprintf(t, " for %s,%s -", hostname(res, ipc->ip_src), - portname(res, proto, tp->th_sport)); + portname(res, proto, (u_int)tp->th_sport)); t += strlen(t); (void) sprintf(t, " %s,%s PR %s len %hu %hu", hostname(res, ipc->ip_dst), - portname(res, proto, tp->th_dport), + portname(res, proto, (u_int)tp->th_dport), proto, ipc->ip_hl << 2, ipc->ip_len); } } else { @@ -668,6 +752,11 @@ t += strlen(t); } + if (ipf->fl_flags & FR_INQUE) + strcpy(t, " IN"); + else if (ipf->fl_flags & FR_OUTQUE) + strcpy(t, " OUT"); + t += strlen(t); *t++ = '\n'; *t++ = '\0'; if (opts & OPT_SYSLOG) @@ -675,7 +764,7 @@ else (void) fprintf(log, "%s", line); if (opts & OPT_HEXHDR) - dumphex(log, (u_char *)buf, sizeof(iplog_t)); + dumphex(log, (u_char *)buf, sizeof(iplog_t) + sizeof(*ipf)); if (opts & OPT_HEXBODY) dumphex(log, (u_char *)ip, ipf->fl_plen + ipf->fl_hlen); } @@ -712,14 +801,14 @@ char *file; FILE *log; { - int fd, cmd, flushed = 0; + int fd, flushed = 0; if ((fd = open(file, O_RDWR)) == -1) { (void) fprintf(stderr, "%s: open: %s\n", file,STRERROR(errno)); exit(-1); } - if (ioctl(fd, cmd, &flushed) == 0) { + if (ioctl(fd, SIOCIPFFB, &flushed) == 0) { printf("%d bytes flushed from log buffer\n", flushed); fflush(stdout); @@ -793,7 +882,7 @@ switch (c) { case 'a' : - opts |= OPT_ALL; + opts |= OPT_LOGALL; fdt[0] = IPL_LOGIPF; fdt[1] = IPL_LOGNAT; fdt[2] = IPL_LOGSTATE; @@ -839,7 +928,10 @@ s = strrchr(argv[0], '/'); if (s == NULL) s = argv[0]; + else + s++; openlog(s, LOG_NDELAY|LOG_PID, LOGFAC); + s = NULL; opts |= OPT_SYSLOG; log = NULL; break; @@ -866,6 +958,8 @@ usage(argv[0]); } + init_tabs(); + /* * Default action is to only open the filter log file. */ @@ -905,9 +999,10 @@ exit(-1); } setvbuf(log, NULL, _IONBF, 0); - } + } else + log = NULL; - if (make_daemon && (log != stdout)) { + if (make_daemon && ((log != stdout) || (opts & OPT_SYSLOG))) { if (fork() > 0) exit(0); write_pid(pidfile); @@ -941,7 +1036,7 @@ continue; nr += tr; - tr = read_log(fd[i], &n, buf, sizeof(buf), log); + tr = read_log(fd[i], &n, buf, sizeof(buf)); if (donehup) { donehup = 0; if (newlog) { Index: usr.sbin/ipftest/Makefile =================================================================== RCS file: /cvs/src/usr.sbin/ipftest/Makefile,v retrieving revision 1.6 retrieving revision 1.8 diff -u -r1.6 -r1.8 --- usr.sbin/ipftest/Makefile 1998/09/15 10:05:46 1.6 +++ usr.sbin/ipftest/Makefile 1999/12/16 07:38:45 1.8 @@ -1,13 +1,13 @@ -# $OpenBSD: Makefile,v 1.6 1998/09/15 10:05:46 pattonme Exp $ +# $OpenBSD: Makefile,v 1.8 1999/12/16 07:38:45 kjell Exp $ PROG= ipftest MAN= ipftest.1 SRCS= ipt.c fil.c ipft_hx.c ipft_sn.c ipft_ef.c ipft_td.c ipft_pc.c \ ipft_tx.c misc.c parse.c opt.c ip_frag.c ip_nat.c ip_state.c \ - ip_auth.c ip_fil.c ip_proxy.c + ip_auth.c ip_fil.c ip_proxy.c facpri.c natparse.c ifaddr.c .PATH: ${.CURDIR}/../../sbin/ipf ${.CURDIR}/../../sbin/ipfstat \ - ${.CURDIR}/../../sys/netinet + ${.CURDIR}/../../sys/netinet ${.CURDIR}/../../sbin/ipnat CFLAGS+=-I${.CURDIR}/../../sbin/ipf \ -I${.CURDIR} Index: usr.sbin/ipftest/ipft_ef.c =================================================================== RCS file: /cvs/src/usr.sbin/ipftest/ipft_ef.c,v retrieving revision 1.10 retrieving revision 1.14 diff -u -r1.10 -r1.14 --- usr.sbin/ipftest/ipft_ef.c 1999/02/05 05:58:45 1.10 +++ usr.sbin/ipftest/ipft_ef.c 2000/03/13 23:40:20 1.14 @@ -1,4 +1,5 @@ -/* $OpenBSD: ipft_ef.c,v 1.10 1999/02/05 05:58:45 deraadt Exp $ */ +/* $OpenBSD: ipft_ef.c,v 1.14 2000/03/13 23:40:20 kjell Exp $ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -45,18 +46,14 @@ #include #include #include -#if defined(__OpenBSD__) -# include -#else -# include -#endif +#include #include #include "ipf.h" #include "ipt.h" #if !defined(lint) static const char sccsid[] = "@(#)ipft_ef.c 1.6 2/4/96 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipft_ef.c,v 1.10 1999/02/05 05:58:45 deraadt Exp $"; +static const char rcsid[] = "@(#)$IPFilter: ipft_ef.c,v 2.1 1999/08/04 17:30:02 darrenr Exp $"; #endif static int etherf_open __P((char *)); Index: usr.sbin/ipftest/ipft_pc.c =================================================================== RCS file: /cvs/src/usr.sbin/ipftest/ipft_pc.c,v retrieving revision 1.12 retrieving revision 1.16 diff -u -r1.12 -r1.16 --- usr.sbin/ipftest/ipft_pc.c 1999/02/05 05:58:46 1.12 +++ usr.sbin/ipftest/ipft_pc.c 2000/03/13 23:40:20 1.16 @@ -1,4 +1,5 @@ -/* $OpenBSD: ipft_pc.c,v 1.12 1999/02/05 05:58:46 deraadt Exp $ */ +/* $OpenBSD: ipft_pc.c,v 1.16 2000/03/13 23:40:20 kjell Exp $ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -27,18 +28,14 @@ #include #include #include -#if defined(__OpenBSD__) -# include -#else -# include -#endif +#include #include #include "ipf.h" -#include "ipt.h" #include "pcap.h" +#include "ipt.h" #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ipft_pc.c,v 1.12 1999/02/05 05:58:46 deraadt Exp $"; +static const char rcsid[] = "@(#)$IPFilter: ipft_pc.c,v 2.1 1999/08/04 17:30:03 darrenr Exp $"; #endif struct llc { Index: usr.sbin/ipftest/ipft_td.c =================================================================== RCS file: /cvs/src/usr.sbin/ipftest/ipft_td.c,v retrieving revision 1.10 retrieving revision 1.14 diff -u -r1.10 -r1.14 --- usr.sbin/ipftest/ipft_td.c 1999/02/05 05:58:46 1.10 +++ usr.sbin/ipftest/ipft_td.c 2000/03/13 23:40:20 1.14 @@ -1,4 +1,5 @@ -/* $OpenBSD: ipft_td.c,v 1.10 1999/02/05 05:58:46 deraadt Exp $ */ +/* $OpenBSD: ipft_td.c,v 1.14 2000/03/13 23:40:20 kjell Exp $ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -54,18 +55,14 @@ #include #include #include -#if defined(__OpenBSD__) -# include -#else -# include -#endif +#include #include #include "ipf.h" #include "ipt.h" #if !defined(lint) static const char sccsid[] = "@(#)ipft_td.c 1.8 2/4/96 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipft_td.c,v 1.10 1999/02/05 05:58:46 deraadt Exp $"; +static const char rcsid[] = "@(#)$IPFilter: ipft_td.c,v 2.1 1999/08/04 17:30:04 darrenr Exp $"; #endif static int tcpd_open __P((char *)); Index: usr.sbin/ipftest/ipt.h =================================================================== RCS file: /cvs/src/usr.sbin/ipftest/ipt.h,v retrieving revision 1.6 retrieving revision 1.10 diff -u -r1.6 -r1.10 --- usr.sbin/ipftest/ipt.h 1999/02/05 05:58:47 1.6 +++ usr.sbin/ipftest/ipt.h 2000/03/13 23:40:20 1.10 @@ -1,23 +1,28 @@ -/* $OpenBSD: ipt.h,v 1.6 1999/02/05 05:58:47 deraadt Exp $ */ +/* $OpenBSD: ipt.h,v 1.10 2000/03/13 23:40:20 kjell Exp $ */ + /* * Copyright (C) 1993-1998 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: ipt.h,v 1.6 1999/02/05 05:58:47 deraadt Exp $ + * $IPFilter: ipt.h,v 2.1 1999/08/04 17:30:08 darrenr Exp $ */ #ifndef __IPT_H__ #define __IPT_H__ -#include -#ifdef __STDC__ -#include -#else -#include +#ifndef __P +# define P_DEF +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif #endif +#include + struct ipread { int (*r_open) __P((char *)); @@ -27,5 +32,10 @@ extern void debug __P((char *, ...)); extern void verbose __P((char *, ...)); + +#ifdef P_DEF +# undef __P +# undef P_DEF +#endif #endif /* __IPT_H__ */ Index: usr.sbin/ipftest/snoop.h =================================================================== RCS file: /cvs/src/usr.sbin/ipftest/snoop.h,v retrieving revision 1.5 retrieving revision 1.9 diff -u -r1.5 -r1.9 --- usr.sbin/ipftest/snoop.h 1999/02/05 05:58:47 1.5 +++ usr.sbin/ipftest/snoop.h 2000/03/13 23:40:20 1.9 @@ -1,4 +1,5 @@ -/* $OpenBSD: snoop.h,v 1.5 1999/02/05 05:58:47 deraadt Exp $ */ +/* $OpenBSD: snoop.h,v 1.9 2000/03/13 23:40:20 kjell Exp $ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -12,7 +13,7 @@ /* * written to comply with the RFC (1761) from Sun. - * $Id: snoop.h,v 1.5 1999/02/05 05:58:47 deraadt Exp $ + * $IPFilter: snoop.h,v 2.1 1999/08/04 17:30:19 darrenr Exp $ */ struct snoophdr { char s_id[8]; Index: usr.sbin/ipftest/ipft_hx.c =================================================================== RCS file: /cvs/src/usr.sbin/ipftest/ipft_hx.c,v retrieving revision 1.8 retrieving revision 1.12 diff -u -r1.8 -r1.12 --- usr.sbin/ipftest/ipft_hx.c 1999/02/05 05:58:46 1.8 +++ usr.sbin/ipftest/ipft_hx.c 2000/03/13 23:40:20 1.12 @@ -1,4 +1,5 @@ -/* $OpenBSD: ipft_hx.c,v 1.8 1999/02/05 05:58:46 deraadt Exp $ */ +/* $OpenBSD: ipft_hx.c,v 1.12 2000/03/13 23:40:20 kjell Exp $ */ + /* * Copyright (C) 1995-1998 by Darren Reed. * @@ -36,18 +37,14 @@ #include #include #include -#if defined(__OpenBSD__) -# include -#else -# include -#endif +#include #include #include "ipf.h" #include "ipt.h" #if !defined(lint) static const char sccsid[] = "@(#)ipft_hx.c 1.1 3/9/96 (C) 1996 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipft_hx.c,v 1.8 1999/02/05 05:58:46 deraadt Exp $"; +static const char rcsid[] = "@(#)$IPFilter: ipft_hx.c,v 2.1 1999/08/04 17:30:03 darrenr Exp $"; #endif extern int opts; Index: usr.sbin/ipftest/ipft_sn.c =================================================================== RCS file: /cvs/src/usr.sbin/ipftest/ipft_sn.c,v retrieving revision 1.9 retrieving revision 1.13 diff -u -r1.9 -r1.13 --- usr.sbin/ipftest/ipft_sn.c 1999/02/05 05:58:46 1.9 +++ usr.sbin/ipftest/ipft_sn.c 2000/03/13 23:40:20 1.13 @@ -1,4 +1,5 @@ -/* $OpenBSD: ipft_sn.c,v 1.9 1999/02/05 05:58:46 deraadt Exp $ */ +/* $OpenBSD: ipft_sn.c,v 1.13 2000/03/13 23:40:20 kjell Exp $ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -31,18 +32,14 @@ #include #include #include -#if defined(__OpenBSD__) -# include -#else -# include -#endif +#include #include #include "ipf.h" -#include "ipt.h" #include "snoop.h" +#include "ipt.h" #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ipft_sn.c,v 1.9 1999/02/05 05:58:46 deraadt Exp $"; +static const char rcsid[] = "@(#)$IPFilter: ipft_sn.c,v 2.1 1999/08/04 17:30:04 darrenr Exp $"; #endif struct llc { Index: usr.sbin/ipftest/ipft_tx.c =================================================================== RCS file: /cvs/src/usr.sbin/ipftest/ipft_tx.c,v retrieving revision 1.12 retrieving revision 1.16 diff -u -r1.12 -r1.16 --- usr.sbin/ipftest/ipft_tx.c 1999/02/05 05:58:46 1.12 +++ usr.sbin/ipftest/ipft_tx.c 2000/03/13 23:40:20 1.16 @@ -1,4 +1,5 @@ -/* $OpenBSD: ipft_tx.c,v 1.12 1999/02/05 05:58:46 deraadt Exp $ */ +/* $OpenBSD: ipft_tx.c,v 1.16 2000/03/13 23:40:20 kjell Exp $ */ + /* * Copyright (C) 1995-1998 by Darren Reed. * @@ -37,18 +38,14 @@ #include #include #include -#if defined(__OpenBSD__) -# include -#else -# include -#endif +#include #include #include "ipf.h" #include "ipt.h" #if !defined(lint) static const char sccsid[] = "@(#)ipft_tx.c 1.7 6/5/96 (C) 1993 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipft_tx.c,v 1.12 1999/02/05 05:58:46 deraadt Exp $"; +static const char rcsid[] = "@(#)$IPFilter: ipft_tx.c,v 2.1 1999/08/04 17:30:05 darrenr Exp $"; #endif extern int opts; @@ -201,7 +198,7 @@ *dir = 0; if (!parseline(line, (ip_t *)buf, ifn, dir)) #if 0 - return sizeof(struct tcpiphdr); + return sizeof(*ip) + sizeof(tcphdr_t); #else return sizeof(ip_t); #endif @@ -268,6 +265,9 @@ tx_proto = "icmp"; } cpp++; + } else if (isdigit(**cpp) && !index(*cpp, '.')) { + ip->ip_p = atoi(*cpp); + cpp++; } else ip->ip_p = IPPROTO_IP; @@ -314,6 +314,7 @@ cpp++; assert(tcp->th_flags != 0); tcp->th_win = htons(4096); + tcp->th_off = sizeof(*tcp) >> 2; } else if (*cpp && ip->ip_p == IPPROTO_ICMP) { extern char *tx_icmptypes[]; char **s, *t; @@ -346,5 +347,6 @@ else if (ip->ip_p == IPPROTO_ICMP) bcopy((char *)ic, ((char *)ip) + (ip->ip_hl << 2), sizeof(*ic)); + ip->ip_len = htons(ip->ip_len); return 0; } Index: usr.sbin/ipftest/ipt.c =================================================================== RCS file: /cvs/src/usr.sbin/ipftest/ipt.c,v retrieving revision 1.13 retrieving revision 1.17 diff -u -r1.13 -r1.17 --- usr.sbin/ipftest/ipt.c 1999/02/05 05:58:47 1.13 +++ usr.sbin/ipftest/ipt.c 2000/03/13 23:40:20 1.17 @@ -1,4 +1,5 @@ -/* $OpenBSD: ipt.c,v 1.13 1999/02/05 05:58:47 deraadt Exp $ */ +/* $OpenBSD: ipt.c,v 1.17 2000/03/13 23:40:20 kjell Exp $ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -46,19 +47,17 @@ #include #include #include -#if defined(__OpenBSD__) -# include -#else -# include -#endif +#include #include #include +#include +#include #include "ipf.h" #include "ipt.h" #if !defined(lint) static const char sccsid[] = "@(#)ipt.c 1.19 6/3/96 (C) 1993-1996 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipt.c,v 1.13 1999/02/05 05:58:47 deraadt Exp $"; +static const char rcsid[] = "@(#)$IPFilter: ipt.c,v 2.1.2.1 2000/01/24 14:49:11 darrenr Exp $"; #endif extern char *optarg; @@ -66,6 +65,8 @@ extern struct ipread snoop, etherf, tcpd, pcap, iptext, iphex; extern struct ifnet *get_unit __P((char *)); extern void init_ifp __P((void)); +extern ipnat_t *natparse __P((char *, int)); +extern int fr_running; int opts = 0; int main __P((int, char *[])); @@ -75,13 +76,13 @@ char *argv[]; { struct ipread *r = &iptext; - u_long buf[64]; + u_long buf[2048]; struct ifnet *ifp; char *rules = NULL, *datain = NULL, *iface = NULL; ip_t *ip; int fd, i, dir = 0, c; - while ((c = getopt(argc, argv, "bdEHi:I:oPr:STvX")) != -1) + while ((c = getopt(argc, argv, "bdEHi:I:NoPr:STvX")) != -1) switch (c) { case 'b' : @@ -111,6 +112,9 @@ case 'H' : r = &iphex; break; + case 'N' : + opts |= OPT_NAT; + break; case 'P' : r = &pcap; break; @@ -130,12 +134,16 @@ exit(-1); } + nat_init(); + fr_stateinit(); initparse(); + fr_running = 1; if (rules) { - struct frentry *fr; char line[513], *s; + void *fr; FILE *fp; + int linenum = 0; if (!strcmp(rules, "-")) fp = stdin; @@ -146,6 +154,7 @@ if (!(opts & OPT_BRIEF)) (void)printf("opening rule file \"%s\"\n", rules); while (fgets(line, sizeof(line)-1, fp)) { + linenum++; /* * treat both CR and LF as EOL */ @@ -162,14 +171,27 @@ if (!*line) continue; - if (!(fr = parse(line))) - continue; /* fake an `ioctl' call :) */ - i = IPL_EXTERN(ioctl)(0, SIOCADDFR, (caddr_t)fr, FWRITE|FREAD); - if (opts & OPT_DEBUG) - fprintf(stderr, - "iplioctl(SIOCADDFR,%p,1) = %d\n", - fr, i); + + if ((opts & OPT_NAT) != 0) { + if (!(fr = natparse(line, linenum))) + continue; + i = IPL_EXTERN(ioctl)(IPL_LOGNAT, SIOCADNAT, + fr, FWRITE|FREAD); + if (opts & OPT_DEBUG) + fprintf(stderr, + "iplioctl(ADNAT,%p,1) = %d\n", + fr, i); + } else { + if (!(fr = parse(line, linenum))) + continue; + i = IPL_EXTERN(ioctl)(0, SIOCADDFR, fr, + FWRITE|FREAD); + if (opts & OPT_DEBUG) + fprintf(stderr, + "iplioctl(ADDFR,%p,1) = %d\n", + fr, i); + } } (void)fclose(fp); } @@ -191,26 +213,30 @@ ifp = iface ? get_unit(iface) : NULL; ip->ip_off = ntohs(ip->ip_off); ip->ip_len = ntohs(ip->ip_len); - switch (fr_check(ip, ip->ip_hl << 2, ifp, dir, (mb_t **)&buf)) - { - case -2 : - (void)printf("auth"); - break; - case -1 : - (void)printf("block"); - break; - case 0 : - (void)printf("pass"); - break; - case 1 : - (void)printf("nomatch"); - break; - } + i = fr_check(ip, ip->ip_hl << 2, ifp, dir, (mb_t **)&buf); + if ((opts & OPT_NAT) == 0) + switch (i) + { + case -2 : + (void)printf("auth"); + break; + case -1 : + (void)printf("block"); + break; + case 0 : + (void)printf("pass"); + break; + case 1 : + (void)printf("nomatch"); + break; + } + if (!(opts & OPT_BRIEF)) { putchar(' '); printpacket((ip_t *)buf); printf("--------------"); - } + } else if ((opts & (OPT_BRIEF|OPT_NAT)) == (OPT_NAT|OPT_BRIEF)) + printpacket((ip_t *)buf); #ifndef linux if (dir && ifp && ip->ip_v) # ifdef __sgi @@ -219,7 +245,8 @@ (*ifp->if_output)(ifp, (void *)buf, NULL, 0); # endif #endif - putchar('\n'); + if ((opts & (OPT_BRIEF|OPT_NAT)) != (OPT_NAT|OPT_BRIEF)) + putchar('\n'); dir = 0; } (*r->r_close)(); Index: usr.sbin/ipftest/misc.c =================================================================== RCS file: /cvs/src/usr.sbin/ipftest/misc.c,v retrieving revision 1.8 retrieving revision 1.12 diff -u -r1.8 -r1.12 --- usr.sbin/ipftest/misc.c 1999/02/05 05:58:47 1.8 +++ usr.sbin/ipftest/misc.c 2000/03/13 23:40:20 1.12 @@ -1,4 +1,5 @@ -/* $OpenBSD: misc.c,v 1.8 1999/02/05 05:58:47 deraadt Exp $ */ +/* $OpenBSD: misc.c,v 1.12 2000/03/13 23:40:20 kjell Exp $ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -6,6 +7,15 @@ * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ +#if (SOLARIS2 >= 7) +# define _SYS_VARARGS_H +# define _VARARGS_H +#endif +#if defined(__STDC__) +# include +#else +# include +#endif #include #include #include @@ -36,11 +46,7 @@ #include #include #include -#if defined(__OpenBSD__) -# include -#else -# include -#endif +#include #include #include #include "ipf.h" @@ -48,7 +54,7 @@ #if !defined(lint) static const char sccsid[] = "@(#)misc.c 1.3 2/4/96 (C) 1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: misc.c,v 1.8 1999/02/05 05:58:47 deraadt Exp $"; +static const char rcsid[] = "@(#)$IPFilter: misc.c,v 2.1 1999/08/04 17:30:11 darrenr Exp $"; #endif extern int opts; @@ -60,9 +66,9 @@ tcphdr_t *tcp; tcp = (struct tcphdr *)((char *)ip + (ip->ip_hl << 2)); - printf("ip %d(%d) %d ", ip->ip_len, ip->ip_hl << 2, ip->ip_p); + printf("ip %d(%d) %d", ip->ip_len, ip->ip_hl << 2, ip->ip_p); if (ip->ip_off & IP_OFFMASK) - printf("@%d", ip->ip_off << 3); + printf(" @%d", ip->ip_off << 3); (void)printf(" %s", inet_ntoa(ip->ip_src)); if (!(ip->ip_off & IP_OFFMASK)) if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) @@ -74,8 +80,9 @@ (void)printf(",%d", ntohs(tcp->th_dport)); putchar('\n'); } + -#ifdef __STDC__ +#if defined(__STDC__) void verbose(char *fmt, ...) #else void verbose(fmt, va_alist) Index: usr.sbin/ipftest/pcap.h =================================================================== RCS file: /cvs/src/usr.sbin/ipftest/pcap.h,v retrieving revision 1.6 retrieving revision 1.10 diff -u -r1.6 -r1.10 --- usr.sbin/ipftest/pcap.h 1999/02/05 05:58:47 1.6 +++ usr.sbin/ipftest/pcap.h 2000/03/13 23:40:20 1.10 @@ -1,11 +1,12 @@ -/* $OpenBSD: pcap.h,v 1.6 1999/02/05 05:58:47 deraadt Exp $ */ +/* $OpenBSD: pcap.h,v 1.10 2000/03/13 23:40:20 kjell Exp $ */ + /* * Copyright (C) 1993-1998 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: pcap.h,v 1.6 1999/02/05 05:58:47 deraadt Exp $ + * $IPFilter: pcap.h,v 2.1 1999/08/04 17:30:17 darrenr Exp $ */ /* * This header file is constructed to match the version described by