diff options
Diffstat (limited to 'sys/contrib/pf')
-rw-r--r-- | sys/contrib/pf/net/if_pflog.c | 289 | ||||
-rw-r--r-- | sys/contrib/pf/net/if_pflog.h | 38 | ||||
-rw-r--r-- | sys/contrib/pf/net/if_pfsync.c | 1046 | ||||
-rw-r--r-- | sys/contrib/pf/net/if_pfsync.h | 96 | ||||
-rw-r--r-- | sys/contrib/pf/net/pf.c | 2074 | ||||
-rw-r--r-- | sys/contrib/pf/net/pf_if.c | 959 | ||||
-rw-r--r-- | sys/contrib/pf/net/pf_ioctl.c | 1817 | ||||
-rw-r--r-- | sys/contrib/pf/net/pf_norm.c | 291 | ||||
-rw-r--r-- | sys/contrib/pf/net/pf_osfp.c | 135 | ||||
-rw-r--r-- | sys/contrib/pf/net/pf_subr.c | 127 | ||||
-rw-r--r-- | sys/contrib/pf/net/pf_table.c | 200 | ||||
-rw-r--r-- | sys/contrib/pf/net/pfvar.h | 533 | ||||
-rw-r--r-- | sys/contrib/pf/netinet/in4_cksum.c | 127 |
13 files changed, 5094 insertions, 2638 deletions
diff --git a/sys/contrib/pf/net/if_pflog.c b/sys/contrib/pf/net/if_pflog.c index 561a2f6..6ddf212 100644 --- a/sys/contrib/pf/net/if_pflog.c +++ b/sys/contrib/pf/net/if_pflog.c @@ -1,4 +1,6 @@ -/* $OpenBSD: if_pflog.c,v 1.22 2006/12/15 09:31:20 otto Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: if_pflog.c,v 1.12 2004/05/19 17:50:51 dhartmei Exp $ */ + /* * The authors of this code are John Ioannidis (ji@tla.org), * Angelos D. Keromytis (kermit@csd.uch.gr) and @@ -33,17 +35,49 @@ * PURPOSE. */ +#ifdef __FreeBSD__ +#include "opt_inet.h" +#include "opt_inet6.h" +#endif + +#ifndef __FreeBSD__ #include "bpfilter.h" #include "pflog.h" +#elif __FreeBSD__ >= 5 +#include "opt_bpf.h" +#include "opt_pf.h" + +#ifdef DEV_BPF +#define NBPFILTER DEV_BPF +#else +#define NBPFILTER 0 +#endif + +#ifdef DEV_PFLOG +#define NPFLOG DEV_PFLOG +#else +#define NPFLOG 0 +#endif + +#endif #include <sys/param.h> #include <sys/systm.h> #include <sys/mbuf.h> -#include <sys/proc.h> #include <sys/socket.h> +#ifdef __FreeBSD__ +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/sockio.h> +#else #include <sys/ioctl.h> +#endif #include <net/if.h> +#if defined(__FreeBSD__) +#include <net/if_clone.h> +#endif #include <net/if_types.h> #include <net/route.h> #include <net/bpf.h> @@ -55,6 +89,10 @@ #include <netinet/ip.h> #endif +#ifdef __FreeBSD__ +#include <machine/in_cksum.h> +#endif + #ifdef INET6 #ifndef INET #include <netinet/in.h> @@ -65,6 +103,10 @@ #include <net/pfvar.h> #include <net/if_pflog.h> +#ifdef __FreeBSD__ +#define PFLOGNAME "pflog" +#endif + #define PFLOGMTU (32768 + MHLEN + MLEN) #ifdef PFLOGDEBUG @@ -73,91 +115,115 @@ #define DPRINTF(x) #endif +#ifndef __FreeBSD__ +struct pflog_softc pflogif[NPFLOG]; +#endif + +#ifdef __FreeBSD__ +static void pflog_clone_destroy(struct ifnet *); +static int pflog_clone_create(struct if_clone *, int, caddr_t); +#else void pflogattach(int); +#endif int pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); int pflogioctl(struct ifnet *, u_long, caddr_t); +void pflogrtrequest(int, struct rtentry *, struct sockaddr *); void pflogstart(struct ifnet *); -int pflog_clone_create(struct if_clone *, int); -int pflog_clone_destroy(struct ifnet *); - -LIST_HEAD(, pflog_softc) pflogif_list; -struct if_clone pflog_cloner = - IF_CLONE_INITIALIZER("pflog", pflog_clone_create, pflog_clone_destroy); - -struct ifnet *pflogifs[PFLOGIFS_MAX]; /* for fast access */ +#ifndef __FreeBSD__ extern int ifqmaxlen; +#endif -void -pflogattach(int npflog) +#ifdef __FreeBSD__ +static MALLOC_DEFINE(M_PFLOG, PFLOGNAME, "Packet Filter Logging Interface"); +static LIST_HEAD(pflog_list, pflog_softc) pflog_list; +#define SCP2IFP(sc) ((sc)->sc_ifp) +IFC_SIMPLE_DECLARE(pflog, 1); + +static void +pflog_clone_destroy(struct ifnet *ifp) { - int i; - LIST_INIT(&pflogif_list); - for (i = 0; i < PFLOGIFS_MAX; i++) - pflogifs[i] = NULL; - (void) pflog_clone_create(&pflog_cloner, 0); - if_clone_attach(&pflog_cloner); + struct pflog_softc *sc; + + sc = ifp->if_softc; + + /* + * Does we really need this? + */ + IF_DRAIN(&ifp->if_snd); + + bpfdetach(ifp); + if_detach(ifp); + if_free(ifp); + LIST_REMOVE(sc, sc_next); + free(sc, M_PFLOG); } -int +static int +#ifdef __FreeBSD__ +pflog_clone_create(struct if_clone *ifc, int unit, caddr_t params) +#else pflog_clone_create(struct if_clone *ifc, int unit) +#endif { + struct pflog_softc *sc; struct ifnet *ifp; - struct pflog_softc *pflogif; - int s; - if (unit >= PFLOGIFS_MAX) - return (EINVAL); - - if ((pflogif = malloc(sizeof(*pflogif), M_DEVBUF, M_NOWAIT)) == NULL) - return (ENOMEM); - bzero(pflogif, sizeof(*pflogif)); + MALLOC(sc, struct pflog_softc *, sizeof(*sc), M_PFLOG, M_WAITOK|M_ZERO); + ifp = sc->sc_ifp = if_alloc(IFT_PFLOG); + if (ifp == NULL) { + free(sc, M_PFLOG); + return (ENOSPC); + } - pflogif->sc_unit = unit; - ifp = &pflogif->sc_if; - snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", unit); - ifp->if_softc = pflogif; + if_initname(ifp, ifc->ifc_name, unit); ifp->if_mtu = PFLOGMTU; ifp->if_ioctl = pflogioctl; ifp->if_output = pflogoutput; ifp->if_start = pflogstart; - ifp->if_type = IFT_PFLOG; ifp->if_snd.ifq_maxlen = ifqmaxlen; ifp->if_hdrlen = PFLOG_HDRLEN; + ifp->if_softc = sc; if_attach(ifp); - if_alloc_sadl(ifp); + LIST_INSERT_HEAD(&pflog_list, sc, sc_next); #if NBPFILTER > 0 - bpfattach(&pflogif->sc_if.if_bpf, ifp, DLT_PFLOG, PFLOG_HDRLEN); + bpfattach(ifp, DLT_PFLOG, PFLOG_HDRLEN); #endif - s = splnet(); - LIST_INSERT_HEAD(&pflogif_list, pflogif, sc_list); - pflogifs[unit] = ifp; - splx(s); - return (0); } - -int -pflog_clone_destroy(struct ifnet *ifp) +#else /* !__FreeBSD__ */ +void +pflogattach(int npflog) { - struct pflog_softc *pflogif = ifp->if_softc; - int s; - - s = splnet(); - pflogifs[pflogif->sc_unit] = NULL; - LIST_REMOVE(pflogif, sc_list); - splx(s); + struct ifnet *ifp; + int i; + + bzero(pflogif, sizeof(pflogif)); + + for (i = 0; i < NPFLOG; i++) { + ifp = &pflogif[i].sc_if; + snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", i); + ifp->if_softc = &pflogif[i]; + ifp->if_mtu = PFLOGMTU; + ifp->if_ioctl = pflogioctl; + ifp->if_output = pflogoutput; + ifp->if_start = pflogstart; + ifp->if_type = IFT_PFLOG; + ifp->if_snd.ifq_maxlen = ifqmaxlen; + ifp->if_hdrlen = PFLOG_HDRLEN; + if_attach(ifp); + if_alloc_sadl(ifp); #if NBPFILTER > 0 - bpfdetach(ifp); + bpfattach(&pflogif[i].sc_if.if_bpf, ifp, DLT_PFLOG, + PFLOG_HDRLEN); #endif - if_detach(ifp); - free(pflogif, M_DEVBUF); - return (0); + } } +#endif /* __FreeBSD__ */ /* * Start output on the pflog interface. @@ -166,18 +232,32 @@ void pflogstart(struct ifnet *ifp) { struct mbuf *m; +#ifndef __FreeBSD__ int s; +#endif for (;;) { - s = splnet(); +#ifdef __FreeBSD__ + IF_LOCK(&ifp->if_snd); + _IF_DROP(&ifp->if_snd); + _IF_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) { + IF_UNLOCK(&ifp->if_snd); + return; + } + else + m_freem(m); + IF_UNLOCK(&ifp->if_snd); +#else + s = splimp(); IF_DROP(&ifp->if_snd); IF_DEQUEUE(&ifp->if_snd, m); splx(s); - if (m == NULL) return; else m_freem(m); +#endif } } @@ -190,6 +270,14 @@ pflogoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, } /* ARGSUSED */ +void +pflogrtrequest(int cmd, struct rtentry *rt, struct sockaddr *sa) +{ + if (rt) + rt->rt_rmx.rmx_mtu = PFLOGMTU; +} + +/* ARGSUSED */ int pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { @@ -198,10 +286,17 @@ pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data) case SIOCAIFADDR: case SIOCSIFDSTADDR: case SIOCSIFFLAGS: +#ifdef __FreeBSD__ + if (ifp->if_flags & IFF_UP) + ifp->if_drv_flags |= IFF_DRV_RUNNING; + else + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; +#else if (ifp->if_flags & IFF_UP) ifp->if_flags |= IFF_RUNNING; else ifp->if_flags &= ~IFF_RUNNING; +#endif break; default: return (EINVAL); @@ -213,18 +308,18 @@ pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data) int pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir, u_int8_t reason, struct pf_rule *rm, struct pf_rule *am, - struct pf_ruleset *ruleset, struct pf_pdesc *pd) + struct pf_ruleset *ruleset) { #if NBPFILTER > 0 struct ifnet *ifn; struct pfloghdr hdr; +#ifndef __FreeBSD__ + struct mbuf m1; +#endif - if (kif == NULL || m == NULL || rm == NULL || pd == NULL) + if (kif == NULL || m == NULL || rm == NULL) return (-1); - if ((ifn = pflogifs[rm->logif]) == NULL || !ifn->if_bpf) - return (0); - bzero(&hdr, sizeof(hdr)); hdr.length = PFLOG_REAL_HDRLEN; hdr.af = af; @@ -242,17 +337,6 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir, strlcpy(hdr.ruleset, ruleset->anchor->name, sizeof(hdr.ruleset)); } - if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done) - pd->lookup.done = pf_socket_lookup(dir, pd); - if (pd->lookup.done > 0) { - hdr.uid = pd->lookup.uid; - hdr.pid = pd->lookup.pid; - } else { - hdr.uid = UID_MAX; - hdr.pid = NO_PID; - } - hdr.rule_uid = rm->cuid; - hdr.rule_pid = rm->cpid; hdr.dir = dir; #ifdef INET @@ -265,11 +349,66 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir, } #endif /* INET */ - ifn->if_opackets++; - ifn->if_obytes += m->m_pkthdr.len; - bpf_mtap_hdr(ifn->if_bpf, (char *)&hdr, PFLOG_HDRLEN, m, - BPF_DIRECTION_OUT); +#ifndef __FreeBSD__ + m1.m_next = m; + m1.m_len = PFLOG_HDRLEN; + m1.m_data = (char *) &hdr; +#endif + +#ifdef __FreeBSD__ + KASSERT((!LIST_EMPTY(&pflog_list)), ("pflog: no interface")); + ifn = SCP2IFP(LIST_FIRST(&pflog_list)); + BPF_MTAP2(ifn, &hdr, sizeof(hdr), m); +#else + ifn = &(pflogif[0].sc_if); + + if (ifn->if_bpf) + bpf_mtap(ifn->if_bpf, &m1); +#endif #endif return (0); } + +#ifdef __FreeBSD__ +static int +pflog_modevent(module_t mod, int type, void *data) +{ + int error = 0; + + switch (type) { + case MOD_LOAD: + LIST_INIT(&pflog_list); + if_clone_attach(&pflog_cloner); + PF_LOCK(); + pflog_packet_ptr = pflog_packet; + PF_UNLOCK(); + break; + + case MOD_UNLOAD: + PF_LOCK(); + pflog_packet_ptr = NULL; + PF_UNLOCK(); + if_clone_detach(&pflog_cloner); + break; + + default: + error = EINVAL; + break; + } + + return error; +} + +static moduledata_t pflog_mod = { + "pflog", + pflog_modevent, + 0 +}; + +#define PFLOG_MODVER 1 + +DECLARE_MODULE(pflog, pflog_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); +MODULE_VERSION(pflog, PFLOG_MODVER); +MODULE_DEPEND(pflog, pf, PF_MODVER, PF_MODVER, PF_MODVER); +#endif /* __FreeBSD__ */ diff --git a/sys/contrib/pf/net/if_pflog.h b/sys/contrib/pf/net/if_pflog.h index e9e0b01..4e160a7 100644 --- a/sys/contrib/pf/net/if_pflog.h +++ b/sys/contrib/pf/net/if_pflog.h @@ -1,4 +1,6 @@ -/* $OpenBSD: if_pflog.h,v 1.14 2006/10/25 11:27:01 henning Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: if_pflog.h,v 1.11 2004/05/19 17:50:51 dhartmei Exp $ */ + /* * Copyright 2001 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -27,12 +29,13 @@ #ifndef _NET_IF_PFLOG_H_ #define _NET_IF_PFLOG_H_ -#define PFLOGIFS_MAX 16 - struct pflog_softc { - struct ifnet sc_if; /* the interface */ - int sc_unit; - LIST_ENTRY(pflog_softc) sc_list; +#ifdef __FreeBSD__ + struct ifnet *sc_ifp; /* the interface */ + LIST_ENTRY(pflog_softc) sc_next; +#else + struct ifnet sc_if; /* the interface */ +#endif }; #define PFLOG_RULESET_NAME_SIZE 16 @@ -46,10 +49,6 @@ struct pfloghdr { char ruleset[PFLOG_RULESET_NAME_SIZE]; u_int32_t rulenr; u_int32_t subrulenr; - uid_t uid; - pid_t pid; - uid_t rule_uid; - pid_t rule_pid; u_int8_t dir; u_int8_t pad[3]; }; @@ -71,10 +70,25 @@ struct old_pfloghdr { #ifdef _KERNEL +#ifdef __FreeBSD__ +struct pf_rule; +struct pf_ruleset; +struct pfi_kif; + +typedef int pflog_packet_t(struct pfi_kif *, struct mbuf *, sa_family_t, + u_int8_t, u_int8_t, struct pf_rule *, struct pf_rule *, + struct pf_ruleset *); +extern pflog_packet_t *pflog_packet_ptr; +#define PFLOG_PACKET(i,x,a,b,c,d,e,f,g) do { \ + if (pflog_packet_ptr != NULL) \ + pflog_packet_ptr(i,a,b,c,d,e,f,g); \ +} while (0) +#else #if NPFLOG > 0 -#define PFLOG_PACKET(i,x,a,b,c,d,e,f,g,h) pflog_packet(i,a,b,c,d,e,f,g,h) +#define PFLOG_PACKET(i,x,a,b,c,d,e,f,g) pflog_packet(i,a,b,c,d,e,f,g) #else -#define PFLOG_PACKET(i,x,a,b,c,d,e,f,g,h) ((void)0) +#define PFLOG_PACKET(i,x,a,b,c,d,e,f,g) ((void)0) #endif /* NPFLOG > 0 */ +#endif /* __FreeBSD__ */ #endif /* _KERNEL */ #endif /* _NET_IF_PFLOG_H_ */ diff --git a/sys/contrib/pf/net/if_pfsync.c b/sys/contrib/pf/net/if_pfsync.c index 1106339..0f5c344 100644 --- a/sys/contrib/pf/net/if_pfsync.c +++ b/sys/contrib/pf/net/if_pfsync.c @@ -1,4 +1,5 @@ -/* $OpenBSD: if_pfsync.c,v 1.73 2006/11/16 13:13:38 henning Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: if_pfsync.c,v 1.46 2005/02/20 15:58:38 mcbride Exp $ */ /* * Copyright (c) 2002 Michael Shalayeff @@ -26,27 +27,67 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ +#ifdef __FreeBSD__ +#include "opt_inet.h" +#include "opt_inet6.h" +#endif + +#ifndef __FreeBSD__ +#include "bpfilter.h" +#include "pfsync.h" +#elif __FreeBSD__ >= 5 +#include "opt_bpf.h" +#include "opt_pf.h" + +#ifdef DEV_BPF +#define NBPFILTER DEV_BPF +#else +#define NBPFILTER 0 +#endif + +#ifdef DEV_PFSYNC +#define NPFSYNC DEV_PFSYNC +#else +#define NPFSYNC 0 +#endif + +#endif #include <sys/param.h> +#ifdef __FreeBSD__ +#include <sys/priv.h> +#endif #include <sys/proc.h> #include <sys/systm.h> #include <sys/time.h> #include <sys/mbuf.h> #include <sys/socket.h> +#include <sys/kernel.h> +#ifdef __FreeBSD__ +#include <sys/endian.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/sockio.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/sysctl.h> +#else #include <sys/ioctl.h> #include <sys/timeout.h> -#include <sys/kernel.h> +#endif #include <net/if.h> +#if defined(__FreeBSD__) +#include <net/if_clone.h> +#endif #include <net/if_types.h> #include <net/route.h> #include <net/bpf.h> -#include <netinet/in.h> -#include <netinet/if_ether.h> #include <netinet/tcp.h> #include <netinet/tcp_seq.h> #ifdef INET +#include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/in_var.h> #include <netinet/ip.h> @@ -54,19 +95,32 @@ #endif #ifdef INET6 +#ifndef INET +#include <netinet/in.h> +#endif #include <netinet6/nd6.h> #endif /* INET6 */ +#ifdef __FreeBSD__ +#include "opt_carp.h" +#ifdef DEV_CARP +#define NCARP 1 +#else +#define NCARP 0 +#endif +#else #include "carp.h" +#endif #if NCARP > 0 -#include <netinet/ip_carp.h> +extern int carp_suppress_preempt; #endif #include <net/pfvar.h> #include <net/if_pfsync.h> -#include "bpfilter.h" -#include "pfsync.h" +#ifdef __FreeBSD__ +#define PFSYNCNAME "pfsync" +#endif #define PFSYNC_MINMTU \ (sizeof(struct pfsync_header) + sizeof(struct pf_state)) @@ -78,17 +132,32 @@ int pfsyncdebug; #define DPRINTF(x) #endif -struct pfsync_softc *pfsyncif = NULL; -struct pfsyncstats pfsyncstats; +#ifndef __FreeBSD__ +struct pfsync_softc pfsyncif; +#endif +struct pfsyncstats pfsyncstats; +#ifdef __FreeBSD__ +SYSCTL_DECL(_net_inet_pfsync); +SYSCTL_STRUCT(_net_inet_pfsync, 0, stats, CTLFLAG_RW, + &pfsyncstats, pfsyncstats, + "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)"); +/* + * Locking notes: + * Whenever we really touch/look at the state table we have to hold the + * PF_LOCK. Functions that do just the interface handling, grab the per + * softc lock instead. + * + */ + +static void pfsync_clone_destroy(struct ifnet *); +static int pfsync_clone_create(struct if_clone *, int, caddr_t params); +static void pfsync_senddef(void *); +#else void pfsyncattach(int); -int pfsync_clone_create(struct if_clone *, int); -int pfsync_clone_destroy(struct ifnet *); +#endif void pfsync_setmtu(struct pfsync_softc *, int); -int pfsync_alloc_scrub_memory(struct pfsync_state_peer *, - struct pf_state_peer *); -int pfsync_insert_net_state(struct pfsync_state *, u_int8_t); -void pfsync_update_net_tdb(struct pfsync_tdb *); +int pfsync_insert_net_state(struct pfsync_state *); int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); int pfsyncioctl(struct ifnet *, u_long, caddr_t); @@ -97,89 +166,160 @@ void pfsyncstart(struct ifnet *); struct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **); int pfsync_request_update(struct pfsync_state_upd *, struct in_addr *); int pfsync_sendout(struct pfsync_softc *); -int pfsync_tdb_sendout(struct pfsync_softc *); -int pfsync_sendout_mbuf(struct pfsync_softc *, struct mbuf *); void pfsync_timeout(void *); -void pfsync_tdb_timeout(void *); void pfsync_send_bus(struct pfsync_softc *, u_int8_t); void pfsync_bulk_update(void *); void pfsync_bulkfail(void *); +#ifdef __FreeBSD__ +static void pfsync_ifdetach(void *, struct ifnet *); +#endif int pfsync_sync_ok; +#ifndef __FreeBSD__ extern int ifqmaxlen; +extern struct timeval time; +extern struct timeval mono_time; +extern int hz; +#endif -struct if_clone pfsync_cloner = - IF_CLONE_INITIALIZER("pfsync", pfsync_clone_create, pfsync_clone_destroy); +#ifdef __FreeBSD__ +static MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface"); +static LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list; +#define SCP2IFP(sc) ((sc)->sc_ifp) +IFC_SIMPLE_DECLARE(pfsync, 1); -void -pfsyncattach(int npfsync) +static void +pfsync_clone_destroy(struct ifnet *ifp) { - if_clone_attach(&pfsync_cloner); + struct pfsync_softc *sc; + + sc = ifp->if_softc; +#ifdef __FreeBSD__ + EVENTHANDLER_DEREGISTER(ifnet_departure_event, sc->sc_detachtag); +#endif + callout_stop(&sc->sc_tmo); + callout_stop(&sc->sc_bulk_tmo); + callout_stop(&sc->sc_bulkfail_tmo); + + callout_stop(&sc->sc_send_tmo); + +#if NBPFILTER > 0 + bpfdetach(ifp); +#endif + if_detach(ifp); + if_free(ifp); + LIST_REMOVE(sc, sc_next); + free(sc->sc_imo.imo_membership, M_PFSYNC); + free(sc, M_PFSYNC); } -int + +static int +#ifdef __FreeBSD__ +pfsync_clone_create(struct if_clone *ifc, int unit, caddr_t params) +#else pfsync_clone_create(struct if_clone *ifc, int unit) +#endif { + struct pfsync_softc *sc; struct ifnet *ifp; - if (unit != 0) - return (EINVAL); + MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC, + M_WAITOK|M_ZERO); + ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC); + if (ifp == NULL) { + free(sc, M_PFSYNC); + return (ENOSPC); + } + +#ifdef __FreeBSD__ + sc->sc_detachtag = EVENTHANDLER_REGISTER(ifnet_departure_event, + pfsync_ifdetach, sc, EVENTHANDLER_PRI_ANY); + if (sc->sc_detachtag == NULL) { + if_free(ifp); + free(sc, M_PFSYNC); + return (ENOSPC); + } +#endif pfsync_sync_ok = 1; - if ((pfsyncif = malloc(sizeof(*pfsyncif), M_DEVBUF, M_NOWAIT)) == NULL) - return (ENOMEM); - bzero(pfsyncif, sizeof(*pfsyncif)); - pfsyncif->sc_mbuf = NULL; - pfsyncif->sc_mbuf_net = NULL; - pfsyncif->sc_mbuf_tdb = NULL; - pfsyncif->sc_statep.s = NULL; - pfsyncif->sc_statep_net.s = NULL; - pfsyncif->sc_statep_tdb.t = NULL; - pfsyncif->sc_maxupdates = 128; - pfsyncif->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP; - pfsyncif->sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP; - pfsyncif->sc_ureq_received = 0; - pfsyncif->sc_ureq_sent = 0; - pfsyncif->sc_bulk_send_next = NULL; - pfsyncif->sc_bulk_terminator = NULL; - ifp = &pfsyncif->sc_if; - snprintf(ifp->if_xname, sizeof ifp->if_xname, "pfsync%d", unit); - ifp->if_softc = pfsyncif; + sc->sc_mbuf = NULL; + sc->sc_mbuf_net = NULL; + sc->sc_statep.s = NULL; + sc->sc_statep_net.s = NULL; + sc->sc_maxupdates = 128; + sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP); + sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP); + sc->sc_ureq_received = 0; + sc->sc_ureq_sent = 0; + sc->sc_imo.imo_membership = (struct in_multi **)malloc( + (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_PFSYNC, + M_WAITOK); + sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS; + + ifp = SCP2IFP(sc); + if_initname(ifp, ifc->ifc_name, unit); ifp->if_ioctl = pfsyncioctl; ifp->if_output = pfsyncoutput; ifp->if_start = pfsyncstart; - ifp->if_type = IFT_PFSYNC; ifp->if_snd.ifq_maxlen = ifqmaxlen; ifp->if_hdrlen = PFSYNC_HDRLEN; - pfsync_setmtu(pfsyncif, ETHERMTU); - timeout_set(&pfsyncif->sc_tmo, pfsync_timeout, pfsyncif); - timeout_set(&pfsyncif->sc_tdb_tmo, pfsync_tdb_timeout, pfsyncif); - timeout_set(&pfsyncif->sc_bulk_tmo, pfsync_bulk_update, pfsyncif); - timeout_set(&pfsyncif->sc_bulkfail_tmo, pfsync_bulkfail, pfsyncif); + ifp->if_baudrate = IF_Mbps(100); + ifp->if_softc = sc; + pfsync_setmtu(sc, MCLBYTES); + callout_init(&sc->sc_tmo, NET_CALLOUT_MPSAFE); + callout_init(&sc->sc_bulk_tmo, NET_CALLOUT_MPSAFE); + callout_init(&sc->sc_bulkfail_tmo, NET_CALLOUT_MPSAFE); + callout_init(&sc->sc_send_tmo, NET_CALLOUT_MPSAFE); + sc->sc_ifq.ifq_maxlen = ifqmaxlen; + mtx_init(&sc->sc_ifq.ifq_mtx, ifp->if_xname, "pfsync send queue", + MTX_DEF); if_attach(ifp); - if_alloc_sadl(ifp); - -#if NCARP > 0 - if_addgroup(ifp, "carp"); -#endif + LIST_INSERT_HEAD(&pfsync_list, sc, sc_next); #if NBPFILTER > 0 - bpfattach(&pfsyncif->sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN); + bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN); #endif return (0); } - -int -pfsync_clone_destroy(struct ifnet *ifp) +#else /* !__FreeBSD__ */ +void +pfsyncattach(int npfsync) { + struct ifnet *ifp; + + pfsync_sync_ok = 1; + bzero(&pfsyncif, sizeof(pfsyncif)); + pfsyncif.sc_mbuf = NULL; + pfsyncif.sc_mbuf_net = NULL; + pfsyncif.sc_statep.s = NULL; + pfsyncif.sc_statep_net.s = NULL; + pfsyncif.sc_maxupdates = 128; + pfsyncif.sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP; + pfsyncif.sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP; + pfsyncif.sc_ureq_received = 0; + pfsyncif.sc_ureq_sent = 0; + ifp = &pfsyncif.sc_if; + strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname); + ifp->if_softc = &pfsyncif; + ifp->if_ioctl = pfsyncioctl; + ifp->if_output = pfsyncoutput; + ifp->if_start = pfsyncstart; + ifp->if_type = IFT_PFSYNC; + ifp->if_snd.ifq_maxlen = ifqmaxlen; + ifp->if_hdrlen = PFSYNC_HDRLEN; + pfsync_setmtu(&pfsyncif, MCLBYTES); + timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif); + timeout_set(&pfsyncif.sc_bulk_tmo, pfsync_bulk_update, &pfsyncif); + timeout_set(&pfsyncif.sc_bulkfail_tmo, pfsync_bulkfail, &pfsyncif); + if_attach(ifp); + if_alloc_sadl(ifp); + #if NBPFILTER > 0 - bpfdetach(ifp); + bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN); #endif - if_detach(ifp); - free(pfsyncif, M_DEVBUF); - pfsyncif = NULL; - return (0); } +#endif /* * Start output on the pfsync interface. @@ -187,11 +327,17 @@ pfsync_clone_destroy(struct ifnet *ifp) void pfsyncstart(struct ifnet *ifp) { +#ifdef __FreeBSD__ + IF_LOCK(&ifp->if_snd); + _IF_DROP(&ifp->if_snd); + _IF_DRAIN(&ifp->if_snd); + IF_UNLOCK(&ifp->if_snd); +#else struct mbuf *m; int s; for (;;) { - s = splnet(); + s = splimp(); IF_DROP(&ifp->if_snd); IF_DEQUEUE(&ifp->if_snd, m); splx(s); @@ -201,36 +347,26 @@ pfsyncstart(struct ifnet *ifp) else m_freem(m); } +#endif } int -pfsync_alloc_scrub_memory(struct pfsync_state_peer *s, - struct pf_state_peer *d) -{ - if (s->scrub.scrub_flag && d->scrub == NULL) { - d->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT); - if (d->scrub == NULL) - return (ENOMEM); - bzero(d->scrub, sizeof(*d->scrub)); - } - - return (0); -} - -int -pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag) +pfsync_insert_net_state(struct pfsync_state *sp) { struct pf_state *st = NULL; struct pf_rule *r = NULL; struct pfi_kif *kif; +#ifdef __FreeBSD__ + PF_ASSERT(MA_OWNED); +#endif if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) { printf("pfsync_insert_net_state: invalid creator id:" " %08x\n", ntohl(sp->creatorid)); return (EINVAL); } - kif = pfi_kif_get(sp->ifname); + kif = pfi_lookup_create(sp->ifname); if (kif == NULL) { if (pf_status.debug >= PF_DEBUG_MISC) printf("pfsync_insert_net_state: " @@ -240,33 +376,19 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag) } /* - * If the ruleset checksums match, it's safe to associate the state - * with the rule of that number. + * Just use the default rule until we have infrastructure to find the + * best matching rule. */ - if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && chksum_flag) - r = pf_main_ruleset.rules[ - PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)]; - else - r = &pf_default_rule; + r = &pf_default_rule; if (!r->max_states || r->states < r->max_states) st = pool_get(&pf_state_pl, PR_NOWAIT); if (st == NULL) { - pfi_kif_unref(kif, PFI_KIF_REF_NONE); + pfi_maybe_destroy(kif); return (ENOMEM); } bzero(st, sizeof(*st)); - /* allocate memory for scrub info */ - if (pfsync_alloc_scrub_memory(&sp->src, &st->src) || - pfsync_alloc_scrub_memory(&sp->dst, &st->dst)) { - pfi_kif_unref(kif, PFI_KIF_REF_NONE); - if (st->src.scrub) - pool_put(&pf_state_scrub_pl, st->src.scrub); - pool_put(&pf_state_pl, st); - return (ENOMEM); - } - st->rule.ptr = r; /* XXX get pointers to nat_rule and anchor */ @@ -296,14 +418,11 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag) st->creatorid = sp->creatorid; st->sync_flags = PFSTATE_FROMSYNC; + if (pf_insert_state(kif, st)) { - pfi_kif_unref(kif, PFI_KIF_REF_NONE); + pfi_maybe_destroy(kif); /* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */ r->states--; - if (st->dst.scrub) - pool_put(&pf_state_scrub_pl, st->dst.scrub); - if (st->src.scrub) - pool_put(&pf_state_scrub_pl, st->src.scrub); pool_put(&pf_state_pl, st); return (EINVAL); } @@ -312,29 +431,34 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag) } void +#ifdef __FreeBSD__ +pfsync_input(struct mbuf *m, __unused int off) +#else pfsync_input(struct mbuf *m, ...) +#endif { struct ip *ip = mtod(m, struct ip *); struct pfsync_header *ph; - struct pfsync_softc *sc = pfsyncif; - struct pf_state *st; - struct pf_state_cmp key; +#ifdef __FreeBSD__ + struct pfsync_softc *sc = LIST_FIRST(&pfsync_list); +#else + struct pfsync_softc *sc = &pfsyncif; +#endif + struct pf_state *st, key; struct pfsync_state *sp; struct pfsync_state_upd *up; struct pfsync_state_del *dp; struct pfsync_state_clr *cp; struct pfsync_state_upd_req *rup; struct pfsync_state_bus *bus; - struct pfsync_tdb *pt; struct in_addr src; struct mbuf *mp; int iplen, action, error, i, s, count, offp, sfail, stale = 0; - u_int8_t chksum_flag = 0; pfsyncstats.pfsyncs_ipackets++; /* verify that we have a sync interface configured */ - if (!sc || !sc->sc_sync_ifp || !pf_status.running) + if (!sc->sc_sync_ifp || !pf_status.running) /* XXX PF_LOCK? */ goto done; /* verify that the packet came in on the right interface */ @@ -383,9 +507,6 @@ pfsync_input(struct mbuf *m, ...) /* Cheaper to grab this now than having to mess with mbufs later */ src = ip->ip_src; - if (!bcmp(&ph->pf_chksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) - chksum_flag++; - switch (action) { case PFSYNC_ACT_CLR: { struct pf_state *nexts; @@ -400,30 +521,43 @@ pfsync_input(struct mbuf *m, ...) creatorid = cp->creatorid; s = splsoftnet(); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif if (cp->ifname[0] == '\0') { for (st = RB_MIN(pf_state_tree_id, &tree_id); st; st = nexts) { - nexts = RB_NEXT(pf_state_tree_id, &tree_id, st); + nexts = RB_NEXT(pf_state_tree_id, &tree_id, st); if (st->creatorid == creatorid) { - st->sync_flags |= PFSTATE_FROMSYNC; - pf_unlink_state(st); + st->timeout = PFTM_PURGE; + pf_purge_expired_state(st); } } } else { - if ((kif = pfi_kif_get(cp->ifname)) == NULL) { + kif = pfi_lookup_if(cp->ifname); + if (kif == NULL) { + if (pf_status.debug >= PF_DEBUG_MISC) + printf("pfsync_input: PFSYNC_ACT_CLR " + "bad interface: %s\n", cp->ifname); splx(s); - return; +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif + goto done; } for (st = RB_MIN(pf_state_tree_lan_ext, &kif->pfik_lan_ext); st; st = nexts) { nexts = RB_NEXT(pf_state_tree_lan_ext, &kif->pfik_lan_ext, st); if (st->creatorid == creatorid) { - st->sync_flags |= PFSTATE_FROMSYNC; - pf_unlink_state(st); + st->timeout = PFTM_PURGE; + pf_purge_expired_state(st); } } } +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif splx(s); break; @@ -436,6 +570,9 @@ pfsync_input(struct mbuf *m, ...) } s = splsoftnet(); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); i < count; i++, sp++) { /* check for invalid values */ @@ -451,15 +588,20 @@ pfsync_input(struct mbuf *m, ...) continue; } - if ((error = pfsync_insert_net_state(sp, - chksum_flag))) { + if ((error = pfsync_insert_net_state(sp))) { if (error == ENOMEM) { splx(s); +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif goto done; } continue; } } +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif splx(s); break; case PFSYNC_ACT_UPD: @@ -470,6 +612,9 @@ pfsync_input(struct mbuf *m, ...) } s = splsoftnet(); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); i < count; i++, sp++) { int flags = PFSYNC_FLAG_STALE; @@ -491,7 +636,7 @@ pfsync_input(struct mbuf *m, ...) st = pf_find_state_byid(&key); if (st == NULL) { /* insert the update */ - if (pfsync_insert_net_state(sp, chksum_flag)) + if (pfsync_insert_net_state(sp)) pfsyncstats.pfsyncs_badstate++; continue; } @@ -530,7 +675,7 @@ pfsync_input(struct mbuf *m, ...) */ if (st->src.state > sp->src.state) sfail = 5; - else if (st->dst.state > sp->dst.state) + else if ( st->dst.state > sp->dst.state) sfail = 6; } if (sfail) { @@ -540,7 +685,11 @@ pfsync_input(struct mbuf *m, ...) "creatorid: %08x\n", (sfail < 7 ? "ignoring" : "partial"), sfail, +#ifdef __FreeBSD__ + (unsigned long long)be64toh(st->id), +#else betoh64(st->id), +#endif ntohl(st->creatorid)); pfsyncstats.pfsyncs_badstate++; @@ -555,7 +704,6 @@ pfsync_input(struct mbuf *m, ...) } continue; } - pfsync_alloc_scrub_memory(&sp->dst, &st->dst); pf_state_peer_ntoh(&sp->src, &st->src); pf_state_peer_ntoh(&sp->dst, &st->dst); st->expire = ntohl(sp->expire) + time_second; @@ -563,6 +711,9 @@ pfsync_input(struct mbuf *m, ...) } if (stale && sc->sc_mbuf != NULL) pfsync_sendout(sc); +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif splx(s); break; /* @@ -577,6 +728,9 @@ pfsync_input(struct mbuf *m, ...) } s = splsoftnet(); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); i < count; i++, sp++) { bcopy(sp->id, &key.id, sizeof(key.id)); @@ -587,9 +741,13 @@ pfsync_input(struct mbuf *m, ...) pfsyncstats.pfsyncs_badstate++; continue; } + st->timeout = PFTM_PURGE; st->sync_flags |= PFSTATE_FROMSYNC; - pf_unlink_state(st); + pf_purge_expired_state(st); } +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif splx(s); break; case PFSYNC_ACT_UPD_C: { @@ -602,6 +760,9 @@ pfsync_input(struct mbuf *m, ...) } s = splsoftnet(); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp); i < count; i++, up++) { /* check for invalid values */ @@ -665,7 +826,11 @@ pfsync_input(struct mbuf *m, ...) printf("pfsync: ignoring stale update " "(%d) id: %016llx " "creatorid: %08x\n", sfail, +#ifdef __FreeBSD__ + (unsigned long long)be64toh(st->id), +#else betoh64(st->id), +#endif ntohl(st->creatorid)); pfsyncstats.pfsyncs_badstate++; @@ -681,7 +846,6 @@ pfsync_input(struct mbuf *m, ...) PFSYNC_FLAG_STALE); continue; } - pfsync_alloc_scrub_memory(&up->dst, &st->dst); pf_state_peer_ntoh(&up->src, &st->src); pf_state_peer_ntoh(&up->dst, &st->dst); st->expire = ntohl(up->expire) + time_second; @@ -689,6 +853,9 @@ pfsync_input(struct mbuf *m, ...) } if ((update_requested || stale) && sc->sc_mbuf) pfsync_sendout(sc); +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif splx(s); break; } @@ -700,6 +867,9 @@ pfsync_input(struct mbuf *m, ...) } s = splsoftnet(); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp); i < count; i++, dp++) { bcopy(dp->id, &key.id, sizeof(key.id)); @@ -710,9 +880,13 @@ pfsync_input(struct mbuf *m, ...) pfsyncstats.pfsyncs_badstate++; continue; } + st->timeout = PFTM_PURGE; st->sync_flags |= PFSTATE_FROMSYNC; - pf_unlink_state(st); + pf_purge_expired_state(st); } +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif splx(s); break; case PFSYNC_ACT_INS_F: @@ -727,6 +901,9 @@ pfsync_input(struct mbuf *m, ...) } s = splsoftnet(); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif if (sc->sc_mbuf != NULL) pfsync_sendout(sc); for (i = 0, @@ -737,15 +914,17 @@ pfsync_input(struct mbuf *m, ...) if (key.id == 0 && key.creatorid == 0) { sc->sc_ureq_received = time_uptime; - if (sc->sc_bulk_send_next == NULL) - sc->sc_bulk_send_next = - TAILQ_FIRST(&state_list); - sc->sc_bulk_terminator = sc->sc_bulk_send_next; if (pf_status.debug >= PF_DEBUG_MISC) printf("pfsync: received " "bulk update request\n"); pfsync_send_bus(sc, PFSYNC_BUS_START); +#ifdef __FreeBSD__ + callout_reset(&sc->sc_bulk_tmo, 1 * hz, + pfsync_bulk_update, + LIST_FIRST(&pfsync_list)); +#else timeout_add(&sc->sc_bulk_tmo, 1 * hz); +#endif } else { st = pf_find_state_byid(&key); if (st == NULL) { @@ -759,6 +938,9 @@ pfsync_input(struct mbuf *m, ...) } if (sc->sc_mbuf != NULL) pfsync_sendout(sc); +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif splx(s); break; case PFSYNC_ACT_BUS: @@ -774,9 +956,16 @@ pfsync_input(struct mbuf *m, ...) bus = (struct pfsync_state_bus *)(mp->m_data + offp); switch (bus->status) { case PFSYNC_BUS_START: +#ifdef __FreeBSD__ + callout_reset(&sc->sc_bulkfail_tmo, + pf_pool_limits[PF_LIMIT_STATES].limit / + (PFSYNC_BULKPACKETS * sc->sc_maxcount), + pfsync_bulkfail, LIST_FIRST(&pfsync_list)); +#else timeout_add(&sc->sc_bulkfail_tmo, pf_pool_limits[PF_LIMIT_STATES].limit / (PFSYNC_BULKPACKETS * sc->sc_maxcount)); +#endif if (pf_status.debug >= PF_DEBUG_MISC) printf("pfsync: received bulk " "update start\n"); @@ -787,10 +976,14 @@ pfsync_input(struct mbuf *m, ...) /* that's it, we're happy */ sc->sc_ureq_sent = 0; sc->sc_bulk_tries = 0; +#ifdef __FreeBSD__ + callout_stop(&sc->sc_bulkfail_tmo); +#else timeout_del(&sc->sc_bulkfail_tmo); -#if NCARP > 0 +#endif +#if NCARP > 0 /* XXX_IMPORT */ if (!pfsync_sync_ok) - carp_group_demote_adj(&sc->sc_if, -1); + carp_suppress_preempt--; #endif pfsync_sync_ok = 1; if (pf_status.debug >= PF_DEBUG_MISC) @@ -804,18 +997,6 @@ pfsync_input(struct mbuf *m, ...) break; } break; - case PFSYNC_ACT_TDB_UPD: - if ((mp = m_pulldown(m, iplen + sizeof(*ph), - count * sizeof(*pt), &offp)) == NULL) { - pfsyncstats.pfsyncs_badlen++; - return; - } - s = splsoftnet(); - for (i = 0, pt = (struct pfsync_tdb *)(mp->m_data + offp); - i < count; i++, pt++) - pfsync_update_net_tdb(pt); - splx(s); - break; } done: @@ -835,7 +1016,9 @@ pfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, int pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { +#ifndef __FreeBSD__ struct proc *p = curproc; +#endif struct pfsync_softc *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *)data; struct ip_moptions *imo = &sc->sc_imo; @@ -848,10 +1031,17 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) case SIOCAIFADDR: case SIOCSIFDSTADDR: case SIOCSIFFLAGS: +#ifdef __FreeBSD__ + if (ifp->if_flags & IFF_UP) + ifp->if_drv_flags |= IFF_DRV_RUNNING; + else + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; +#else if (ifp->if_flags & IFF_UP) ifp->if_flags |= IFF_RUNNING; else ifp->if_flags &= ~IFF_RUNNING; +#endif break; case SIOCSIFMTU: if (ifr->ifr_mtu < PFSYNC_MINMTU) @@ -859,12 +1049,22 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) if (ifr->ifr_mtu > MCLBYTES) ifr->ifr_mtu = MCLBYTES; s = splnet(); - if (ifr->ifr_mtu < ifp->if_mtu) +#ifdef __FreeBSD__ + PF_LOCK(); +#endif + if (ifr->ifr_mtu < ifp->if_mtu) { pfsync_sendout(sc); + } pfsync_setmtu(sc, ifr->ifr_mtu); +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif splx(s); break; case SIOCGETPFSYNC: +#ifdef __FreeBSD__ + /* XXX: read unlocked */ +#endif bzero(&pfsyncr, sizeof(pfsyncr)); if (sc->sc_sync_ifp) strlcpy(pfsyncr.pfsyncr_syncdev, @@ -875,19 +1075,31 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) return (error); break; case SIOCSETPFSYNC: +#ifdef __FreeBSD__ + if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0) +#else if ((error = suser(p, p->p_acflag)) != 0) +#endif return (error); if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr)))) return (error); if (pfsyncr.pfsyncr_syncpeer.s_addr == 0) +#ifdef __FreeBSD__ + sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP); +#else sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP; +#endif else sc->sc_sync_peer.s_addr = pfsyncr.pfsyncr_syncpeer.s_addr; if (pfsyncr.pfsyncr_maxupdates > 255) return (EINVAL); +#ifdef __FreeBSD__ + callout_drain(&sc->sc_send_tmo); + PF_LOCK(); +#endif sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates; if (pfsyncr.pfsyncr_syncdev[0] == 0) { @@ -904,21 +1116,36 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); imo->imo_multicast_ifp = NULL; } +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif break; } - if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) + if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) { +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif return (EINVAL); + } s = splnet(); +#ifdef __FreeBSD__ + if (sifp->if_mtu < SCP2IFP(sc)->if_mtu || +#else if (sifp->if_mtu < sc->sc_if.if_mtu || +#endif (sc->sc_sync_ifp != NULL && sifp->if_mtu < sc->sc_sync_ifp->if_mtu) || sifp->if_mtu < MCLBYTES - sizeof(struct ip)) pfsync_sendout(sc); sc->sc_sync_ifp = sifp; +#ifdef __FreeBSD__ + pfsync_setmtu(sc, SCP2IFP(sc)->if_mtu); +#else pfsync_setmtu(sc, sc->sc_if.if_mtu); +#endif if (imo->imo_num_memberships > 0) { in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); @@ -926,16 +1153,27 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } if (sc->sc_sync_ifp && +#ifdef __FreeBSD__ + sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { +#else sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) { +#endif struct in_addr addr; if (!(sc->sc_sync_ifp->if_flags & IFF_MULTICAST)) { sc->sc_sync_ifp = NULL; +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif splx(s); return (EADDRNOTAVAIL); } - +#ifdef __FreeBSD__ + PF_UNLOCK(); /* addmulti mallocs w/ WAITOK */ + addr.s_addr = htonl(INADDR_PFSYNC_GROUP); +#else addr.s_addr = INADDR_PFSYNC_GROUP; +#endif if ((imo->imo_membership[0] = in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) { @@ -947,27 +1185,45 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) imo->imo_multicast_ifp = sc->sc_sync_ifp; imo->imo_multicast_ttl = PFSYNC_DFLTTL; imo->imo_multicast_loop = 0; +#ifdef __FreeBSD__ + PF_LOCK(); +#endif } if (sc->sc_sync_ifp || +#ifdef __FreeBSD__ + sc->sc_sendaddr.s_addr != htonl(INADDR_PFSYNC_GROUP)) { +#else sc->sc_sendaddr.s_addr != INADDR_PFSYNC_GROUP) { +#endif /* Request a full state table update. */ sc->sc_ureq_sent = time_uptime; #if NCARP > 0 if (pfsync_sync_ok) - carp_group_demote_adj(&sc->sc_if, 1); + carp_suppress_preempt++; #endif pfsync_sync_ok = 0; if (pf_status.debug >= PF_DEBUG_MISC) printf("pfsync: requesting bulk update\n"); +#ifdef __FreeBSD__ + callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, + pfsync_bulkfail, LIST_FIRST(&pfsync_list)); +#else timeout_add(&sc->sc_bulkfail_tmo, 5 * hz); +#endif error = pfsync_request_update(NULL, NULL); if (error == ENOMEM) { +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif splx(s); return (ENOMEM); } pfsync_sendout(sc); } +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif splx(s); break; @@ -993,8 +1249,13 @@ pfsync_setmtu(struct pfsync_softc *sc, int mtu_req) sizeof(struct pfsync_state); if (sc->sc_maxcount > 254) sc->sc_maxcount = 254; +#ifdef __FreeBSD__ + SCP2IFP(sc)->if_mtu = sizeof(struct pfsync_header) + + sc->sc_maxcount * sizeof(struct pfsync_state); +#else sc->sc_if.if_mtu = sizeof(struct pfsync_header) + sc->sc_maxcount * sizeof(struct pfsync_state); +#endif } struct mbuf * @@ -1004,9 +1265,16 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp) struct mbuf *m; int len; +#ifdef __FreeBSD__ + PF_ASSERT(MA_OWNED); +#endif MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) { +#ifdef __FreeBSD__ + SCP2IFP(sc)->if_oerrors++; +#else sc->sc_if.if_oerrors++; +#endif return (NULL); } @@ -1031,10 +1299,6 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp) len = sizeof(struct pfsync_header) + sizeof(struct pfsync_state_bus); break; - case PFSYNC_ACT_TDB_UPD: - len = (sc->sc_maxcount * sizeof(struct pfsync_tdb)) + - sizeof(struct pfsync_header); - break; default: len = (sc->sc_maxcount * sizeof(struct pfsync_state)) + sizeof(struct pfsync_header); @@ -1045,7 +1309,11 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp) MCLGET(m, M_DONTWAIT); if ((m->m_flags & M_EXT) == 0) { m_free(m); +#ifdef __FreeBSD__ + SCP2IFP(sc)->if_oerrors++; +#else sc->sc_if.if_oerrors++; +#endif return (NULL); } m->m_data += (MCLBYTES - len) &~ (sizeof(long) - 1); @@ -1059,23 +1327,26 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp) h->af = 0; h->count = 0; h->action = action; - if (action != PFSYNC_ACT_TDB_UPD) - bcopy(&pf_status.pf_chksum, &h->pf_chksum, - PF_MD5_DIGEST_LENGTH); *sp = (void *)((char *)h + PFSYNC_HDRLEN); - if (action == PFSYNC_ACT_TDB_UPD) - timeout_add(&sc->sc_tdb_tmo, hz); - else - timeout_add(&sc->sc_tmo, hz); +#ifdef __FreeBSD__ + callout_reset(&sc->sc_tmo, hz, pfsync_timeout, + LIST_FIRST(&pfsync_list)); +#else + timeout_add(&sc->sc_tmo, hz); +#endif return (m); } int pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags) { - struct ifnet *ifp = NULL; - struct pfsync_softc *sc = pfsyncif; +#ifdef __FreeBSD__ + struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list)); +#else + struct ifnet *ifp = &pfsyncif.sc_if; +#endif + struct pfsync_softc *sc = ifp->if_softc; struct pfsync_header *h, *h_net; struct pfsync_state *sp = NULL; struct pfsync_state_upd *up = NULL; @@ -1085,16 +1356,19 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags) int s, ret = 0; u_int8_t i = 255, newaction = 0; - if (sc == NULL) - return (0); - ifp = &sc->sc_if; - +#ifdef __FreeBSD__ + PF_ASSERT(MA_OWNED); +#endif /* * If a packet falls in the forest and there's nobody around to * hear, does it make a sound? */ if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL && +#ifdef __FreeBSD__ + sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { +#else sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) { +#endif /* Don't leave any stale pfsync packets hanging around. */ if (sc->sc_mbuf != NULL) { m_freem(sc->sc_mbuf); @@ -1151,6 +1425,8 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags) secs = time_second; st->pfsync_time = time_uptime; + TAILQ_REMOVE(&state_updates, st, u.s.entry_updates); + TAILQ_INSERT_TAIL(&state_updates, st, u.s.entry_updates); if (sp == NULL) { /* not a "duplicate" update */ @@ -1172,10 +1448,10 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags) bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); sp->creation = htonl(secs - st->creation); - pf_state_counter_hton(st->packets[0], sp->packets[0]); - pf_state_counter_hton(st->packets[1], sp->packets[1]); - pf_state_counter_hton(st->bytes[0], sp->bytes[0]); - pf_state_counter_hton(st->bytes[1], sp->bytes[1]); + sp->packets[0] = htonl(st->packets[0]); + sp->packets[1] = htonl(st->packets[1]); + sp->bytes[0] = htonl(st->bytes[0]); + sp->bytes[1] = htonl(st->bytes[1]); if ((r = st->rule.ptr) == NULL) sp->rule = htonl(-1); else @@ -1274,16 +1550,19 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags) int pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src) { - struct ifnet *ifp = NULL; +#ifdef __FreeBSD__ + struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list)); +#else + struct ifnet *ifp = &pfsyncif.sc_if; +#endif struct pfsync_header *h; - struct pfsync_softc *sc = pfsyncif; + struct pfsync_softc *sc = ifp->if_softc; struct pfsync_state_upd_req *rup; int ret = 0; - if (sc == NULL) - return (0); - - ifp = &sc->sc_if; +#ifdef __FreeBSD__ + PF_ASSERT(MA_OWNED); +#endif if (sc->sc_mbuf == NULL) { if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ, (void *)&sc->sc_statep.s)) == NULL) @@ -1320,16 +1599,19 @@ pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src) int pfsync_clear_states(u_int32_t creatorid, char *ifname) { - struct ifnet *ifp = NULL; - struct pfsync_softc *sc = pfsyncif; +#ifdef __FreeBSD__ + struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list)); +#else + struct ifnet *ifp = &pfsyncif.sc_if; +#endif + struct pfsync_softc *sc = ifp->if_softc; struct pfsync_state_clr *cp; int s, ret; - if (sc == NULL) - return (0); - - ifp = &sc->sc_if; s = splnet(); +#ifdef __FreeBSD__ + PF_ASSERT(MA_OWNED); +#endif if (sc->sc_mbuf != NULL) pfsync_sendout(sc); if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR, @@ -1355,18 +1637,13 @@ pfsync_timeout(void *v) int s; s = splnet(); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif pfsync_sendout(sc); - splx(s); -} - -void -pfsync_tdb_timeout(void *v) -{ - struct pfsync_softc *sc = v; - int s; - - s = splnet(); - pfsync_tdb_sendout(sc); +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif splx(s); } @@ -1376,6 +1653,9 @@ pfsync_send_bus(struct pfsync_softc *sc, u_int8_t status) { struct pfsync_state_bus *bus; +#ifdef __FreeBSD__ + PF_ASSERT(MA_OWNED); +#endif if (sc->sc_mbuf != NULL) pfsync_sendout(sc); @@ -1398,6 +1678,9 @@ pfsync_bulk_update(void *v) int s, i = 0; struct pf_state *state; +#ifdef __FreeBSD__ + PF_LOCK(); +#endif s = splnet(); if (sc->sc_mbuf != NULL) pfsync_sendout(sc); @@ -1406,43 +1689,44 @@ pfsync_bulk_update(void *v) * Grab at most PFSYNC_BULKPACKETS worth of states which have not * been sent since the latest request was made. */ - state = sc->sc_bulk_send_next; - if (state) - do { - /* send state update if syncable and not already sent */ - if (!state->sync_flags - && state->timeout < PFTM_MAX - && state->pfsync_time <= sc->sc_ureq_received) { + while ((state = TAILQ_FIRST(&state_updates)) != NULL && + ++i < (sc->sc_maxcount * PFSYNC_BULKPACKETS)) { + if (state->pfsync_time > sc->sc_ureq_received) { + /* we're done */ + pfsync_send_bus(sc, PFSYNC_BUS_END); + sc->sc_ureq_received = 0; +#ifdef __FreeBSD__ + callout_stop(&sc->sc_bulk_tmo); +#else + timeout_del(&sc->sc_bulk_tmo); +#endif + if (pf_status.debug >= PF_DEBUG_MISC) + printf("pfsync: bulk update complete\n"); + break; + } else { + /* send an update and move to end of list */ + if (!state->sync_flags) pfsync_pack_state(PFSYNC_ACT_UPD, state, 0); - i++; - } - - /* figure next state to send */ - state = TAILQ_NEXT(state, u.s.entry_list); - - /* wrap to start of list if we hit the end */ - if (!state) - state = TAILQ_FIRST(&state_list); - } while (i < sc->sc_maxcount * PFSYNC_BULKPACKETS && - state != sc->sc_bulk_terminator); - - if (!state || state == sc->sc_bulk_terminator) { - /* we're done */ - pfsync_send_bus(sc, PFSYNC_BUS_END); - sc->sc_ureq_received = 0; - sc->sc_bulk_send_next = NULL; - sc->sc_bulk_terminator = NULL; - timeout_del(&sc->sc_bulk_tmo); - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync: bulk update complete\n"); - } else { - /* look again for more in a bit */ - timeout_add(&sc->sc_bulk_tmo, 1); - sc->sc_bulk_send_next = state; + state->pfsync_time = time_uptime; + TAILQ_REMOVE(&state_updates, state, u.s.entry_updates); + TAILQ_INSERT_TAIL(&state_updates, state, + u.s.entry_updates); + + /* look again for more in a bit */ +#ifdef __FreeBSD__ + callout_reset(&sc->sc_bulk_tmo, 1, pfsync_timeout, + LIST_FIRST(&pfsync_list)); +#else + timeout_add(&sc->sc_bulk_tmo, 1); +#endif + } } if (sc->sc_mbuf != NULL) pfsync_sendout(sc); splx(s); +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif } void @@ -1451,9 +1735,17 @@ pfsync_bulkfail(void *v) struct pfsync_softc *sc = v; int s, error; +#ifdef __FreeBSD__ + PF_LOCK(); +#endif if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) { /* Try again in a bit */ +#ifdef __FreeBSD__ + callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail, + LIST_FIRST(&pfsync_list)); +#else timeout_add(&sc->sc_bulkfail_tmo, 5 * hz); +#endif s = splnet(); error = pfsync_request_update(NULL, NULL); if (error == ENOMEM) { @@ -1469,26 +1761,43 @@ pfsync_bulkfail(void *v) sc->sc_bulk_tries = 0; #if NCARP > 0 if (!pfsync_sync_ok) - carp_group_demote_adj(&sc->sc_if, -1); + carp_suppress_preempt--; #endif pfsync_sync_ok = 1; if (pf_status.debug >= PF_DEBUG_MISC) printf("pfsync: failed to receive " "bulk update status\n"); +#ifdef __FreeBSD__ + callout_stop(&sc->sc_bulkfail_tmo); +#else timeout_del(&sc->sc_bulkfail_tmo); +#endif } +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif } /* This must be called in splnet() */ int -pfsync_sendout(struct pfsync_softc *sc) +pfsync_sendout(sc) + struct pfsync_softc *sc; { #if NBPFILTER > 0 - struct ifnet *ifp = &sc->sc_if; +# ifdef __FreeBSD__ + struct ifnet *ifp = SCP2IFP(sc); +# else + struct ifnet *ifp = &sc->if_sc; +# endif #endif struct mbuf *m; +#ifdef __FreeBSD__ + PF_ASSERT(MA_OWNED); + callout_stop(&sc->sc_tmo); +#else timeout_del(&sc->sc_tmo); +#endif if (sc->sc_mbuf == NULL) return (0); @@ -1496,9 +1805,16 @@ pfsync_sendout(struct pfsync_softc *sc) sc->sc_mbuf = NULL; sc->sc_statep.s = NULL; +#ifdef __FreeBSD__ + KASSERT(m != NULL, ("pfsync_sendout: null mbuf")); +#endif #if NBPFILTER > 0 +#ifdef __FreeBSD__ + BPF_MTAP(ifp, m); +#else if (ifp->if_bpf) - bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); + bpf_mtap(ifp->if_bpf, m); +#endif #endif if (sc->sc_mbuf_net) { @@ -1508,41 +1824,15 @@ pfsync_sendout(struct pfsync_softc *sc) sc->sc_statep_net.s = NULL; } - return pfsync_sendout_mbuf(sc, m); -} - -int -pfsync_tdb_sendout(struct pfsync_softc *sc) -{ -#if NBPFILTER > 0 - struct ifnet *ifp = &sc->sc_if; -#endif - struct mbuf *m; - - timeout_del(&sc->sc_tdb_tmo); - - if (sc->sc_mbuf_tdb == NULL) - return (0); - m = sc->sc_mbuf_tdb; - sc->sc_mbuf_tdb = NULL; - sc->sc_statep_tdb.t = NULL; - -#if NBPFILTER > 0 - if (ifp->if_bpf) - bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); +#ifdef __FreeBSD__ + if (sc->sc_sync_ifp || + sc->sc_sync_peer.s_addr != htonl(INADDR_PFSYNC_GROUP)) { +#else + if (sc->sc_sync_ifp ||sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) { #endif + struct ip *ip; + struct sockaddr sa; - return pfsync_sendout_mbuf(sc, m); -} - -int -pfsync_sendout_mbuf(struct pfsync_softc *sc, struct mbuf *m) -{ - struct sockaddr sa; - struct ip *ip; - - if (sc->sc_sync_ifp || - sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) { M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); if (m == NULL) { pfsyncstats.pfsyncs_onomem++; @@ -1552,9 +1842,17 @@ pfsync_sendout_mbuf(struct pfsync_softc *sc, struct mbuf *m) ip->ip_v = IPVERSION; ip->ip_hl = sizeof(*ip) >> 2; ip->ip_tos = IPTOS_LOWDELAY; +#ifdef __FreeBSD__ + ip->ip_len = m->m_pkthdr.len; +#else ip->ip_len = htons(m->m_pkthdr.len); +#endif ip->ip_id = htons(ip_randomid()); +#ifdef __FreeBSD__ + ip->ip_off = IP_DF; +#else ip->ip_off = htons(IP_DF); +#endif ip->ip_ttl = PFSYNC_DFLTTL; ip->ip_p = IPPROTO_PFSYNC; ip->ip_sum = 0; @@ -1562,168 +1860,118 @@ pfsync_sendout_mbuf(struct pfsync_softc *sc, struct mbuf *m) bzero(&sa, sizeof(sa)); ip->ip_src.s_addr = INADDR_ANY; +#ifdef __FreeBSD__ + if (sc->sc_sendaddr.s_addr == htonl(INADDR_PFSYNC_GROUP)) +#else if (sc->sc_sendaddr.s_addr == INADDR_PFSYNC_GROUP) +#endif m->m_flags |= M_MCAST; ip->ip_dst = sc->sc_sendaddr; sc->sc_sendaddr.s_addr = sc->sc_sync_peer.s_addr; pfsyncstats.pfsyncs_opackets++; - +#ifdef __FreeBSD__ + if (!IF_HANDOFF(&sc->sc_ifq, m, NULL)) + pfsyncstats.pfsyncs_oerrors++; + callout_reset(&sc->sc_send_tmo, 1, pfsync_senddef, sc); +#else if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)) pfsyncstats.pfsyncs_oerrors++; +#endif } else m_freem(m); return (0); } -/* Update an in-kernel tdb. Silently fail if no tdb is found. */ -void -pfsync_update_net_tdb(struct pfsync_tdb *pt) +#ifdef __FreeBSD__ +static void +pfsync_ifdetach(void *arg, struct ifnet *ifp) { - struct tdb *tdb; - int s; - - /* check for invalid values */ - if (ntohl(pt->spi) <= SPI_RESERVED_MAX || - (pt->dst.sa.sa_family != AF_INET && - pt->dst.sa.sa_family != AF_INET6)) - goto bad; - - s = spltdb(); - tdb = gettdb(pt->spi, &pt->dst, pt->sproto); - if (tdb) { - pt->rpl = ntohl(pt->rpl); - pt->cur_bytes = betoh64(pt->cur_bytes); - - /* Neither replay nor byte counter should ever decrease. */ - if (pt->rpl < tdb->tdb_rpl || - pt->cur_bytes < tdb->tdb_cur_bytes) { - splx(s); - goto bad; - } + struct pfsync_softc *sc = (struct pfsync_softc *)arg; + struct ip_moptions *imo; - tdb->tdb_rpl = pt->rpl; - tdb->tdb_cur_bytes = pt->cur_bytes; + if (sc == NULL || sc->sc_sync_ifp != ifp) + return; /* not for us; unlocked read */ + + PF_LOCK(); + + /* Deal with a member interface going away from under us. */ + sc->sc_sync_ifp = NULL; + if (sc->sc_mbuf_net != NULL) { + m_freem(sc->sc_mbuf_net); + sc->sc_mbuf_net = NULL; + sc->sc_statep_net.s = NULL; } - splx(s); - return; - - bad: - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync_insert: PFSYNC_ACT_TDB_UPD: " - "invalid value\n"); - pfsyncstats.pfsyncs_badstate++; - return; + imo = &sc->sc_imo; + if (imo->imo_num_memberships > 0) { + KASSERT(imo->imo_num_memberships == 1, + ("%s: imo_num_memberships != 1", __func__)); + /* + * Our event handler is always called after protocol + * domains have been detached from the underlying ifnet. + * Do not call in_delmulti(); we held a single reference + * which the protocol domain has purged in in_purgemaddrs(). + */ + imo->imo_membership[--imo->imo_num_memberships] = NULL; + imo->imo_multicast_ifp = NULL; + } + + PF_UNLOCK(); } -/* One of our local tdbs have been updated, need to sync rpl with others */ -int -pfsync_update_tdb(struct tdb *tdb, int output) +static void +pfsync_senddef(void *arg) { - struct ifnet *ifp = NULL; - struct pfsync_softc *sc = pfsyncif; - struct pfsync_header *h; - struct pfsync_tdb *pt = NULL; - int s, i, ret; - - if (sc == NULL) - return (0); + struct pfsync_softc *sc = (struct pfsync_softc *)arg; + struct mbuf *m; - ifp = &sc->sc_if; - if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL && - sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) { - /* Don't leave any stale pfsync packets hanging around. */ - if (sc->sc_mbuf_tdb != NULL) { - m_freem(sc->sc_mbuf_tdb); - sc->sc_mbuf_tdb = NULL; - sc->sc_statep_tdb.t = NULL; + for(;;) { + IF_DEQUEUE(&sc->sc_ifq, m); + if (m == NULL) + break; + /* Deal with a member interface going away from under us. */ + if (sc->sc_sync_ifp == NULL) { + pfsyncstats.pfsyncs_oerrors++; + m_freem(m); + continue; } - return (0); + if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)) + pfsyncstats.pfsyncs_oerrors++; } +} - s = splnet(); - if (sc->sc_mbuf_tdb == NULL) { - if ((sc->sc_mbuf_tdb = pfsync_get_mbuf(sc, PFSYNC_ACT_TDB_UPD, - (void *)&sc->sc_statep_tdb.t)) == NULL) { - splx(s); - return (ENOMEM); - } - h = mtod(sc->sc_mbuf_tdb, struct pfsync_header *); - } else { - h = mtod(sc->sc_mbuf_tdb, struct pfsync_header *); - if (h->action != PFSYNC_ACT_TDB_UPD) { - /* - * XXX will never happen as long as there's - * only one "TDB action". - */ - pfsync_tdb_sendout(sc); - sc->sc_mbuf_tdb = pfsync_get_mbuf(sc, - PFSYNC_ACT_TDB_UPD, (void *)&sc->sc_statep_tdb.t); - if (sc->sc_mbuf_tdb == NULL) { - splx(s); - return (ENOMEM); - } - h = mtod(sc->sc_mbuf_tdb, struct pfsync_header *); - } else if (sc->sc_maxupdates) { - /* - * If it's an update, look in the packet to see if - * we already have an update for the state. - */ - struct pfsync_tdb *u = - (void *)((char *)h + PFSYNC_HDRLEN); - - for (i = 0; !pt && i < h->count; i++) { - if (tdb->tdb_spi == u->spi && - tdb->tdb_sproto == u->sproto && - !bcmp(&tdb->tdb_dst, &u->dst, - SA_LEN(&u->dst.sa))) { - pt = u; - pt->updates++; - } - u++; - } - } - } +static int +pfsync_modevent(module_t mod, int type, void *data) +{ + int error = 0; - if (pt == NULL) { - /* not a "duplicate" update */ - pt = sc->sc_statep_tdb.t++; - sc->sc_mbuf_tdb->m_pkthdr.len = - sc->sc_mbuf_tdb->m_len += sizeof(struct pfsync_tdb); - h->count++; - bzero(pt, sizeof(*pt)); + switch (type) { + case MOD_LOAD: + LIST_INIT(&pfsync_list); + if_clone_attach(&pfsync_cloner); + break; + + case MOD_UNLOAD: + if_clone_detach(&pfsync_cloner); + break; - pt->spi = tdb->tdb_spi; - memcpy(&pt->dst, &tdb->tdb_dst, sizeof pt->dst); - pt->sproto = tdb->tdb_sproto; + default: + error = EINVAL; + break; } - /* - * When a failover happens, the master's rpl is probably above - * what we see here (we may be up to a second late), so - * increase it a bit for outbound tdbs to manage most such - * situations. - * - * For now, just add an offset that is likely to be larger - * than the number of packets we can see in one second. The RFC - * just says the next packet must have a higher seq value. - * - * XXX What is a good algorithm for this? We could use - * a rate-determined increase, but to know it, we would have - * to extend struct tdb. - * XXX pt->rpl can wrap over MAXINT, but if so the real tdb - * will soon be replaced anyway. For now, just don't handle - * this edge case. - */ -#define RPL_INCR 16384 - pt->rpl = htonl(tdb->tdb_rpl + (output ? RPL_INCR : 0)); - pt->cur_bytes = htobe64(tdb->tdb_cur_bytes); + return error; +} - if (h->count == sc->sc_maxcount || - (sc->sc_maxupdates && (pt->updates >= sc->sc_maxupdates))) - ret = pfsync_tdb_sendout(sc); +static moduledata_t pfsync_mod = { + "pfsync", + pfsync_modevent, + 0 +}; - splx(s); - return (ret); -} +#define PFSYNC_MODVER 1 + +DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); +MODULE_VERSION(pfsync, PFSYNC_MODVER); +#endif /* __FreeBSD__ */ diff --git a/sys/contrib/pf/net/if_pfsync.h b/sys/contrib/pf/net/if_pfsync.h index 5ed465e..77ef3a5 100644 --- a/sys/contrib/pf/net/if_pfsync.h +++ b/sys/contrib/pf/net/if_pfsync.h @@ -1,4 +1,5 @@ -/* $OpenBSD: if_pfsync.h,v 1.30 2006/10/31 14:49:01 henning Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: if_pfsync.h,v 1.19 2005/01/20 17:47:38 mcbride Exp $ */ /* * Copyright (c) 2001 Michael Shalayeff @@ -35,7 +36,6 @@ struct pfsync_state_scrub { u_int16_t pfss_flags; u_int8_t pfss_ttl; /* stashed TTL */ -#define PFSYNC_SCRUB_FLAG_VALID 0x01 u_int8_t scrub_flag; u_int32_t pfss_ts_mod; /* timestamp modulation */ } __packed; @@ -55,7 +55,8 @@ struct pfsync_state_peer { u_int16_t mss; /* Maximum segment size option */ u_int8_t state; /* active state level */ u_int8_t wscale; /* window scaling factor */ - u_int8_t pad[6]; + u_int8_t scrub_flag; + u_int8_t pad[5]; } __packed; struct pfsync_state { @@ -72,8 +73,8 @@ struct pfsync_state { u_int32_t nat_rule; u_int32_t creation; u_int32_t expire; - u_int32_t packets[2][2]; - u_int32_t bytes[2][2]; + u_int32_t packets[2]; + u_int32_t bytes[2]; u_int32_t creatorid; sa_family_t af; u_int8_t proto; @@ -88,16 +89,6 @@ struct pfsync_state { #define PFSYNC_FLAG_COMPRESS 0x01 #define PFSYNC_FLAG_STALE 0x02 -struct pfsync_tdb { - u_int32_t spi; - union sockaddr_union dst; - u_int32_t rpl; - u_int64_t cur_bytes; - u_int8_t sproto; - u_int8_t updates; - u_int8_t pad[2]; -} __packed; - struct pfsync_state_upd { u_int32_t id[2]; struct pfsync_state_peer src; @@ -153,45 +144,52 @@ union sc_statep { struct pfsync_state_upd_req *r; }; -union sc_tdb_statep { - struct pfsync_tdb *t; -}; - extern int pfsync_sync_ok; struct pfsync_softc { +#ifdef __FreeBSD__ + struct ifnet *sc_ifp; +#else struct ifnet sc_if; +#endif struct ifnet *sc_sync_ifp; struct ip_moptions sc_imo; +#ifdef __FreeBSD__ + struct callout sc_tmo; + struct callout sc_bulk_tmo; + struct callout sc_bulkfail_tmo; +#else struct timeout sc_tmo; - struct timeout sc_tdb_tmo; struct timeout sc_bulk_tmo; struct timeout sc_bulkfail_tmo; +#endif struct in_addr sc_sync_peer; struct in_addr sc_sendaddr; struct mbuf *sc_mbuf; /* current cumulative mbuf */ struct mbuf *sc_mbuf_net; /* current cumulative mbuf */ - struct mbuf *sc_mbuf_tdb; /* dito for TDB updates */ +#ifdef __FreeBSD__ + struct ifqueue sc_ifq; + struct callout sc_send_tmo; +#endif union sc_statep sc_statep; union sc_statep sc_statep_net; - union sc_tdb_statep sc_statep_tdb; u_int32_t sc_ureq_received; u_int32_t sc_ureq_sent; - struct pf_state *sc_bulk_send_next; - struct pf_state *sc_bulk_terminator; int sc_bulk_tries; int sc_maxcount; /* number of states in mtu */ int sc_maxupdates; /* number of updates/state */ +#ifdef __FreeBSD__ + LIST_ENTRY(pfsync_softc) sc_next; + eventhandler_tag sc_detachtag; +#endif }; - -extern struct pfsync_softc *pfsyncif; #endif struct pfsync_header { u_int8_t version; -#define PFSYNC_VERSION 3 +#define PFSYNC_VERSION 2 u_int8_t af; u_int8_t action; #define PFSYNC_ACT_CLR 0 /* clear all states */ @@ -204,10 +202,8 @@ struct pfsync_header { #define PFSYNC_ACT_DEL_F 7 /* delete fragments */ #define PFSYNC_ACT_UREQ 8 /* request "uncompressed" state */ #define PFSYNC_ACT_BUS 9 /* Bulk Update Status */ -#define PFSYNC_ACT_TDB_UPD 10 /* TDB replay counter update */ -#define PFSYNC_ACT_MAX 11 +#define PFSYNC_ACT_MAX 10 u_int8_t count; - u_int8_t pf_chksum[PF_MD5_DIGEST_LENGTH]; } __packed; #define PFSYNC_BULKPACKETS 1 /* # of packets per timeout */ @@ -216,7 +212,7 @@ struct pfsync_header { #define PFSYNC_ACTIONS \ "CLR ST", "INS ST", "UPD ST", "DEL ST", \ "UPD ST COMP", "DEL ST COMP", "INS FR", "DEL FR", \ - "UPD REQ", "BLK UPD STAT", "TDB UPD" + "UPD REQ", "BLK UPD STAT" #define PFSYNC_DFLTTL 255 @@ -250,6 +246,10 @@ struct pfsyncreq { int pfsyncr_authlevel; }; +#ifdef __FreeBSD__ +#define SIOCSETPFSYNC _IOW('i', 247, struct ifreq) +#define SIOCGETPFSYNC _IOWR('i', 248, struct ifreq) +#endif #define pf_state_peer_hton(s,d) do { \ (d)->seqlo = htonl((s)->seqlo); \ @@ -259,13 +259,6 @@ struct pfsyncreq { (d)->mss = htons((s)->mss); \ (d)->state = (s)->state; \ (d)->wscale = (s)->wscale; \ - if ((s)->scrub) { \ - (d)->scrub.pfss_flags = \ - htons((s)->scrub->pfss_flags & PFSS_TIMESTAMP); \ - (d)->scrub.pfss_ttl = (s)->scrub->pfss_ttl; \ - (d)->scrub.pfss_ts_mod = htonl((s)->scrub->pfss_ts_mod);\ - (d)->scrub.scrub_flag = PFSYNC_SCRUB_FLAG_VALID; \ - } \ } while (0) #define pf_state_peer_ntoh(s,d) do { \ @@ -276,13 +269,6 @@ struct pfsyncreq { (d)->mss = ntohs((s)->mss); \ (d)->state = (s)->state; \ (d)->wscale = (s)->wscale; \ - if ((s)->scrub.scrub_flag == PFSYNC_SCRUB_FLAG_VALID && \ - (d)->scrub != NULL) { \ - (d)->scrub->pfss_flags = \ - ntohs((s)->scrub.pfss_flags) & PFSS_TIMESTAMP; \ - (d)->scrub->pfss_ttl = (s)->scrub.pfss_ttl; \ - (d)->scrub->pfss_ts_mod = ntohl((s)->scrub.pfss_ts_mod);\ - } \ } while (0) #define pf_state_host_hton(s,d) do { \ @@ -295,19 +281,12 @@ struct pfsyncreq { (d)->port = (s)->port; \ } while (0) -#define pf_state_counter_hton(s,d) do { \ - d[0] = htonl((s>>32)&0xffffffff); \ - d[1] = htonl(s&0xffffffff); \ -} while (0) - -#define pf_state_counter_ntoh(s,d) do { \ - d = ntohl(s[0]); \ - d = d<<32; \ - d += ntohl(s[1]); \ -} while (0) - #ifdef _KERNEL +#ifdef __FreeBSD__ +void pfsync_input(struct mbuf *, __unused int); +#else void pfsync_input(struct mbuf *, ...); +#endif int pfsync_clear_states(u_int32_t, char *); int pfsync_pack_state(u_int8_t, struct pf_state *, int); #define pfsync_insert_state(st) do { \ @@ -315,8 +294,7 @@ int pfsync_pack_state(u_int8_t, struct pf_state *, int); (st->proto == IPPROTO_PFSYNC)) \ st->sync_flags |= PFSTATE_NOSYNC; \ else if (!st->sync_flags) \ - pfsync_pack_state(PFSYNC_ACT_INS, (st), \ - PFSYNC_FLAG_COMPRESS); \ + pfsync_pack_state(PFSYNC_ACT_INS, (st), 1); \ st->sync_flags &= ~PFSTATE_FROMSYNC; \ } while (0) #define pfsync_update_state(st) do { \ @@ -329,8 +307,8 @@ int pfsync_pack_state(u_int8_t, struct pf_state *, int); if (!st->sync_flags) \ pfsync_pack_state(PFSYNC_ACT_DEL, (st), \ PFSYNC_FLAG_COMPRESS); \ + st->sync_flags &= ~PFSTATE_FROMSYNC; \ } while (0) -int pfsync_update_tdb(struct tdb *, int); #endif #endif /* _NET_IF_PFSYNC_H_ */ diff --git a/sys/contrib/pf/net/pf.c b/sys/contrib/pf/net/pf.c index 793dc34..282cbb5 100644 --- a/sys/contrib/pf/net/pf.c +++ b/sys/contrib/pf/net/pf.c @@ -1,4 +1,5 @@ -/* $OpenBSD: pf.c,v 1.527 2007/02/22 15:23:23 pyr Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: pf.c,v 1.483 2005/03/15 17:38:43 dhartmei Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -35,9 +36,39 @@ * */ +#ifdef __FreeBSD__ +#include "opt_inet.h" +#include "opt_inet6.h" +#endif + +#ifdef __FreeBSD__ +#include "opt_mac.h" +#include "opt_bpf.h" +#include "opt_pf.h" + +#ifdef DEV_BPF +#define NBPFILTER DEV_BPF +#else +#define NBPFILTER 0 +#endif + +#ifdef DEV_PFLOG +#define NPFLOG DEV_PFLOG +#else +#define NPFLOG 0 +#endif + +#ifdef DEV_PFSYNC +#define NPFSYNC DEV_PFSYNC +#else +#define NPFSYNC 0 +#endif + +#else #include "bpfilter.h" #include "pflog.h" #include "pfsync.h" +#endif #include <sys/param.h> #include <sys/systm.h> @@ -47,15 +78,17 @@ #include <sys/socketvar.h> #include <sys/kernel.h> #include <sys/time.h> +#ifdef __FreeBSD__ +#include <sys/sysctl.h> +#include <sys/endian.h> +#else #include <sys/pool.h> -#include <sys/proc.h> -#include <sys/rwlock.h> +#endif #include <net/if.h> #include <net/if_types.h> #include <net/bpf.h> #include <net/route.h> -#include <net/radix_mpath.h> #include <netinet/in.h> #include <netinet/in_var.h> @@ -73,7 +106,9 @@ #include <netinet/icmp_var.h> #include <netinet/if_ether.h> +#ifndef __FreeBSD__ #include <dev/rndvar.h> +#endif #include <net/pfvar.h> #include <net/if_pflog.h> @@ -86,8 +121,20 @@ #include <netinet/in_pcb.h> #include <netinet/icmp6.h> #include <netinet6/nd6.h> +#ifdef __FreeBSD__ +#include <netinet6/ip6_var.h> +#include <netinet6/in6_pcb.h> +#endif #endif /* INET6 */ +#ifdef __FreeBSD__ +#include <machine/in_cksum.h> +#include <sys/limits.h> +#include <sys/ucred.h> +#include <security/mac/mac_framework.h> + +extern int ip_optcopy(struct ip *, struct ip *); +#endif #define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x @@ -95,6 +142,8 @@ * Global variables */ +struct pf_anchor_global pf_anchors; +struct pf_ruleset pf_main_ruleset; struct pf_altqqueue pf_altqs[2]; struct pf_palist pf_pabuf; struct pf_altqqueue *pf_altqs_active; @@ -106,6 +155,12 @@ u_int32_t ticket_altqs_inactive; int altqs_inactive_open; u_int32_t ticket_pabuf; +#ifdef __FreeBSD__ +struct callout pf_expire_to; /* expire timeout */ +#else +struct timeout pf_expire_to; /* expire timeout */ +#endif + struct pf_anchor_stackframe { struct pf_ruleset *rs; struct pf_rule *r; @@ -113,8 +168,13 @@ struct pf_anchor_stackframe { struct pf_anchor *child; } pf_anchor_stack[64]; +#ifdef __FreeBSD__ +uma_zone_t pf_src_tree_pl, pf_rule_pl; +uma_zone_t pf_state_pl, pf_altq_pl, pf_pooladdr_pl; +#else struct pool pf_src_tree_pl, pf_rule_pl; struct pool pf_state_pl, pf_altq_pl, pf_pooladdr_pl; +#endif void pf_print_host(struct pf_addr *, u_int16_t, u_int8_t); @@ -126,8 +186,6 @@ int pf_check_threshold(struct pf_threshold *); void pf_change_ap(struct pf_addr *, u_int16_t *, u_int16_t *, u_int16_t *, struct pf_addr *, u_int16_t, u_int8_t, sa_family_t); -int pf_modulate_sack(struct mbuf *, int, struct pf_pdesc *, - struct tcphdr *, struct pf_state_peer *); #ifdef INET6 void pf_change_a6(struct pf_addr *, u_int16_t *, struct pf_addr *, u_int8_t); @@ -136,11 +194,16 @@ void pf_change_icmp(struct pf_addr *, u_int16_t *, struct pf_addr *, struct pf_addr *, u_int16_t, u_int16_t *, u_int16_t *, u_int16_t *, u_int16_t *, u_int8_t, sa_family_t); +#ifdef __FreeBSD__ +void pf_send_tcp(struct mbuf *, + const struct pf_rule *, sa_family_t, +#else void pf_send_tcp(const struct pf_rule *, sa_family_t, +#endif const struct pf_addr *, const struct pf_addr *, u_int16_t, u_int16_t, u_int32_t, u_int32_t, u_int8_t, u_int16_t, u_int16_t, u_int8_t, int, - u_int16_t, struct ether_header *, struct ifnet *); + struct ether_header *, struct ifnet *); void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t, sa_family_t, struct pf_rule *); struct pf_rule *pf_match_translation(struct pf_pdesc *, struct mbuf *, @@ -155,11 +218,21 @@ struct pf_rule *pf_get_translation(struct pf_pdesc *, struct mbuf *, int pf_test_tcp(struct pf_rule **, struct pf_state **, int, struct pfi_kif *, struct mbuf *, int, void *, struct pf_pdesc *, struct pf_rule **, +#ifdef __FreeBSD__ + struct pf_ruleset **, struct ifqueue *, + struct inpcb *); +#else struct pf_ruleset **, struct ifqueue *); +#endif int pf_test_udp(struct pf_rule **, struct pf_state **, int, struct pfi_kif *, struct mbuf *, int, void *, struct pf_pdesc *, struct pf_rule **, +#ifdef __FreeBSD__ + struct pf_ruleset **, struct ifqueue *, + struct inpcb *); +#else struct pf_ruleset **, struct ifqueue *); +#endif int pf_test_icmp(struct pf_rule **, struct pf_state **, int, struct pfi_kif *, struct mbuf *, int, void *, struct pf_pdesc *, struct pf_rule **, @@ -183,11 +256,9 @@ int pf_test_state_icmp(struct pf_state **, int, void *, struct pf_pdesc *, u_short *); int pf_test_state_other(struct pf_state **, int, struct pfi_kif *, struct pf_pdesc *); +struct pf_tag *pf_get_tag(struct mbuf *); int pf_match_tag(struct mbuf *, struct pf_rule *, - struct pf_mtag *, int *); -int pf_step_out_of_anchor(int *, struct pf_ruleset **, - int, struct pf_rule **, struct pf_rule **, - int *); + struct pf_tag **, int *); void pf_hash(struct pf_addr *, struct pf_addr *, struct pf_poolhashkey *, sa_family_t); int pf_map_addr(u_int8_t, struct pf_rule *, @@ -198,12 +269,16 @@ int pf_get_sport(sa_family_t, u_int8_t, struct pf_rule *, struct pf_addr *, u_int16_t*, u_int16_t, u_int16_t, struct pf_src_node **); void pf_route(struct mbuf **, struct pf_rule *, int, - struct ifnet *, struct pf_state *, - struct pf_pdesc *); + struct ifnet *, struct pf_state *); void pf_route6(struct mbuf **, struct pf_rule *, int, - struct ifnet *, struct pf_state *, - struct pf_pdesc *); -int pf_socket_lookup(int, struct pf_pdesc *); + struct ifnet *, struct pf_state *); +#ifdef __FreeBSD__ +int pf_socket_lookup(uid_t *, gid_t *, + int, struct pf_pdesc *, struct inpcb *); +#else +int pf_socket_lookup(uid_t *, gid_t *, + int, struct pf_pdesc *); +#endif u_int8_t pf_get_wscale(struct mbuf *, int, u_int16_t, sa_family_t); u_int16_t pf_get_mss(struct mbuf *, int, u_int16_t, @@ -216,21 +291,24 @@ int pf_check_proto_cksum(struct mbuf *, int, int, u_int8_t, sa_family_t); int pf_addr_wrap_neq(struct pf_addr_wrap *, struct pf_addr_wrap *); +static int pf_add_mbuf_tag(struct mbuf *, u_int); struct pf_state *pf_find_state_recurse(struct pfi_kif *, - struct pf_state_cmp *, u_int8_t); + struct pf_state *, u_int8_t); int pf_src_connlimit(struct pf_state **); int pf_check_congestion(struct ifqueue *); -extern struct pool pfr_ktable_pl; -extern struct pool pfr_kentry_pl; +#ifdef __FreeBSD__ +int in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len); + +struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX]; +#else struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = { { &pf_state_pl, PFSTATE_HIWAT }, { &pf_src_tree_pl, PFSNODE_HIWAT }, - { &pf_frent_pl, PFFRAG_FRENT_HIWAT }, - { &pfr_ktable_pl, PFR_KTABLE_HIWAT }, - { &pfr_kentry_pl, PFR_KENTRY_HIWAT } + { &pf_frent_pl, PFFRAG_FRENT_HIWAT } }; +#endif #define STATE_LOOKUP() \ do { \ @@ -260,8 +338,9 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = { (s)->lan.addr.addr32[3] != (s)->gwy.addr.addr32[3])) || \ (s)->lan.port != (s)->gwy.port -#define BOUND_IFACE(r, k) \ - ((r)->rule_flag & PFRULE_IFBOUND) ? (k) : pfi_all +#define BOUND_IFACE(r, k) (((r)->rule_flag & PFRULE_IFBOUND) ? (k) : \ + ((r)->rule_flag & PFRULE_GRBOUND) ? (k)->pfik_parent : \ + (k)->pfik_parent->pfik_parent) #define STATE_INC_COUNTERS(s) \ do { \ @@ -281,6 +360,7 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = { s->rule.ptr->states--; \ } while (0) +#ifndef __FreeBSD__ static __inline int pf_src_compare(struct pf_src_node *, struct pf_src_node *); static __inline int pf_state_compare_lan_ext(struct pf_state *, struct pf_state *); @@ -288,11 +368,22 @@ static __inline int pf_state_compare_ext_gwy(struct pf_state *, struct pf_state *); static __inline int pf_state_compare_id(struct pf_state *, struct pf_state *); +static __inline int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *); +#else +static int pf_src_compare(struct pf_src_node *, struct pf_src_node *); +static int pf_state_compare_lan_ext(struct pf_state *, + struct pf_state *); +static int pf_state_compare_ext_gwy(struct pf_state *, + struct pf_state *); +static int pf_state_compare_id(struct pf_state *, + struct pf_state *); +static int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *); +#endif struct pf_src_tree tree_src_tracking; struct pf_state_tree_id tree_id; -struct pf_state_queue state_list; +struct pf_state_queue state_updates; RB_GENERATE(pf_src_tree, pf_src_node, entry, pf_src_compare); RB_GENERATE(pf_state_tree_lan_ext, pf_state, @@ -301,8 +392,14 @@ RB_GENERATE(pf_state_tree_ext_gwy, pf_state, u.s.entry_ext_gwy, pf_state_compare_ext_gwy); RB_GENERATE(pf_state_tree_id, pf_state, u.s.entry_id, pf_state_compare_id); +RB_GENERATE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare); +RB_GENERATE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare); +#ifdef __FreeBSD__ +static int +#else static __inline int +#endif pf_src_compare(struct pf_src_node *a, struct pf_src_node *b) { int diff; @@ -346,7 +443,11 @@ pf_src_compare(struct pf_src_node *a, struct pf_src_node *b) return (0); } +#ifdef __FreeBSD__ +static int +#else static __inline int +#endif pf_state_compare_lan_ext(struct pf_state *a, struct pf_state *b) { int diff; @@ -414,7 +515,11 @@ pf_state_compare_lan_ext(struct pf_state *a, struct pf_state *b) return (0); } +#ifdef __FreeBSD__ +static int +#else static __inline int +#endif pf_state_compare_ext_gwy(struct pf_state *a, struct pf_state *b) { int diff; @@ -482,7 +587,11 @@ pf_state_compare_ext_gwy(struct pf_state *a, struct pf_state *b) return (0); } +#ifdef __FreeBSD__ +static int +#else static __inline int +#endif pf_state_compare_id(struct pf_state *a, struct pf_state *b) { if (a->id > b->id) @@ -497,6 +606,18 @@ pf_state_compare_id(struct pf_state *a, struct pf_state *b) return (0); } +#ifdef __FreeBSD__ +static int +#else +static __inline int +#endif +pf_anchor_compare(struct pf_anchor *a, struct pf_anchor *b) +{ + int c = strcmp(a->path, b->path); + + return (c ? (c < 0 ? -1 : 1) : 0); +} + #ifdef INET6 void pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af) @@ -518,14 +639,14 @@ pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af) #endif /* INET6 */ struct pf_state * -pf_find_state_byid(struct pf_state_cmp *key) +pf_find_state_byid(struct pf_state *key) { pf_status.fcounters[FCNT_STATE_SEARCH]++; - return (RB_FIND(pf_state_tree_id, &tree_id, (struct pf_state *)key)); + return (RB_FIND(pf_state_tree_id, &tree_id, key)); } struct pf_state * -pf_find_state_recurse(struct pfi_kif *kif, struct pf_state_cmp *key, u_int8_t tree) +pf_find_state_recurse(struct pfi_kif *kif, struct pf_state *key, u_int8_t tree) { struct pf_state *s; @@ -533,20 +654,20 @@ pf_find_state_recurse(struct pfi_kif *kif, struct pf_state_cmp *key, u_int8_t tr switch (tree) { case PF_LAN_EXT: - if ((s = RB_FIND(pf_state_tree_lan_ext, &kif->pfik_lan_ext, - (struct pf_state *)key)) != NULL) - return (s); - if ((s = RB_FIND(pf_state_tree_lan_ext, &pfi_all->pfik_lan_ext, - (struct pf_state *)key)) != NULL) - return (s); + for (; kif != NULL; kif = kif->pfik_parent) { + s = RB_FIND(pf_state_tree_lan_ext, + &kif->pfik_lan_ext, key); + if (s != NULL) + return (s); + } return (NULL); case PF_EXT_GWY: - if ((s = RB_FIND(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, - (struct pf_state *)key)) != NULL) - return (s); - if ((s = RB_FIND(pf_state_tree_ext_gwy, &pfi_all->pfik_ext_gwy, - (struct pf_state *)key)) != NULL) - return (s); + for (; kif != NULL; kif = kif->pfik_parent) { + s = RB_FIND(pf_state_tree_ext_gwy, + &kif->pfik_ext_gwy, key); + if (s != NULL) + return (s); + } return (NULL); default: panic("pf_find_state_recurse"); @@ -554,7 +675,7 @@ pf_find_state_recurse(struct pfi_kif *kif, struct pf_state_cmp *key, u_int8_t tr } struct pf_state * -pf_find_state_all(struct pf_state_cmp *key, u_int8_t tree, int *more) +pf_find_state_all(struct pf_state *key, u_int8_t tree, int *more) { struct pf_state *s, *ss = NULL; struct pfi_kif *kif; @@ -565,7 +686,7 @@ pf_find_state_all(struct pf_state_cmp *key, u_int8_t tree, int *more) case PF_LAN_EXT: TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) { s = RB_FIND(pf_state_tree_lan_ext, - &kif->pfik_lan_ext, (struct pf_state *)key); + &kif->pfik_lan_ext, key); if (s == NULL) continue; if (more == NULL) @@ -577,7 +698,7 @@ pf_find_state_all(struct pf_state_cmp *key, u_int8_t tree, int *more) case PF_EXT_GWY: TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) { s = RB_FIND(pf_state_tree_ext_gwy, - &kif->pfik_ext_gwy, (struct pf_state *)key); + &kif->pfik_ext_gwy, key); if (s == NULL) continue; if (more == NULL) @@ -628,7 +749,9 @@ pf_src_connlimit(struct pf_state **state) int bad = 0; (*state)->src_node->conn++; - (*state)->src.tcp_est = 1; +#ifdef __FreeBSD__ + (*state)->local_flags |= PFSTATE_SRC_CONN; +#endif pf_add_threshold(&(*state)->src_node->conn_rate); if ((*state)->rule.ptr->max_src_conn && @@ -831,9 +954,16 @@ pf_insert_state(struct pfi_kif *kif, struct pf_state *state) } if (RB_INSERT(pf_state_tree_id, &tree_id, state) != NULL) { if (pf_status.debug >= PF_DEBUG_MISC) { +#ifdef __FreeBSD__ + printf("pf: state insert failed: " + "id: %016llx creatorid: %08x", + (long long)be64toh(state->id), + ntohl(state->creatorid)); +#else printf("pf: state insert failed: " "id: %016llx creatorid: %08x", betoh64(state->id), ntohl(state->creatorid)); +#endif if (state->sync_flags & PFSTATE_FROMSYNC) printf(" (from sync)"); printf("\n"); @@ -842,10 +972,11 @@ pf_insert_state(struct pfi_kif *kif, struct pf_state *state) RB_REMOVE(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state); return (-1); } - TAILQ_INSERT_TAIL(&state_list, state, u.s.entry_list); + TAILQ_INSERT_HEAD(&state_updates, state, u.s.entry_updates); + pf_status.fcounters[FCNT_STATE_INSERT]++; pf_status.states++; - pfi_kif_ref(kif, PFI_KIF_REF_STATE); + pfi_attach_state(kif); #if NPFSYNC pfsync_insert_state(state); #endif @@ -853,28 +984,33 @@ pf_insert_state(struct pfi_kif *kif, struct pf_state *state) } void -pf_purge_thread(void *v) +pf_purge_timeout(void *arg) { - int nloops = 0, s; - - for (;;) { - tsleep(pf_purge_thread, PWAIT, "pftm", 1 * hz); - - s = splsoftnet(); - - /* process a fraction of the state table every second */ - pf_purge_expired_states(1 + (pf_status.states - / pf_default_rule.timeout[PFTM_INTERVAL])); +#ifdef __FreeBSD__ + struct callout *to = arg; +#else + struct timeout *to = arg; +#endif + int s; - /* purge other expired types every PFTM_INTERVAL seconds */ - if (++nloops >= pf_default_rule.timeout[PFTM_INTERVAL]) { - pf_purge_expired_fragments(); - pf_purge_expired_src_nodes(0); - nloops = 0; - } +#ifdef __FreeBSD__ + PF_LOCK(); +#endif + s = splsoftnet(); + pf_purge_expired_states(); + pf_purge_expired_fragments(); + pf_purge_expired_src_nodes(); + splx(s); +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif - splx(s); - } +#ifdef __FreeBSD__ + callout_reset(to, pf_default_rule.timeout[PFTM_INTERVAL] * hz, + pf_purge_timeout, to); +#else + timeout_add(to, pf_default_rule.timeout[PFTM_INTERVAL] * hz); +#endif } u_int32_t @@ -890,8 +1026,12 @@ pf_state_expires(const struct pf_state *state) return (time_second); if (state->timeout == PFTM_UNTIL_PACKET) return (0); - KASSERT(state->timeout != PFTM_UNLINKED); +#ifdef __FreeBSD__ + KASSERT((state->timeout < PFTM_MAX), + ("pf_state_expires: timeout > PFTM_MAX")); +#else KASSERT(state->timeout < PFTM_MAX); +#endif timeout = state->rule.ptr->timeout[state->timeout]; if (!timeout) timeout = pf_default_rule.timeout[state->timeout]; @@ -915,21 +1055,14 @@ pf_state_expires(const struct pf_state *state) } void -pf_purge_expired_src_nodes(int waslocked) +pf_purge_expired_src_nodes(void) { struct pf_src_node *cur, *next; - int locked = waslocked; for (cur = RB_MIN(pf_src_tree, &tree_src_tracking); cur; cur = next) { next = RB_NEXT(pf_src_tree, &tree_src_tracking, cur); if (cur->states <= 0 && cur->expire <= time_second) { - if (! locked) { - rw_enter_write(&pf_consistency_lock); - next = RB_NEXT(pf_src_tree, - &tree_src_tracking, cur); - locked = 1; - } if (cur->rule.ptr != NULL) { cur->rule.ptr->src_nodes--; if (cur->rule.ptr->states <= 0 && @@ -942,9 +1075,6 @@ pf_purge_expired_src_nodes(int waslocked) pool_put(&pf_src_tree_pl, cur); } } - - if (locked && !waslocked) - rw_exit_write(&pf_consistency_lock); } void @@ -954,7 +1084,12 @@ pf_src_tree_remove_state(struct pf_state *s) if (s->src_node != NULL) { if (s->proto == IPPROTO_TCP) { - if (s->src.tcp_est) +#ifdef __FreeBSD__ + if (s->local_flags & PFSTATE_SRC_CONN) +#else + if (s->src.state == PF_TCPS_PROXY_DST || + s->timeout >= PFTM_TCP_ESTABLISHED) +#endif --s->src_node->conn; } if (--s->src_node->states <= 0) { @@ -977,42 +1112,33 @@ pf_src_tree_remove_state(struct pf_state *s) s->src_node = s->nat_src_node = NULL; } -/* callers should be at splsoftnet */ void -pf_unlink_state(struct pf_state *cur) +pf_purge_expired_state(struct pf_state *cur) { - if (cur->src.state == PF_TCPS_PROXY_DST) { +#ifdef __FreeBSD__ + if (cur->local_flags & PFSTATE_EXPIRING) + return; + cur->local_flags |= PFSTATE_EXPIRING; +#endif + if (cur->src.state == PF_TCPS_PROXY_DST) +#ifdef __FreeBSD__ + pf_send_tcp(NULL, cur->rule.ptr, cur->af, +#else pf_send_tcp(cur->rule.ptr, cur->af, +#endif &cur->ext.addr, &cur->lan.addr, cur->ext.port, cur->lan.port, cur->src.seqhi, cur->src.seqlo + 1, - TH_RST|TH_ACK, 0, 0, 0, 1, cur->tag, NULL, NULL); - } + TH_RST|TH_ACK, 0, 0, 0, 1, NULL, NULL); RB_REMOVE(pf_state_tree_ext_gwy, &cur->u.s.kif->pfik_ext_gwy, cur); RB_REMOVE(pf_state_tree_lan_ext, &cur->u.s.kif->pfik_lan_ext, cur); RB_REMOVE(pf_state_tree_id, &tree_id, cur); #if NPFSYNC - if (cur->creatorid == pf_status.hostid) - pfsync_delete_state(cur); + pfsync_delete_state(cur); #endif - cur->timeout = PFTM_UNLINKED; pf_src_tree_remove_state(cur); -} - -/* callers should be at splsoftnet and hold the - * write_lock on pf_consistency_lock */ -void -pf_free_state(struct pf_state *cur) -{ -#if NPFSYNC - if (pfsyncif != NULL && - (pfsyncif->sc_bulk_send_next == cur || - pfsyncif->sc_bulk_terminator == cur)) - return; -#endif - KASSERT(cur->timeout == PFTM_UNLINKED); if (--cur->rule.ptr->states <= 0 && cur->rule.ptr->src_nodes <= 0) pf_rm_rule(NULL, cur->rule.ptr); @@ -1024,8 +1150,8 @@ pf_free_state(struct pf_state *cur) if (--cur->anchor.ptr->states <= 0) pf_rm_rule(NULL, cur->anchor.ptr); pf_normalize_tcp_cleanup(cur); - pfi_kif_unref(cur->u.s.kif, PFI_KIF_REF_STATE); - TAILQ_REMOVE(&state_list, cur, u.s.entry_list); + pfi_detach_state(cur->u.s.kif); + TAILQ_REMOVE(&state_updates, cur, u.s.entry_updates); if (cur->tag) pf_tag_unref(cur->tag); pool_put(&pf_state_pl, cur); @@ -1034,44 +1160,16 @@ pf_free_state(struct pf_state *cur) } void -pf_purge_expired_states(u_int32_t maxcheck) +pf_purge_expired_states(void) { - static struct pf_state *cur = NULL; - struct pf_state *next; - int locked = 0; - - while (maxcheck--) { - /* wrap to start of list when we hit the end */ - if (cur == NULL) { - cur = TAILQ_FIRST(&state_list); - if (cur == NULL) - break; /* list empty */ - } - - /* get next state, as cur may get deleted */ - next = TAILQ_NEXT(cur, u.s.entry_list); - - if (cur->timeout == PFTM_UNLINKED) { - /* free unlinked state */ - if (! locked) { - rw_enter_write(&pf_consistency_lock); - locked = 1; - } - pf_free_state(cur); - } else if (pf_state_expires(cur) <= time_second) { - /* unlink and free expired state */ - pf_unlink_state(cur); - if (! locked) { - rw_enter_write(&pf_consistency_lock); - locked = 1; - } - pf_free_state(cur); - } - cur = next; - } + struct pf_state *cur, *next; - if (locked) - rw_exit_write(&pf_consistency_lock); + for (cur = RB_MIN(pf_state_tree_id, &tree_id); + cur; cur = next) { + next = RB_NEXT(pf_state_tree_id, &tree_id, cur); + if (pf_state_expires(cur) <= time_second) + pf_purge_expired_state(cur); + } } int @@ -1297,12 +1395,9 @@ pf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2) case PF_ADDR_DYNIFTL: return (aw1->p.dyn->pfid_kt != aw2->p.dyn->pfid_kt); case PF_ADDR_NOROUTE: - case PF_ADDR_URPFFAILED: return (0); case PF_ADDR_TABLE: return (aw1->p.tbl != aw2->p.tbl); - case PF_ADDR_RTLABEL: - return (aw1->v.rtlabel != aw2->v.rtlabel); default: printf("invalid address type: %d\n", aw1->type); return (1); @@ -1417,7 +1512,7 @@ pf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa, /* Change inner protocol port, fix inner protocol checksum. */ if (ip != NULL) { u_int16_t oip = *ip; - u_int32_t opc; + u_int32_t opc = 0; /* make the compiler happy */ if (pc != NULL) opc = *pc; @@ -1489,82 +1584,27 @@ pf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa, } } - -/* - * Need to modulate the sequence numbers in the TCP SACK option - * (credits to Krzysztof Pfaff for report and patch) - */ -int -pf_modulate_sack(struct mbuf *m, int off, struct pf_pdesc *pd, - struct tcphdr *th, struct pf_state_peer *dst) -{ - int hlen = (th->th_off << 2) - sizeof(*th), thoptlen = hlen; - u_int8_t opts[MAX_TCPOPTLEN], *opt = opts; - int copyback = 0, i, olen; - struct sackblk sack; - -#define TCPOLEN_SACKLEN (TCPOLEN_SACK + 2) - if (hlen < TCPOLEN_SACKLEN || - !pf_pull_hdr(m, off + sizeof(*th), opts, hlen, NULL, NULL, pd->af)) - return 0; - - while (hlen >= TCPOLEN_SACKLEN) { - olen = opt[1]; - switch (*opt) { - case TCPOPT_EOL: /* FALLTHROUGH */ - case TCPOPT_NOP: - opt++; - hlen--; - break; - case TCPOPT_SACK: - if (olen > hlen) - olen = hlen; - if (olen >= TCPOLEN_SACKLEN) { - for (i = 2; i + TCPOLEN_SACK <= olen; - i += TCPOLEN_SACK) { - memcpy(&sack, &opt[i], sizeof(sack)); - pf_change_a(&sack.start, &th->th_sum, - htonl(ntohl(sack.start) - - dst->seqdiff), 0); - pf_change_a(&sack.end, &th->th_sum, - htonl(ntohl(sack.end) - - dst->seqdiff), 0); - memcpy(&opt[i], &sack, sizeof(sack)); - } - copyback = 1; - } - /* FALLTHROUGH */ - default: - if (olen < 2) - olen = 2; - hlen -= olen; - opt += olen; - } - } - - if (copyback) - m_copyback(m, off + sizeof(*th), thoptlen, opts); - return (copyback); -} - void +#ifdef __FreeBSD__ +pf_send_tcp(struct mbuf *replyto, const struct pf_rule *r, sa_family_t af, +#else pf_send_tcp(const struct pf_rule *r, sa_family_t af, +#endif const struct pf_addr *saddr, const struct pf_addr *daddr, u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack, u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, int tag, - u_int16_t rtag, struct ether_header *eh, struct ifnet *ifp) + struct ether_header *eh, struct ifnet *ifp) { struct mbuf *m; - int len, tlen; + int len = 0, tlen; /* make the compiler happy */ #ifdef INET - struct ip *h; + struct ip *h = NULL; /* make the compiler happy */ #endif /* INET */ #ifdef INET6 - struct ip6_hdr *h6; + struct ip6_hdr *h6 = NULL; /* make the compiler happy */ #endif /* INET6 */ - struct tcphdr *th; - char *opt; - struct pf_mtag *pf_mtag; + struct tcphdr *th = NULL; /* make the compiler happy */ + char *opt; /* maximum segment size tcp option */ tlen = sizeof(struct tcphdr); @@ -1588,24 +1628,44 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, m = m_gethdr(M_DONTWAIT, MT_HEADER); if (m == NULL) return; - if ((pf_mtag = pf_get_mtag(m)) == NULL) { - m_freem(m); - return; - } - if (tag) - pf_mtag->flags |= PF_TAG_GENERATED; - - pf_mtag->tag = rtag; - - if (r != NULL && r->rtableid >= 0) - pf_mtag->rtableid = r->rtableid; +#ifdef __FreeBSD__ +#ifdef MAC + if (replyto) + mac_create_mbuf_netlayer(replyto, m); + else + mac_create_mbuf_from_firewall(m); +#else + (void)replyto; +#endif +#endif + if (tag) { +#ifdef __FreeBSD__ + m->m_flags |= M_SKIP_FIREWALL; +#else + struct m_tag *mtag; + mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT); + if (mtag == NULL) { + m_freem(m); + return; + } + m_tag_prepend(m, mtag); +#endif + } #ifdef ALTQ if (r != NULL && r->qid) { - pf_mtag->qid = r->qid; - /* add hints for ecn */ - pf_mtag->af = af; - pf_mtag->hdr = mtod(m, struct ip *); + struct m_tag *mtag; + struct altq_tag *atag; + + mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT); + if (mtag != NULL) { + atag = (struct altq_tag *)(mtag + 1); + atag->qid = r->qid; + /* add hints for ecn */ + atag->af = af; + atag->hdr = mtod(m, struct ip *); + m_tag_prepend(m, mtag); + } } #endif /* ALTQ */ m->m_data += max_linkhdr; @@ -1668,13 +1728,25 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, h->ip_v = 4; h->ip_hl = sizeof(*h) >> 2; h->ip_tos = IPTOS_LOWDELAY; - h->ip_len = htons(len); +#ifdef __FreeBSD__ + h->ip_off = path_mtu_discovery ? IP_DF : 0; + h->ip_len = len; +#else h->ip_off = htons(ip_mtudisc ? IP_DF : 0); + h->ip_len = htons(len); +#endif h->ip_ttl = ttl ? ttl : ip_defttl; h->ip_sum = 0; if (eh == NULL) { +#ifdef __FreeBSD__ + PF_UNLOCK(); ip_output(m, (void *)NULL, (void *)NULL, 0, (void *)NULL, (void *)NULL); + PF_LOCK(); +#else /* ! __FreeBSD__ */ + ip_output(m, (void *)NULL, (void *)NULL, 0, + (void *)NULL, (void *)NULL); +#endif } else { struct route ro; struct rtentry rt; @@ -1691,8 +1763,16 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, bcopy(eh->ether_dhost, e->ether_shost, ETHER_ADDR_LEN); bcopy(eh->ether_shost, e->ether_dhost, ETHER_ADDR_LEN); e->ether_type = eh->ether_type; +#ifdef __FreeBSD__ + PF_UNLOCK(); + /* XXX_IMPORT: later */ + ip_output(m, (void *)NULL, &ro, 0, + (void *)NULL, (void *)NULL); + PF_LOCK(); +#else /* ! __FreeBSD__ */ ip_output(m, (void *)NULL, &ro, IP_ROUTETOETHER, (void *)NULL, (void *)NULL); +#endif } break; #endif /* INET */ @@ -1705,7 +1785,13 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, h6->ip6_vfc |= IPV6_VERSION; h6->ip6_hlim = IPV6_DEFHLIM; +#ifdef __FreeBSD__ + PF_UNLOCK(); + ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); + PF_LOCK(); +#else ip6_output(m, NULL, NULL, 0, NULL, NULL); +#endif break; #endif /* INET6 */ } @@ -1715,36 +1801,72 @@ void pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af, struct pf_rule *r) { - struct pf_mtag *pf_mtag; +#ifdef ALTQ + struct m_tag *mtag; +#endif struct mbuf *m0; +#ifdef __FreeBSD__ + struct ip *ip; +#endif +#ifdef __FreeBSD__ + m0 = m_copypacket(m, M_DONTWAIT); + if (m0 == NULL) + return; + m0->m_flags |= M_SKIP_FIREWALL; +#else + mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT); + if (mtag == NULL) + return; m0 = m_copy(m, 0, M_COPYALL); - - if ((pf_mtag = pf_get_mtag(m0)) == NULL) + if (m0 == NULL) { + m_tag_free(mtag); return; - pf_mtag->flags |= PF_TAG_GENERATED; - - if (r->rtableid >= 0) - pf_mtag->rtableid = r->rtableid; + } + m_tag_prepend(m0, mtag); +#endif #ifdef ALTQ if (r->qid) { - pf_mtag->qid = r->qid; - /* add hints for ecn */ - pf_mtag->af = af; - pf_mtag->hdr = mtod(m0, struct ip *); + struct altq_tag *atag; + + mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT); + if (mtag != NULL) { + atag = (struct altq_tag *)(mtag + 1); + atag->qid = r->qid; + /* add hints for ecn */ + atag->af = af; + atag->hdr = mtod(m0, struct ip *); + m_tag_prepend(m0, mtag); + } } #endif /* ALTQ */ switch (af) { #ifdef INET case AF_INET: +#ifdef __FreeBSD__ + /* icmp_error() expects host byte ordering */ + ip = mtod(m0, struct ip *); + NTOHS(ip->ip_len); + NTOHS(ip->ip_off); + PF_UNLOCK(); icmp_error(m0, type, code, 0, 0); + PF_LOCK(); +#else + icmp_error(m0, type, code, 0, (void *)NULL); +#endif break; #endif /* INET */ #ifdef INET6 case AF_INET6: +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif icmp6_error(m0, type, code, 0); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif break; #endif /* INET6 */ } @@ -1847,71 +1969,58 @@ pf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g) return (pf_match(op, a1, a2, g)); } -struct pf_mtag * -pf_find_mtag(struct mbuf *m) +struct pf_tag * +pf_get_tag(struct mbuf *m) { struct m_tag *mtag; - if ((mtag = m_tag_find(m, PACKET_TAG_PF, NULL)) == NULL) + if ((mtag = m_tag_find(m, PACKET_TAG_PF_TAG, NULL)) != NULL) + return ((struct pf_tag *)(mtag + 1)); + else return (NULL); - - return ((struct pf_mtag *)(mtag + 1)); -} - -struct pf_mtag * -pf_get_mtag(struct mbuf *m) -{ - struct m_tag *mtag; - - if ((mtag = m_tag_find(m, PACKET_TAG_PF, NULL)) == NULL) { - mtag = m_tag_get(PACKET_TAG_PF, sizeof(struct pf_mtag), - M_NOWAIT); - if (mtag == NULL) - return (NULL); - bzero(mtag + 1, sizeof(struct pf_mtag)); - m_tag_prepend(m, mtag); - } - - return ((struct pf_mtag *)(mtag + 1)); } int -pf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_mtag *pf_mtag, - int *tag) +pf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_tag **pftag, int *tag) { - if (*tag == -1) - *tag = pf_mtag->tag; + if (*tag == -1) { /* find mbuf tag */ + *pftag = pf_get_tag(m); + if (*pftag != NULL) + *tag = (*pftag)->tag; + else + *tag = 0; + } return ((!r->match_tag_not && r->match_tag == *tag) || (r->match_tag_not && r->match_tag != *tag)); } int -pf_tag_packet(struct mbuf *m, struct pf_mtag *pf_mtag, int tag, int rtableid) +pf_tag_packet(struct mbuf *m, struct pf_tag *pftag, int tag) { - if (tag <= 0 && rtableid < 0) + struct m_tag *mtag; + + if (tag <= 0) return (0); - if (pf_mtag == NULL) - if ((pf_mtag = pf_get_mtag(m)) == NULL) + if (pftag == NULL) { + mtag = m_tag_get(PACKET_TAG_PF_TAG, sizeof(*pftag), M_NOWAIT); + if (mtag == NULL) return (1); - if (tag > 0) - pf_mtag->tag = tag; - if (rtableid >= 0) - pf_mtag->rtableid = rtableid; + ((struct pf_tag *)(mtag + 1))->tag = tag; + m_tag_prepend(m, mtag); + } else + pftag->tag = tag; return (0); } static void pf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n, - struct pf_rule **r, struct pf_rule **a, int *match) + struct pf_rule **r, struct pf_rule **a) { struct pf_anchor_stackframe *f; - (*r)->anchor->match = 0; - if (match) - *match = 0; if (*depth >= sizeof(pf_anchor_stack) / sizeof(pf_anchor_stack[0])) { printf("pf_step_into_anchor: stack overflow\n"); @@ -1938,23 +2047,17 @@ pf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n, *r = TAILQ_FIRST((*rs)->rules[n].active.ptr); } -int +static void pf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n, - struct pf_rule **r, struct pf_rule **a, int *match) + struct pf_rule **r, struct pf_rule **a) { struct pf_anchor_stackframe *f; - int quick = 0; do { if (*depth <= 0) break; f = pf_anchor_stack + *depth - 1; if (f->parent != NULL && f->child != NULL) { - if (f->child->match || - (match != NULL && *match)) { - f->r->anchor->match = 1; - *match = 0; - } f->child = RB_NEXT(pf_anchor_node, f->parent, f->child); if (f->child != NULL) { *rs = &f->child->ruleset; @@ -1969,12 +2072,8 @@ pf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n, if (*depth == 0 && a != NULL) *a = NULL; *rs = f->rs; - if (f->r->anchor->match || (match != NULL && *match)) - quick = f->r->quick; *r = TAILQ_NEXT(f->r, entries); } while (*r == NULL); - - return (quick); } #ifdef INET6 @@ -2278,7 +2377,7 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high, struct pf_src_node **sn) { - struct pf_state_cmp key; + struct pf_state key; struct pf_addr init_addr; u_int16_t cut; @@ -2370,8 +2469,8 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off, { struct pf_rule *r, *rm = NULL; struct pf_ruleset *ruleset = NULL; + struct pf_tag *pftag = NULL; int tag = -1; - int rtableid = -1; int asd = 0; r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr); @@ -2389,7 +2488,8 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off, } r->evaluations++; - if (pfi_kif_match(r->kif, kif) == r->ifnot) + if (r->kif != NULL && + (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR].ptr; @@ -2397,8 +2497,7 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off, r = r->skip[PF_SKIP_AF].ptr; else if (r->proto && r->proto != pd->proto) r = r->skip[PF_SKIP_PROTO].ptr; - else if (PF_MISMATCHAW(&src->addr, saddr, pd->af, - src->neg, kif)) + else if (PF_MISMATCHAW(&src->addr, saddr, pd->af, src->neg)) r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR : PF_SKIP_DST_ADDR].ptr; else if (src->port_op && !pf_match_port(src->port_op, @@ -2406,16 +2505,15 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off, r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT : PF_SKIP_DST_PORT].ptr; else if (dst != NULL && - PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg, NULL)) + PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg)) r = r->skip[PF_SKIP_DST_ADDR].ptr; - else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af, - 0, NULL)) + else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af, 0)) r = TAILQ_NEXT(r, entries); else if (dst != NULL && dst->port_op && !pf_match_port(dst->port_op, dst->port[0], dst->port[1], dport)) r = r->skip[PF_SKIP_DST_PORT].ptr; - else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag)) + else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag)) r = TAILQ_NEXT(r, entries); else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto != IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m, @@ -2424,19 +2522,15 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off, else { if (r->tag) tag = r->tag; - if (r->rtableid >= 0) - rtableid = r->rtableid; if (r->anchor == NULL) { rm = r; } else - pf_step_into_anchor(&asd, &ruleset, rs_num, - &r, NULL, NULL); + pf_step_into_anchor(&asd, &ruleset, rs_num, &r, NULL); } if (r == NULL) - pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r, - NULL, NULL); + pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r, NULL); } - if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) + if (pf_tag_packet(m, pftag, tag)) return (NULL); if (rm != NULL && (rm->action == PF_NONAT || rm->action == PF_NORDR || rm->action == PF_NOBINAT)) @@ -2596,35 +2690,56 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, } int -pf_socket_lookup(int direction, struct pf_pdesc *pd) +#ifdef __FreeBSD__ +pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd, + struct inpcb *inp_arg) +#else +pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd) +#endif { struct pf_addr *saddr, *daddr; u_int16_t sport, dport; +#ifdef __FreeBSD__ + struct inpcbinfo *pi; +#else struct inpcbtable *tb; +#endif struct inpcb *inp; - if (pd == NULL) - return (-1); - pd->lookup.uid = UID_MAX; - pd->lookup.gid = GID_MAX; - pd->lookup.pid = NO_PID; + *uid = UID_MAX; + *gid = GID_MAX; +#ifdef __FreeBSD__ + if (inp_arg != NULL) { + INP_LOCK_ASSERT(inp_arg); + if (inp_arg->inp_socket) { + *uid = inp_arg->inp_socket->so_cred->cr_uid; + *gid = inp_arg->inp_socket->so_cred->cr_groups[0]; + return (1); + } else + return (0); + } +#endif switch (pd->proto) { case IPPROTO_TCP: - if (pd->hdr.tcp == NULL) - return (-1); sport = pd->hdr.tcp->th_sport; dport = pd->hdr.tcp->th_dport; +#ifdef __FreeBSD__ + pi = &tcbinfo; +#else tb = &tcbtable; +#endif break; case IPPROTO_UDP: - if (pd->hdr.udp == NULL) - return (-1); sport = pd->hdr.udp->uh_sport; dport = pd->hdr.udp->uh_dport; +#ifdef __FreeBSD__ + pi = &udbinfo; +#else tb = &udbtable; +#endif break; default: - return (-1); + return (0); } if (direction == PF_IN) { saddr = pd->src; @@ -2641,32 +2756,72 @@ pf_socket_lookup(int direction, struct pf_pdesc *pd) switch (pd->af) { #ifdef INET case AF_INET: +#ifdef __FreeBSD__ + INP_INFO_RLOCK(pi); /* XXX LOR */ + inp = in_pcblookup_hash(pi, saddr->v4, sport, daddr->v4, + dport, 0, NULL); + if (inp == NULL) { + inp = in_pcblookup_hash(pi, saddr->v4, sport, + daddr->v4, dport, INPLOOKUP_WILDCARD, NULL); + if(inp == NULL) { + INP_INFO_RUNLOCK(pi); + return (0); + } + } +#else inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport); if (inp == NULL) { inp = in_pcblookup_listen(tb, daddr->v4, dport, 0); if (inp == NULL) - return (-1); + return (0); } +#endif break; #endif /* INET */ #ifdef INET6 case AF_INET6: +#ifdef __FreeBSD__ + INP_INFO_RLOCK(pi); + inp = in6_pcblookup_hash(pi, &saddr->v6, sport, + &daddr->v6, dport, 0, NULL); + if (inp == NULL) { + inp = in6_pcblookup_hash(pi, &saddr->v6, sport, + &daddr->v6, dport, INPLOOKUP_WILDCARD, NULL); + if (inp == NULL) { + INP_INFO_RUNLOCK(pi); + return (0); + } + } +#else inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6, dport); if (inp == NULL) { inp = in6_pcblookup_listen(tb, &daddr->v6, dport, 0); if (inp == NULL) - return (-1); + return (0); } +#endif break; #endif /* INET6 */ default: - return (-1); + return (0); } - pd->lookup.uid = inp->inp_socket->so_euid; - pd->lookup.gid = inp->inp_socket->so_egid; - pd->lookup.pid = inp->inp_socket->so_cpid; +#ifdef __FreeBSD__ + INP_LOCK(inp); + if ((inp->inp_socket == NULL) || (inp->inp_socket->so_cred == NULL)) { + INP_UNLOCK(inp); + INP_INFO_RUNLOCK(pi); + return (0); + } + *uid = inp->inp_socket->so_cred->cr_uid; + *gid = inp->inp_socket->so_cred->cr_groups[0]; + INP_UNLOCK(inp); + INP_INFO_RUNLOCK(pi); +#else + *uid = inp->inp_socket->so_euid; + *gid = inp->inp_socket->so_egid; +#endif return (1); } @@ -2760,7 +2915,7 @@ pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer) struct route_in6 ro6; #endif /* INET6 */ struct rtentry *rt = NULL; - int hlen; + int hlen = 0; /* make the compiler happy */ u_int16_t mss = tcp_mssdflt; switch (af) { @@ -2772,7 +2927,15 @@ pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer) dst->sin_family = AF_INET; dst->sin_len = sizeof(*dst); dst->sin_addr = addr->v4; +#ifdef __FreeBSD__ +#ifdef RTF_PRCLONING + rtalloc_ign(&ro, (RTF_CLONING | RTF_PRCLONING)); +#else /* !RTF_PRCLONING */ + rtalloc_ign(&ro, RTF_CLONING); +#endif +#else /* ! __FreeBSD__ */ rtalloc_noclone(&ro, NO_CLONING); +#endif rt = ro.ro_rt; break; #endif /* INET */ @@ -2784,7 +2947,16 @@ pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer) dst6->sin6_family = AF_INET6; dst6->sin6_len = sizeof(*dst6); dst6->sin6_addr = addr->v6; +#ifdef __FreeBSD__ +#ifdef RTF_PRCLONING + rtalloc_ign((struct route *)&ro6, + (RTF_CLONING | RTF_PRCLONING)); +#else /* !RTF_PRCLONING */ + rtalloc_ign((struct route *)&ro6, RTF_CLONING); +#endif +#else /* ! __FreeBSD__ */ rtalloc_noclone((struct route *)&ro6, NO_CLONING); +#endif rt = ro6.ro_rt; break; #endif /* INET6 */ @@ -2829,29 +3001,43 @@ pf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr) int pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, struct pfi_kif *kif, struct mbuf *m, int off, void *h, +#ifdef __FreeBSD__ + struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, + struct ifqueue *ifq, struct inpcb *inp) +#else struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, struct ifqueue *ifq) +#endif { struct pf_rule *nr = NULL; struct pf_addr *saddr = pd->src, *daddr = pd->dst; struct tcphdr *th = pd->hdr.tcp; u_int16_t bport, nport = 0; sa_family_t af = pd->af; + int lookup = -1; + uid_t uid; + gid_t gid; struct pf_rule *r, *a = NULL; struct pf_ruleset *ruleset = NULL; struct pf_src_node *nsn = NULL; u_short reason; int rewrite = 0; - int tag = -1, rtableid = -1; + struct pf_tag *pftag = NULL; + int tag = -1; u_int16_t mss = tcp_mssdflt; int asd = 0; - int match = 0; if (pf_check_congestion(ifq)) { REASON_SET(&reason, PFRES_CONGEST); return (PF_DROP); } +#if defined(__FreeBSD__) && defined(PF_MPSAFE_UGID) + PF_UNLOCK(); + lookup = pf_socket_lookup(&uid, &gid, direction, pd, inp); + PF_LOCK(); +#endif + r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); if (direction == PF_OUT) { @@ -2886,7 +3072,8 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, while (r != NULL) { r->evaluations++; - if (pfi_kif_match(r->kif, kif) == r->ifnot) + if (r->kif != NULL && + (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR].ptr; @@ -2894,37 +3081,43 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, r = r->skip[PF_SKIP_AF].ptr; else if (r->proto && r->proto != IPPROTO_TCP) r = r->skip[PF_SKIP_PROTO].ptr; - else if (PF_MISMATCHAW(&r->src.addr, saddr, af, - r->src.neg, kif)) + else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg)) r = r->skip[PF_SKIP_SRC_ADDR].ptr; else if (r->src.port_op && !pf_match_port(r->src.port_op, r->src.port[0], r->src.port[1], th->th_sport)) r = r->skip[PF_SKIP_SRC_PORT].ptr; - else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, - r->dst.neg, NULL)) + else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg)) r = r->skip[PF_SKIP_DST_ADDR].ptr; else if (r->dst.port_op && !pf_match_port(r->dst.port_op, r->dst.port[0], r->dst.port[1], th->th_dport)) r = r->skip[PF_SKIP_DST_PORT].ptr; - else if (r->tos && !(r->tos == pd->tos)) + else if (r->tos && !(r->tos & pd->tos)) r = TAILQ_NEXT(r, entries); else if (r->rule_flag & PFRULE_FRAGMENT) r = TAILQ_NEXT(r, entries); else if ((r->flagset & th->th_flags) != r->flags) r = TAILQ_NEXT(r, entries); - else if (r->uid.op && (pd->lookup.done || (pd->lookup.done = - pf_socket_lookup(direction, pd), 1)) && + else if (r->uid.op && (lookup != -1 || (lookup = +#ifdef __FreeBSD__ + pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) && +#else + pf_socket_lookup(&uid, &gid, direction, pd), 1)) && +#endif !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1], - pd->lookup.uid)) + uid)) r = TAILQ_NEXT(r, entries); - else if (r->gid.op && (pd->lookup.done || (pd->lookup.done = - pf_socket_lookup(direction, pd), 1)) && + else if (r->gid.op && (lookup != -1 || (lookup = +#ifdef __FreeBSD__ + pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) && +#else + pf_socket_lookup(&uid, &gid, direction, pd), 1)) && +#endif !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1], - pd->lookup.gid)) + gid)) r = TAILQ_NEXT(r, entries); else if (r->prob && r->prob <= arc4random()) r = TAILQ_NEXT(r, entries); - else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag)) + else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag)) r = TAILQ_NEXT(r, entries); else if (r->os_fingerprint != PF_OSFP_ANY && !pf_osfp_match( pf_osfp_fingerprint(pd, m, off, th), r->os_fingerprint)) @@ -2932,10 +3125,7 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, else { if (r->tag) tag = r->tag; - if (r->rtableid >= 0) - rtableid = r->rtableid; if (r->anchor == NULL) { - match = 1; *rm = r; *am = a; *rsm = ruleset; @@ -2944,11 +3134,11 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, r = TAILQ_NEXT(r, entries); } else pf_step_into_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match); + PF_RULESET_FILTER, &r, &a); } - if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match)) - break; + if (r == NULL) + pf_step_out_of_anchor(&asd, &ruleset, + PF_RULESET_FILTER, &r, &a); } r = *rm; a = *am; @@ -2956,11 +3146,10 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_MATCH); - if (r->log || (nr != NULL && nr->natpass && nr->log)) { + if (r->log) { if (rewrite) - m_copyback(m, off, sizeof(*th), th); - PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr, - a, ruleset, pd); + m_copyback(m, off, sizeof(*th), (caddr_t)th); + PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset); } if ((r->action == PF_DROP) && @@ -2988,10 +3177,14 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, ack++; if (th->th_flags & TH_FIN) ack++; +#ifdef __FreeBSD__ + pf_send_tcp(m, r, af, pd->dst, +#else pf_send_tcp(r, af, pd->dst, +#endif pd->src, th->th_dport, th->th_sport, ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0, - r->return_ttl, 1, 0, pd->eh, kif->pfik_ifp); + r->return_ttl, 1, pd->eh, kif->pfik_ifp); } else if ((af == AF_INET) && r->return_icmp) pf_send_icmp(m, r->return_icmp >> 8, r->return_icmp & 255, af, r); @@ -3003,7 +3196,7 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, if (r->action == PF_DROP) return (PF_DROP); - if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) { + if (pf_tag_packet(m, pftag, tag)) { REASON_SET(&reason, PFRES_MEMORY); return (PF_DROP); } @@ -3023,7 +3216,7 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_MAXSTATES); goto cleanup; } - /* src node for filter rule */ + /* src node for flter rule */ if ((r->rule_flag & PFRULE_SRCTRACK || r->rpool.opts & PF_POOL_STICKYADDR) && pf_insert_src_node(&sn, r, saddr, af) != 0) { @@ -3063,9 +3256,7 @@ cleanup: s->anchor.ptr = a; STATE_INC_COUNTERS(s); s->allow_opts = r->allow_opts; - s->log = r->log & PF_LOG_ALL; - if (nr != NULL) - s->log |= nr->log & PF_LOG_ALL; + s->log = r->log & 2; s->proto = IPPROTO_TCP; s->direction = direction; s->af = af; @@ -3100,8 +3291,7 @@ cleanup: if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN && r->keep_state == PF_STATE_MODULATE) { /* Generate sequence number modulator */ - while ((s->src.seqdiff = - tcp_rndiss_next() - s->src.seqlo) == 0) + while ((s->src.seqdiff = htonl(arc4random())) == 0) ; pf_change_a(&th->th_seq, &th->th_sum, htonl(s->src.seqlo + s->src.seqdiff), 0); @@ -3192,9 +3382,13 @@ cleanup: mss = pf_calc_mss(saddr, af, mss); mss = pf_calc_mss(daddr, af, mss); s->src.mss = mss; +#ifdef __FreeBSD__ + pf_send_tcp(NULL, r, af, daddr, saddr, th->th_dport, +#else pf_send_tcp(r, af, daddr, saddr, th->th_dport, +#endif th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1, - TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL, NULL); + TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, NULL, NULL); REASON_SET(&reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); } @@ -3202,7 +3396,7 @@ cleanup: /* copy back packet headers if we performed NAT operations */ if (rewrite) - m_copyback(m, off, sizeof(*th), th); + m_copyback(m, off, sizeof(*th), (caddr_t)th); return (PF_PASS); } @@ -3210,28 +3404,42 @@ cleanup: int pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, struct pfi_kif *kif, struct mbuf *m, int off, void *h, +#ifdef __FreeBSD__ + struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, + struct ifqueue *ifq, struct inpcb *inp) +#else struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, struct ifqueue *ifq) +#endif { struct pf_rule *nr = NULL; struct pf_addr *saddr = pd->src, *daddr = pd->dst; struct udphdr *uh = pd->hdr.udp; u_int16_t bport, nport = 0; sa_family_t af = pd->af; + int lookup = -1; + uid_t uid; + gid_t gid; struct pf_rule *r, *a = NULL; struct pf_ruleset *ruleset = NULL; struct pf_src_node *nsn = NULL; u_short reason; int rewrite = 0; - int tag = -1, rtableid = -1; + struct pf_tag *pftag = NULL; + int tag = -1; int asd = 0; - int match = 0; if (pf_check_congestion(ifq)) { REASON_SET(&reason, PFRES_CONGEST); return (PF_DROP); } +#if defined(__FreeBSD__) && defined(PF_MPSAFE_UGID) + PF_UNLOCK(); + lookup = pf_socket_lookup(&uid, &gid, direction, pd, inp); + PF_LOCK(); +#endif + r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); if (direction == PF_OUT) { @@ -3266,7 +3474,8 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, while (r != NULL) { r->evaluations++; - if (pfi_kif_match(r->kif, kif) == r->ifnot) + if (r->kif != NULL && + (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR].ptr; @@ -3274,45 +3483,48 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, r = r->skip[PF_SKIP_AF].ptr; else if (r->proto && r->proto != IPPROTO_UDP) r = r->skip[PF_SKIP_PROTO].ptr; - else if (PF_MISMATCHAW(&r->src.addr, saddr, af, - r->src.neg, kif)) + else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg)) r = r->skip[PF_SKIP_SRC_ADDR].ptr; else if (r->src.port_op && !pf_match_port(r->src.port_op, r->src.port[0], r->src.port[1], uh->uh_sport)) r = r->skip[PF_SKIP_SRC_PORT].ptr; - else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, - r->dst.neg, NULL)) + else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg)) r = r->skip[PF_SKIP_DST_ADDR].ptr; else if (r->dst.port_op && !pf_match_port(r->dst.port_op, r->dst.port[0], r->dst.port[1], uh->uh_dport)) r = r->skip[PF_SKIP_DST_PORT].ptr; - else if (r->tos && !(r->tos == pd->tos)) + else if (r->tos && !(r->tos & pd->tos)) r = TAILQ_NEXT(r, entries); else if (r->rule_flag & PFRULE_FRAGMENT) r = TAILQ_NEXT(r, entries); - else if (r->uid.op && (pd->lookup.done || (pd->lookup.done = - pf_socket_lookup(direction, pd), 1)) && + else if (r->uid.op && (lookup != -1 || (lookup = +#ifdef __FreeBSD__ + pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) && +#else + pf_socket_lookup(&uid, &gid, direction, pd), 1)) && +#endif !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1], - pd->lookup.uid)) + uid)) r = TAILQ_NEXT(r, entries); - else if (r->gid.op && (pd->lookup.done || (pd->lookup.done = - pf_socket_lookup(direction, pd), 1)) && + else if (r->gid.op && (lookup != -1 || (lookup = +#ifdef __FreeBSD__ + pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) && +#else + pf_socket_lookup(&uid, &gid, direction, pd), 1)) && +#endif !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1], - pd->lookup.gid)) + gid)) r = TAILQ_NEXT(r, entries); else if (r->prob && r->prob <= arc4random()) r = TAILQ_NEXT(r, entries); - else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag)) + else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag)) r = TAILQ_NEXT(r, entries); else if (r->os_fingerprint != PF_OSFP_ANY) r = TAILQ_NEXT(r, entries); else { if (r->tag) tag = r->tag; - if (r->rtableid >= 0) - rtableid = r->rtableid; if (r->anchor == NULL) { - match = 1; *rm = r; *am = a; *rsm = ruleset; @@ -3321,11 +3533,11 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, r = TAILQ_NEXT(r, entries); } else pf_step_into_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match); + PF_RULESET_FILTER, &r, &a); } - if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match)) - break; + if (r == NULL) + pf_step_out_of_anchor(&asd, &ruleset, + PF_RULESET_FILTER, &r, &a); } r = *rm; a = *am; @@ -3333,11 +3545,10 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_MATCH); - if (r->log || (nr != NULL && nr->natpass && nr->log)) { + if (r->log) { if (rewrite) - m_copyback(m, off, sizeof(*uh), uh); - PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr, - a, ruleset, pd); + m_copyback(m, off, sizeof(*uh), (caddr_t)uh); + PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset); } if ((r->action == PF_DROP) && @@ -3366,7 +3577,7 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, if (r->action == PF_DROP) return (PF_DROP); - if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) { + if (pf_tag_packet(m, pftag, tag)) { REASON_SET(&reason, PFRES_MEMORY); return (PF_DROP); } @@ -3382,7 +3593,7 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_MAXSTATES); goto cleanup; } - /* src node for filter rule */ + /* src node for flter rule */ if ((r->rule_flag & PFRULE_SRCTRACK || r->rpool.opts & PF_POOL_STICKYADDR) && pf_insert_src_node(&sn, r, saddr, af) != 0) { @@ -3422,9 +3633,7 @@ cleanup: s->anchor.ptr = a; STATE_INC_COUNTERS(s); s->allow_opts = r->allow_opts; - s->log = r->log & PF_LOG_ALL; - if (nr != NULL) - s->log |= nr->log & PF_LOG_ALL; + s->log = r->log & 2; s->proto = IPPROTO_UDP; s->direction = direction; s->af = af; @@ -3484,7 +3693,7 @@ cleanup: /* copy back packet headers if we performed NAT operations */ if (rewrite) - m_copyback(m, off, sizeof(*uh), uh); + m_copyback(m, off, sizeof(*uh), (caddr_t)uh); return (PF_PASS); } @@ -3501,16 +3710,17 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, struct pf_ruleset *ruleset = NULL; struct pf_src_node *nsn = NULL; u_short reason; - u_int16_t icmpid, bport, nport = 0; + u_int16_t icmpid = 0, bport, nport = 0; sa_family_t af = pd->af; - u_int8_t icmptype, icmpcode; + u_int8_t icmptype = 0; /* make the compiler happy */ + u_int8_t icmpcode = 0; /* make the compiler happy */ int state_icmp = 0; - int tag = -1, rtableid = -1; + struct pf_tag *pftag = NULL; + int tag = -1; #ifdef INET6 int rewrite = 0; #endif /* INET6 */ int asd = 0; - int match = 0; if (pf_check_congestion(ifq)) { REASON_SET(&reason, PFRES_CONGEST); @@ -3564,7 +3774,8 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, pd->hdr.icmp->icmp_cksum = pf_cksum_fixup( pd->hdr.icmp->icmp_cksum, icmpid, nport, 0); pd->hdr.icmp->icmp_id = nport; - m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp); + m_copyback(m, off, ICMP_MINLEN, + (caddr_t)pd->hdr.icmp); break; #endif /* INET */ #ifdef INET6 @@ -3609,7 +3820,8 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, while (r != NULL) { r->evaluations++; - if (pfi_kif_match(r->kif, kif) == r->ifnot) + if (r->kif != NULL && + (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR].ptr; @@ -3617,33 +3829,28 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, r = r->skip[PF_SKIP_AF].ptr; else if (r->proto && r->proto != pd->proto) r = r->skip[PF_SKIP_PROTO].ptr; - else if (PF_MISMATCHAW(&r->src.addr, saddr, af, - r->src.neg, kif)) + else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg)) r = r->skip[PF_SKIP_SRC_ADDR].ptr; - else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, - r->dst.neg, NULL)) + else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg)) r = r->skip[PF_SKIP_DST_ADDR].ptr; else if (r->type && r->type != icmptype + 1) r = TAILQ_NEXT(r, entries); else if (r->code && r->code != icmpcode + 1) r = TAILQ_NEXT(r, entries); - else if (r->tos && !(r->tos == pd->tos)) + else if (r->tos && !(r->tos & pd->tos)) r = TAILQ_NEXT(r, entries); else if (r->rule_flag & PFRULE_FRAGMENT) r = TAILQ_NEXT(r, entries); else if (r->prob && r->prob <= arc4random()) r = TAILQ_NEXT(r, entries); - else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag)) + else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag)) r = TAILQ_NEXT(r, entries); else if (r->os_fingerprint != PF_OSFP_ANY) r = TAILQ_NEXT(r, entries); else { if (r->tag) tag = r->tag; - if (r->rtableid >= 0) - rtableid = r->rtableid; if (r->anchor == NULL) { - match = 1; *rm = r; *am = a; *rsm = ruleset; @@ -3652,11 +3859,11 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, r = TAILQ_NEXT(r, entries); } else pf_step_into_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match); + PF_RULESET_FILTER, &r, &a); } - if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match)) - break; + if (r == NULL) + pf_step_out_of_anchor(&asd, &ruleset, + PF_RULESET_FILTER, &r, &a); } r = *rm; a = *am; @@ -3664,20 +3871,19 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_MATCH); - if (r->log || (nr != NULL && nr->natpass && nr->log)) { + if (r->log) { #ifdef INET6 if (rewrite) m_copyback(m, off, sizeof(struct icmp6_hdr), - pd->hdr.icmp6); + (caddr_t)pd->hdr.icmp6); #endif /* INET6 */ - PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr, - a, ruleset, pd); + PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset); } if (r->action != PF_PASS) return (PF_DROP); - if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) { + if (pf_tag_packet(m, pftag, tag)) { REASON_SET(&reason, PFRES_MEMORY); return (PF_DROP); } @@ -3693,7 +3899,7 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_MAXSTATES); goto cleanup; } - /* src node for filter rule */ + /* src node for flter rule */ if ((r->rule_flag & PFRULE_SRCTRACK || r->rpool.opts & PF_POOL_STICKYADDR) && pf_insert_src_node(&sn, r, saddr, af) != 0) { @@ -3733,9 +3939,7 @@ cleanup: s->anchor.ptr = a; STATE_INC_COUNTERS(s); s->allow_opts = r->allow_opts; - s->log = r->log & PF_LOG_ALL; - if (nr != NULL) - s->log |= nr->log & PF_LOG_ALL; + s->log = r->log & 2; s->proto = pd->proto; s->direction = direction; s->af = af; @@ -3795,7 +3999,7 @@ cleanup: /* copy back packet headers if we performed IPv6 NAT operations */ if (rewrite) m_copyback(m, off, sizeof(struct icmp6_hdr), - pd->hdr.icmp6); + (caddr_t)pd->hdr.icmp6); #endif /* INET6 */ return (PF_PASS); @@ -3813,9 +4017,9 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, struct pf_addr *saddr = pd->src, *daddr = pd->dst; sa_family_t af = pd->af; u_short reason; - int tag = -1, rtableid = -1; + struct pf_tag *pftag = NULL; + int tag = -1; int asd = 0; - int match = 0; if (pf_check_congestion(ifq)) { REASON_SET(&reason, PFRES_CONGEST); @@ -3872,7 +4076,8 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, while (r != NULL) { r->evaluations++; - if (pfi_kif_match(r->kif, kif) == r->ifnot) + if (r->kif != NULL && + (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR].ptr; @@ -3880,29 +4085,24 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, r = r->skip[PF_SKIP_AF].ptr; else if (r->proto && r->proto != pd->proto) r = r->skip[PF_SKIP_PROTO].ptr; - else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, - r->src.neg, kif)) + else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg)) r = r->skip[PF_SKIP_SRC_ADDR].ptr; - else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, - r->dst.neg, NULL)) + else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg)) r = r->skip[PF_SKIP_DST_ADDR].ptr; - else if (r->tos && !(r->tos == pd->tos)) + else if (r->tos && !(r->tos & pd->tos)) r = TAILQ_NEXT(r, entries); else if (r->rule_flag & PFRULE_FRAGMENT) r = TAILQ_NEXT(r, entries); else if (r->prob && r->prob <= arc4random()) r = TAILQ_NEXT(r, entries); - else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag)) + else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag)) r = TAILQ_NEXT(r, entries); else if (r->os_fingerprint != PF_OSFP_ANY) r = TAILQ_NEXT(r, entries); else { if (r->tag) tag = r->tag; - if (r->rtableid >= 0) - rtableid = r->rtableid; if (r->anchor == NULL) { - match = 1; *rm = r; *am = a; *rsm = ruleset; @@ -3911,11 +4111,11 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, r = TAILQ_NEXT(r, entries); } else pf_step_into_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match); + PF_RULESET_FILTER, &r, &a); } - if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match)) - break; + if (r == NULL) + pf_step_out_of_anchor(&asd, &ruleset, + PF_RULESET_FILTER, &r, &a); } r = *rm; a = *am; @@ -3923,9 +4123,8 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_MATCH); - if (r->log || (nr != NULL && nr->natpass && nr->log)) - PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr, - a, ruleset, pd); + if (r->log) + PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset); if ((r->action == PF_DROP) && ((r->rule_flag & PFRULE_RETURNICMP) || @@ -3964,7 +4163,7 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, if (r->action != PF_PASS) return (PF_DROP); - if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) { + if (pf_tag_packet(m, pftag, tag)) { REASON_SET(&reason, PFRES_MEMORY); return (PF_DROP); } @@ -3980,7 +4179,7 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_MAXSTATES); goto cleanup; } - /* src node for filter rule */ + /* src node for flter rule */ if ((r->rule_flag & PFRULE_SRCTRACK || r->rpool.opts & PF_POOL_STICKYADDR) && pf_insert_src_node(&sn, r, saddr, af) != 0) { @@ -4020,9 +4219,7 @@ cleanup: s->anchor.ptr = a; STATE_INC_COUNTERS(s); s->allow_opts = r->allow_opts; - s->log = r->log & PF_LOG_ALL; - if (nr != NULL) - s->log |= nr->log & PF_LOG_ALL; + s->log = r->log & 2; s->proto = pd->proto; s->direction = direction; s->af = af; @@ -4082,14 +4279,15 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, struct pf_ruleset *ruleset = NULL; sa_family_t af = pd->af; u_short reason; + struct pf_tag *pftag = NULL; int tag = -1; int asd = 0; - int match = 0; r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); while (r != NULL) { r->evaluations++; - if (pfi_kif_match(r->kif, kif) == r->ifnot) + if (r->kif != NULL && + (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR].ptr; @@ -4097,13 +4295,11 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, r = r->skip[PF_SKIP_AF].ptr; else if (r->proto && r->proto != pd->proto) r = r->skip[PF_SKIP_PROTO].ptr; - else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, - r->src.neg, kif)) + else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg)) r = r->skip[PF_SKIP_SRC_ADDR].ptr; - else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, - r->dst.neg, NULL)) + else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg)) r = r->skip[PF_SKIP_DST_ADDR].ptr; - else if (r->tos && !(r->tos == pd->tos)) + else if (r->tos && !(r->tos & pd->tos)) r = TAILQ_NEXT(r, entries); else if (r->src.port_op || r->dst.port_op || r->flagset || r->type || r->code || @@ -4111,11 +4307,10 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, r = TAILQ_NEXT(r, entries); else if (r->prob && r->prob <= arc4random()) r = TAILQ_NEXT(r, entries); - else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag)) + else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag)) r = TAILQ_NEXT(r, entries); else { if (r->anchor == NULL) { - match = 1; *rm = r; *am = a; *rsm = ruleset; @@ -4124,11 +4319,11 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, r = TAILQ_NEXT(r, entries); } else pf_step_into_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match); + PF_RULESET_FILTER, &r, &a); } - if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match)) - break; + if (r == NULL) + pf_step_out_of_anchor(&asd, &ruleset, + PF_RULESET_FILTER, &r, &a); } r = *rm; a = *am; @@ -4137,13 +4332,12 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, REASON_SET(&reason, PFRES_MATCH); if (r->log) - PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset, - pd); + PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset); if (r->action != PF_PASS) return (PF_DROP); - if (pf_tag_packet(m, pd->pf_mtag, tag, -1)) { + if (pf_tag_packet(m, pftag, tag)) { REASON_SET(&reason, PFRES_MEMORY); return (PF_DROP); } @@ -4156,7 +4350,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason) { - struct pf_state_cmp key; + struct pf_state key; struct tcphdr *th = pd->hdr.tcp; u_int16_t win = ntohs(th->th_win); u_int32_t ack, end, seq, orig_seq; @@ -4199,11 +4393,15 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, REASON_SET(reason, PFRES_SYNPROXY); return (PF_DROP); } +#ifdef __FreeBSD__ + pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst, +#else pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst, +#endif pd->src, th->th_dport, th->th_sport, (*state)->src.seqhi, ntohl(th->th_seq) + 1, TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1, - 0, NULL, NULL); + NULL, NULL); REASON_SET(reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); } else if (!(th->th_flags & TH_ACK) || @@ -4238,10 +4436,15 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, (*state)->src.max_win = MAX(ntohs(th->th_win), 1); if ((*state)->dst.seqhi == 1) (*state)->dst.seqhi = htonl(arc4random()); +#ifdef __FreeBSD__ + pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, + &src->addr, +#else pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr, +#endif &dst->addr, src->port, dst->port, (*state)->dst.seqhi, 0, TH_SYN, 0, - (*state)->src.mss, 0, 0, (*state)->tag, NULL, NULL); + (*state)->src.mss, 0, 0, NULL, NULL); REASON_SET(reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); } else if (((th->th_flags & (TH_SYN|TH_ACK)) != @@ -4252,16 +4455,25 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, } else { (*state)->dst.max_win = MAX(ntohs(th->th_win), 1); (*state)->dst.seqlo = ntohl(th->th_seq); +#ifdef __FreeBSD__ + pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst, +#else pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst, +#endif pd->src, th->th_dport, th->th_sport, ntohl(th->th_ack), ntohl(th->th_seq) + 1, TH_ACK, (*state)->src.max_win, 0, 0, 0, - (*state)->tag, NULL, NULL); + NULL, NULL); +#ifdef __FreeBSD__ + pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, + &src->addr, +#else pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr, +#endif &dst->addr, src->port, dst->port, (*state)->src.seqhi + 1, (*state)->src.seqlo + 1, TH_ACK, (*state)->dst.max_win, 0, 0, 1, - 0, NULL, NULL); + NULL, NULL); (*state)->src.seqdiff = (*state)->dst.seqhi - (*state)->src.seqlo; (*state)->dst.seqdiff = (*state)->src.seqhi - @@ -4304,7 +4516,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, /* Deferred generation of sequence number modulator */ if (dst->seqdiff && !src->seqdiff) { - while ((src->seqdiff = tcp_rndiss_next() - seq) == 0) + while ((src->seqdiff = htonl(arc4random())) == 0) ; ack = ntohl(th->th_ack) - dst->seqdiff; pf_change_a(&th->th_seq, &th->th_sum, htonl(seq + @@ -4393,25 +4605,6 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, ackskew = dst->seqlo - ack; - - /* - * Need to demodulate the sequence numbers in any TCP SACK options - * (Selective ACK). We could optionally validate the SACK values - * against the current ACK window, either forwards or backwards, but - * I'm not confident that SACK has been implemented properly - * everywhere. It wouldn't surprise me if several stacks accidently - * SACK too far backwards of previously ACKed data. There really aren't - * any security implications of bad SACKing unless the target stack - * doesn't validate the option length correctly. Someone trying to - * spoof into a TCP connection won't bother blindly sending SACK - * options anyway. - */ - if (dst->seqdiff && (th->th_off << 2) > sizeof(struct tcphdr)) { - if (pf_modulate_sack(m, off, pd, th, dst)) - copyback = 1; - } - - #define MAXACKWINDOW (0xffff + 1500) /* 1500 is an arbitrary fudge factor */ if (SEQ_GEQ(src->seqhi, end) && /* Last octet inside other's window space */ @@ -4422,8 +4615,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, (ackskew <= (MAXACKWINDOW << sws)) && /* Acking not more than one window forward */ ((th->th_flags & TH_RST) == 0 || orig_seq == src->seqlo || - (orig_seq == src->seqlo + 1) || (pd->flags & PFDESC_IP_REAS) == 0)) { - /* Require an exact/+1 sequence match on resets when possible */ + (pd->flags & PFDESC_IP_REAS) == 0)) { + /* Require an exact sequence match on resets when possible */ if (dst->scrub || src->scrub) { if (pf_normalize_tcp_stateful(m, off, pd, reason, th, @@ -4469,8 +4662,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, if (src->state >= TCPS_FIN_WAIT_2 && dst->state >= TCPS_FIN_WAIT_2) (*state)->timeout = PFTM_TCP_CLOSED; - else if (src->state >= TCPS_CLOSING && - dst->state >= TCPS_CLOSING) + else if (src->state >= TCPS_FIN_WAIT_2 || + dst->state >= TCPS_FIN_WAIT_2) (*state)->timeout = PFTM_TCP_FIN_WAIT; else if (src->state < TCPS_ESTABLISHED || dst->state < TCPS_ESTABLISHED) @@ -4516,10 +4709,9 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, printf("pf: loose state match: "); pf_print_state(*state); pf_print_flags(th->th_flags); - printf(" seq=%u (%u) ack=%u len=%u ackskew=%d " - "pkts=%llu:%llu\n", seq, orig_seq, ack, pd->p_len, - ackskew, (*state)->packets[0], - (*state)->packets[1]); + printf(" seq=%u ack=%u len=%u ackskew=%d pkts=%d:%d\n", + seq, ack, pd->p_len, ackskew, + (*state)->packets[0], (*state)->packets[1]); } if (dst->scrub || src->scrub) { @@ -4556,11 +4748,15 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, (*state)->src.state == TCPS_SYN_SENT) { /* Send RST for state mismatches during handshake */ if (!(th->th_flags & TH_RST)) +#ifdef __FreeBSD__ + pf_send_tcp(m, (*state)->rule.ptr, pd->af, +#else pf_send_tcp((*state)->rule.ptr, pd->af, +#endif pd->dst, pd->src, th->th_dport, th->th_sport, ntohl(th->th_ack), 0, TH_RST, 0, 0, - (*state)->rule.ptr->return_ttl, 1, 0, + (*state)->rule.ptr->return_ttl, 1, pd->eh, kif->pfik_ifp); src->seqlo = 0; src->seqhi = 1; @@ -4569,9 +4765,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, printf("pf: BAD state: "); pf_print_state(*state); pf_print_flags(th->th_flags); - printf(" seq=%u (%u) ack=%u len=%u ackskew=%d " - "pkts=%llu:%llu dir=%s,%s\n", - seq, orig_seq, ack, pd->p_len, ackskew, + printf(" seq=%u ack=%u len=%u ackskew=%d pkts=%d:%d " + "dir=%s,%s\n", seq, ack, pd->p_len, ackskew, (*state)->packets[0], (*state)->packets[1], direction == PF_IN ? "in" : "out", direction == (*state)->direction ? "fwd" : "rev"); @@ -4600,10 +4795,10 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum, &th->th_sum, &(*state)->lan.addr, (*state)->lan.port, 0, pd->af); - m_copyback(m, off, sizeof(*th), th); + m_copyback(m, off, sizeof(*th), (caddr_t)th); } else if (copyback) { /* Copyback sequence modulation or stateful scrub changes */ - m_copyback(m, off, sizeof(*th), th); + m_copyback(m, off, sizeof(*th), (caddr_t)th); } return (PF_PASS); @@ -4614,7 +4809,7 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd) { struct pf_state_peer *src, *dst; - struct pf_state_cmp key; + struct pf_state key; struct udphdr *uh = pd->hdr.udp; key.af = pd->af; @@ -4664,7 +4859,7 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif, pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum, &uh->uh_sum, &(*state)->lan.addr, (*state)->lan.port, 1, pd->af); - m_copyback(m, off, sizeof(*uh), uh); + m_copyback(m, off, sizeof(*uh), (caddr_t)uh); } return (PF_PASS); @@ -4675,10 +4870,10 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason) { struct pf_addr *saddr = pd->src, *daddr = pd->dst; - u_int16_t icmpid, *icmpsum; - u_int8_t icmptype; + u_int16_t icmpid = 0; /* make the compiler happy */ + u_int16_t *icmpsum = NULL; /* make the compiler happy */ + u_int8_t icmptype = 0; /* make the compiler happy */ int state_icmp = 0; - struct pf_state_cmp key; switch (pd->proto) { #ifdef INET @@ -4716,6 +4911,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, * ICMP query/reply message not related to a TCP/UDP packet. * Search for an ICMP state. */ + struct pf_state key; + key.af = pd->af; key.proto = pd->proto; if (direction == PF_IN) { @@ -4751,7 +4948,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, pd->hdr.icmp->icmp_id = (*state)->gwy.port; m_copyback(m, off, ICMP_MINLEN, - pd->hdr.icmp); + (caddr_t)pd->hdr.icmp); break; #endif /* INET */ #ifdef INET6 @@ -4761,7 +4958,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, &(*state)->gwy.addr, 0); m_copyback(m, off, sizeof(struct icmp6_hdr), - pd->hdr.icmp6); + (caddr_t)pd->hdr.icmp6); break; #endif /* INET6 */ } @@ -4779,7 +4976,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, pd->hdr.icmp->icmp_id = (*state)->lan.port; m_copyback(m, off, ICMP_MINLEN, - pd->hdr.icmp); + (caddr_t)pd->hdr.icmp); break; #endif /* INET */ #ifdef INET6 @@ -4789,7 +4986,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, &(*state)->lan.addr, 0); m_copyback(m, off, sizeof(struct icmp6_hdr), - pd->hdr.icmp6); + (caddr_t)pd->hdr.icmp6); break; #endif /* INET6 */ } @@ -4812,8 +5009,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, struct ip6_hdr h2_6; int terminal = 0; #endif /* INET6 */ - int ipoff2; - int off2; + int ipoff2 = 0; /* make the compiler happy */ + int off2 = 0; /* make the compiler happy */ pd2.af = pd->af; switch (pd->af) { @@ -4907,6 +5104,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, case IPPROTO_TCP: { struct tcphdr th; u_int32_t seq; + struct pf_state key; struct pf_state_peer *src, *dst; u_int8_t dws; int copyback = 0; @@ -5000,22 +5198,22 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, #ifdef INET case AF_INET: m_copyback(m, off, ICMP_MINLEN, - pd->hdr.icmp); + (caddr_t)pd->hdr.icmp); m_copyback(m, ipoff2, sizeof(h2), - &h2); + (caddr_t)&h2); break; #endif /* INET */ #ifdef INET6 case AF_INET6: m_copyback(m, off, sizeof(struct icmp6_hdr), - pd->hdr.icmp6); + (caddr_t)pd->hdr.icmp6); m_copyback(m, ipoff2, sizeof(h2_6), - &h2_6); + (caddr_t)&h2_6); break; #endif /* INET6 */ } - m_copyback(m, off2, 8, &th); + m_copyback(m, off2, 8, (caddr_t)&th); } return (PF_PASS); @@ -5023,6 +5221,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, } case IPPROTO_UDP: { struct udphdr uh; + struct pf_state key; if (!pf_pull_hdr(m, off2, &uh, sizeof(uh), NULL, reason, pd2.af)) { @@ -5066,21 +5265,23 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, #ifdef INET case AF_INET: m_copyback(m, off, ICMP_MINLEN, - pd->hdr.icmp); - m_copyback(m, ipoff2, sizeof(h2), &h2); + (caddr_t)pd->hdr.icmp); + m_copyback(m, ipoff2, sizeof(h2), + (caddr_t)&h2); break; #endif /* INET */ #ifdef INET6 case AF_INET6: m_copyback(m, off, sizeof(struct icmp6_hdr), - pd->hdr.icmp6); + (caddr_t)pd->hdr.icmp6); m_copyback(m, ipoff2, sizeof(h2_6), - &h2_6); + (caddr_t)&h2_6); break; #endif /* INET6 */ } - m_copyback(m, off2, sizeof(uh), &uh); + m_copyback(m, off2, sizeof(uh), + (caddr_t)&uh); } return (PF_PASS); @@ -5089,6 +5290,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, #ifdef INET case IPPROTO_ICMP: { struct icmp iih; + struct pf_state key; if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN, NULL, reason, pd2.af)) { @@ -5128,9 +5330,12 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, pd2.ip_sum, icmpsum, pd->ip_sum, 0, AF_INET); } - m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp); - m_copyback(m, ipoff2, sizeof(h2), &h2); - m_copyback(m, off2, ICMP_MINLEN, &iih); + m_copyback(m, off, ICMP_MINLEN, + (caddr_t)pd->hdr.icmp); + m_copyback(m, ipoff2, sizeof(h2), + (caddr_t)&h2); + m_copyback(m, off2, ICMP_MINLEN, + (caddr_t)&iih); } return (PF_PASS); @@ -5140,6 +5345,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, #ifdef INET6 case IPPROTO_ICMPV6: { struct icmp6_hdr iih; + struct pf_state key; if (!pf_pull_hdr(m, off2, &iih, sizeof(struct icmp6_hdr), NULL, reason, pd2.af)) { @@ -5180,10 +5386,11 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, pd->ip_sum, 0, AF_INET6); } m_copyback(m, off, sizeof(struct icmp6_hdr), - pd->hdr.icmp6); - m_copyback(m, ipoff2, sizeof(h2_6), &h2_6); + (caddr_t)pd->hdr.icmp6); + m_copyback(m, ipoff2, sizeof(h2_6), + (caddr_t)&h2_6); m_copyback(m, off2, sizeof(struct icmp6_hdr), - &iih); + (caddr_t)&iih); } return (PF_PASS); @@ -5191,6 +5398,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, } #endif /* INET6 */ default: { + struct pf_state key; + key.af = pd2.af; key.proto = pd2.proto; if (direction == PF_IN) { @@ -5225,17 +5434,18 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, #ifdef INET case AF_INET: m_copyback(m, off, ICMP_MINLEN, - pd->hdr.icmp); - m_copyback(m, ipoff2, sizeof(h2), &h2); + (caddr_t)pd->hdr.icmp); + m_copyback(m, ipoff2, sizeof(h2), + (caddr_t)&h2); break; #endif /* INET */ #ifdef INET6 case AF_INET6: m_copyback(m, off, sizeof(struct icmp6_hdr), - pd->hdr.icmp6); + (caddr_t)pd->hdr.icmp6); m_copyback(m, ipoff2, sizeof(h2_6), - &h2_6); + (caddr_t)&h2_6); break; #endif /* INET6 */ } @@ -5253,7 +5463,7 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif, struct pf_pdesc *pd) { struct pf_state_peer *src, *dst; - struct pf_state_cmp key; + struct pf_state key; key.af = pd->af; key.proto = pd->proto; @@ -5381,24 +5591,16 @@ pf_pull_hdr(struct mbuf *m, int off, void *p, int len, } int -pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif) +pf_routable(struct pf_addr *addr, sa_family_t af) { struct sockaddr_in *dst; - int ret = 1; - int check_mpath; - extern int ipmultipath; #ifdef INET6 - extern int ip6_multipath; struct sockaddr_in6 *dst6; struct route_in6 ro; #else struct route ro; #endif - struct radix_node *rn; - struct rtentry *rt; - struct ifnet *ifp; - check_mpath = 0; bzero(&ro, sizeof(ro)); switch (af) { case AF_INET: @@ -5406,8 +5608,6 @@ pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif) dst->sin_family = AF_INET; dst->sin_len = sizeof(*dst); dst->sin_addr = addr->v4; - if (ipmultipath) - check_mpath = 1; break; #ifdef INET6 case AF_INET6: @@ -5415,50 +5615,28 @@ pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif) dst6->sin6_family = AF_INET6; dst6->sin6_len = sizeof(*dst6); dst6->sin6_addr = addr->v6; - if (ip6_multipath) - check_mpath = 1; break; #endif /* INET6 */ default: return (0); } - /* Skip checks for ipsec interfaces */ - if (kif != NULL && kif->pfik_ifp->if_type == IFT_ENC) - goto out; - +#ifdef __FreeBSD__ +#ifdef RTF_PRCLONING + rtalloc_ign((struct route *)&ro, (RTF_CLONING | RTF_PRCLONING)); +#else /* !RTF_PRCLONING */ + rtalloc_ign((struct route *)&ro, RTF_CLONING); +#endif +#else /* ! __FreeBSD__ */ rtalloc_noclone((struct route *)&ro, NO_CLONING); +#endif if (ro.ro_rt != NULL) { - /* No interface given, this is a no-route check */ - if (kif == NULL) - goto out; - - if (kif->pfik_ifp == NULL) { - ret = 0; - goto out; - } - - /* Perform uRPF check if passed input interface */ - ret = 0; - rn = (struct radix_node *)ro.ro_rt; - do { - rt = (struct rtentry *)rn; - if (rt->rt_ifp->if_type == IFT_CARP) - ifp = rt->rt_ifp->if_carpdev; - else - ifp = rt->rt_ifp; - - if (kif->pfik_ifp == ifp) - ret = 1; - rn = rn_mpath_next(rn); - } while (check_mpath == 1 && rn != NULL && ret == 0); - } else - ret = 0; -out: - if (ro.ro_rt != NULL) RTFREE(ro.ro_rt); - return (ret); + return (1); + } + + return (0); } int @@ -5493,11 +5671,23 @@ pf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw) return (0); } +#ifdef __FreeBSD__ +# ifdef RTF_PRCLONING + rtalloc_ign((struct route *)&ro, (RTF_CLONING|RTF_PRCLONING)); +# else /* !RTF_PRCLONING */ + rtalloc_ign((struct route *)&ro, RTF_CLONING); +# endif +#else /* ! __FreeBSD__ */ rtalloc_noclone((struct route *)&ro, NO_CLONING); +#endif if (ro.ro_rt != NULL) { +#ifdef __FreeBSD__ + /* XXX_IMPORT: later */ +#else if (ro.ro_rt->rt_labelid == aw->v.rtlabel) ret = 1; +#endif RTFREE(ro.ro_rt); } @@ -5505,35 +5695,53 @@ pf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw) } #ifdef INET + void pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, - struct pf_state *s, struct pf_pdesc *pd) + struct pf_state *s) { struct mbuf *m0, *m1; + struct m_tag *mtag; struct route iproute; - struct route *ro = NULL; + struct route *ro = NULL; /* XXX: was uninitialized */ struct sockaddr_in *dst; struct ip *ip; struct ifnet *ifp = NULL; struct pf_addr naddr; struct pf_src_node *sn = NULL; int error = 0; -#ifdef IPSEC - struct m_tag *mtag; -#endif /* IPSEC */ +#ifdef __FreeBSD__ + int sw_csum; +#endif if (m == NULL || *m == NULL || r == NULL || (dir != PF_IN && dir != PF_OUT) || oifp == NULL) panic("pf_route: invalid parameters"); - if (pd->pf_mtag->routed++ > 3) { - m0 = *m; - *m = NULL; - goto bad; + if ((mtag = m_tag_find(*m, PACKET_TAG_PF_ROUTED, NULL)) == NULL) { + if ((mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 1, M_NOWAIT)) == + NULL) { + m0 = *m; + *m = NULL; + goto bad; + } + *(char *)(mtag + 1) = 1; + m_tag_prepend(*m, mtag); + } else { + if (*(char *)(mtag + 1) > 3) { + m0 = *m; + *m = NULL; + goto bad; + } + (*(char *)(mtag + 1))++; } if (r->rt == PF_DUPTO) { +#ifdef __FreeBSD__ + if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL) +#else if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL) +#endif return; } else { if ((r->rt == PF_REPLYTO) == (r->direction == dir)) @@ -5592,10 +5800,22 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, goto bad; if (oifp != ifp) { +#ifdef __FreeBSD__ + PF_UNLOCK(); + if (pf_test(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) { + PF_LOCK(); + goto bad; + } else if (m0 == NULL) { + PF_LOCK(); + goto done; + } + PF_LOCK(); +#else if (pf_test(PF_OUT, ifp, &m0, NULL) != PF_PASS) goto bad; else if (m0 == NULL) goto done; +#endif if (m0->m_len < sizeof(struct ip)) { DPFPRINTF(PF_DEBUG_URGENT, ("pf_route: m0->m_len < sizeof(struct ip)\n")); @@ -5604,6 +5824,47 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, ip = mtod(m0, struct ip *); } +#ifdef __FreeBSD__ + /* Copied from FreeBSD 5.1-CURRENT ip_output. */ + m0->m_pkthdr.csum_flags |= CSUM_IP; + sw_csum = m0->m_pkthdr.csum_flags & ~ifp->if_hwassist; + if (sw_csum & CSUM_DELAY_DATA) { + /* + * XXX: in_delayed_cksum assumes HBO for ip->ip_len (at least) + */ + NTOHS(ip->ip_len); + NTOHS(ip->ip_off); /* XXX: needed? */ + in_delayed_cksum(m0); + HTONS(ip->ip_len); + HTONS(ip->ip_off); + sw_csum &= ~CSUM_DELAY_DATA; + } + m0->m_pkthdr.csum_flags &= ifp->if_hwassist; + + if (ntohs(ip->ip_len) <= ifp->if_mtu || + (ifp->if_hwassist & CSUM_FRAGMENT && + ((ip->ip_off & htons(IP_DF)) == 0))) { + /* + * ip->ip_len = htons(ip->ip_len); + * ip->ip_off = htons(ip->ip_off); + */ + ip->ip_sum = 0; + if (sw_csum & CSUM_DELAY_IP) { + /* From KAME */ + if (ip->ip_v == IPVERSION && + (ip->ip_hl << 2) == sizeof(*ip)) { + ip->ip_sum = in_cksum_hdr(ip); + } else { + ip->ip_sum = in_cksum(m0, ip->ip_hl << 2); + } + } + PF_UNLOCK(); + error = (*ifp->if_output)(ifp, m0, sintosa(dst), ro->ro_rt); + PF_LOCK(); + goto done; + } + +#else /* Copied from ip_output. */ #ifdef IPSEC /* @@ -5619,38 +5880,38 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, #endif /* IPSEC */ /* Catch routing changes wrt. hardware checksumming for TCP or UDP. */ - if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT) { + if (m0->m_pkthdr.csum & M_TCPV4_CSUM_OUT) { if (!(ifp->if_capabilities & IFCAP_CSUM_TCPv4) || ifp->if_bridge != NULL) { in_delayed_cksum(m0); - m0->m_pkthdr.csum_flags &= ~M_TCPV4_CSUM_OUT; /* Clear */ + m0->m_pkthdr.csum &= ~M_TCPV4_CSUM_OUT; /* Clear */ } - } else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT) { + } else if (m0->m_pkthdr.csum & M_UDPV4_CSUM_OUT) { if (!(ifp->if_capabilities & IFCAP_CSUM_UDPv4) || ifp->if_bridge != NULL) { in_delayed_cksum(m0); - m0->m_pkthdr.csum_flags &= ~M_UDPV4_CSUM_OUT; /* Clear */ + m0->m_pkthdr.csum &= ~M_UDPV4_CSUM_OUT; /* Clear */ } } if (ntohs(ip->ip_len) <= ifp->if_mtu) { if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) && ifp->if_bridge == NULL) { - m0->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT; + m0->m_pkthdr.csum |= M_IPV4_CSUM_OUT; ipstat.ips_outhwcsum++; } else { ip->ip_sum = 0; ip->ip_sum = in_cksum(m0, ip->ip_hl << 2); } /* Update relevant hardware checksum stats for TCP/UDP */ - if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT) + if (m0->m_pkthdr.csum & M_TCPV4_CSUM_OUT) tcpstat.tcps_outhwcsum++; - else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT) + else if (m0->m_pkthdr.csum & M_UDPV4_CSUM_OUT) udpstat.udps_outhwcsum++; error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL); goto done; } - +#endif /* * Too large for interface; fragment if possible. * Must be able to put at least 8 bytes per fragment. @@ -5658,27 +5919,57 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, if (ip->ip_off & htons(IP_DF)) { ipstat.ips_cantfrag++; if (r->rt != PF_DUPTO) { +#ifdef __FreeBSD__ + /* icmp_error() expects host byte ordering */ + NTOHS(ip->ip_len); + NTOHS(ip->ip_off); + PF_UNLOCK(); icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0, ifp->if_mtu); + PF_LOCK(); +#else + icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0, + ifp); +#endif goto done; } else goto bad; } m1 = m0; +#ifdef __FreeBSD__ + /* + * XXX: is cheaper + less error prone than own function + */ + NTOHS(ip->ip_len); + NTOHS(ip->ip_off); + error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist, sw_csum); +#else error = ip_fragment(m0, ifp, ifp->if_mtu); +#endif if (error) { +#ifndef __FreeBSD__ /* ip_fragment does not do m_freem() on FreeBSD */ m0 = NULL; +#endif goto bad; } for (m0 = m1; m0; m0 = m1) { m1 = m0->m_nextpkt; m0->m_nextpkt = 0; +#ifdef __FreeBSD__ + if (error == 0) { + PF_UNLOCK(); + error = (*ifp->if_output)(ifp, m0, sintosa(dst), + NULL); + PF_LOCK(); + } else +#else if (error == 0) error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL); else +#endif m_freem(m0); } @@ -5701,9 +5992,10 @@ bad: #ifdef INET6 void pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, - struct pf_state *s, struct pf_pdesc *pd) + struct pf_state *s) { struct mbuf *m0; + struct m_tag *mtag; struct route_in6 ip6route; struct route_in6 *ro; struct sockaddr_in6 *dst; @@ -5717,14 +6009,30 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, (dir != PF_IN && dir != PF_OUT) || oifp == NULL) panic("pf_route6: invalid parameters"); - if (pd->pf_mtag->routed++ > 3) { - m0 = *m; - *m = NULL; - goto bad; + if ((mtag = m_tag_find(*m, PACKET_TAG_PF_ROUTED, NULL)) == NULL) { + if ((mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 1, M_NOWAIT)) == + NULL) { + m0 = *m; + *m = NULL; + goto bad; + } + *(char *)(mtag + 1) = 1; + m_tag_prepend(*m, mtag); + } else { + if (*(char *)(mtag + 1) > 3) { + m0 = *m; + *m = NULL; + goto bad; + } + (*(char *)(mtag + 1))++; } if (r->rt == PF_DUPTO) { +#ifdef __FreeBSD__ + if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL) +#else if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL) +#endif return; } else { if ((r->rt == PF_REPLYTO) == (r->direction == dir)) @@ -5746,10 +6054,20 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, dst->sin6_len = sizeof(*dst); dst->sin6_addr = ip6->ip6_dst; - /* Cheat. XXX why only in the v6 case??? */ + /* Cheat. */ if (r->rt == PF_FASTROUTE) { - pd->pf_mtag->flags |= PF_TAG_GENERATED; +#ifdef __FreeBSD__ + m0->m_flags |= M_SKIP_FIREWALL; + PF_UNLOCK(); + ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL); + PF_LOCK(); +#else + mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT); + if (mtag == NULL) + goto bad; + m_tag_prepend(m0, mtag); ip6_output(m0, NULL, NULL, 0, NULL, NULL); +#endif return; } @@ -5775,10 +6093,22 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, goto bad; if (oifp != ifp) { +#ifdef __FreeBSD__ + PF_UNLOCK(); + if (pf_test6(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) { + PF_LOCK(); + goto bad; + } else if (m0 == NULL) { + PF_LOCK(); + goto done; + } + PF_LOCK(); +#else if (pf_test6(PF_OUT, ifp, &m0, NULL) != PF_PASS) goto bad; else if (m0 == NULL) goto done; +#endif if (m0->m_len < sizeof(struct ip6_hdr)) { DPFPRINTF(PF_DEBUG_URGENT, ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n")); @@ -5791,15 +6121,29 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, * If the packet is too large for the outgoing interface, * send back an icmp6 error. */ - if (IN6_IS_SCOPE_EMBED(&dst->sin6_addr)) + if (IN6_IS_ADDR_LINKLOCAL(&dst->sin6_addr)) dst->sin6_addr.s6_addr16[1] = htons(ifp->if_index); if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) { +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif error = nd6_output(ifp, ifp, m0, dst, NULL); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif } else { in6_ifstat_inc(ifp, ifs6_in_toobig); +#ifdef __FreeBSD__ + if (r->rt != PF_DUPTO) { + PF_UNLOCK(); + icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu); + PF_LOCK(); + } else +#else if (r->rt != PF_DUPTO) icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu); else +#endif goto bad; } @@ -5815,6 +6159,131 @@ bad: #endif /* INET6 */ +#ifdef __FreeBSD__ +/* + * FreeBSD supports cksum offloads for the following drivers. + * em(4), fxp(4), ixgb(4), lge(4), ndis(4), nge(4), re(4), + * ti(4), txp(4), xl(4) + * + * CSUM_DATA_VALID | CSUM_PSEUDO_HDR : + * network driver performed cksum including pseudo header, need to verify + * csum_data + * CSUM_DATA_VALID : + * network driver performed cksum, needs to additional pseudo header + * cksum computation with partial csum_data(i.e. lack of H/W support for + * pseudo header, for instance hme(4), sk(4) and possibly gem(4)) + * + * After validating the cksum of packet, set both flag CSUM_DATA_VALID and + * CSUM_PSEUDO_HDR in order to avoid recomputation of the cksum in upper + * TCP/UDP layer. + * Also, set csum_data to 0xffff to force cksum validation. + */ +int +pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t af) +{ + u_int16_t sum = 0; + int hw_assist = 0; + struct ip *ip; + + if (off < sizeof(struct ip) || len < sizeof(struct udphdr)) + return (1); + if (m->m_pkthdr.len < off + len) + return (1); + + switch (p) { + case IPPROTO_TCP: + if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { + if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) { + sum = m->m_pkthdr.csum_data; + } else { + ip = mtod(m, struct ip *); + sum = in_pseudo(ip->ip_src.s_addr, + ip->ip_dst.s_addr, htonl((u_short)len + + m->m_pkthdr.csum_data + IPPROTO_TCP)); + } + sum ^= 0xffff; + ++hw_assist; + } + break; + case IPPROTO_UDP: + if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { + if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) { + sum = m->m_pkthdr.csum_data; + } else { + ip = mtod(m, struct ip *); + sum = in_pseudo(ip->ip_src.s_addr, + ip->ip_dst.s_addr, htonl((u_short)len + + m->m_pkthdr.csum_data + IPPROTO_UDP)); + } + sum ^= 0xffff; + ++hw_assist; + } + break; + case IPPROTO_ICMP: +#ifdef INET6 + case IPPROTO_ICMPV6: +#endif /* INET6 */ + break; + default: + return (1); + } + + if (!hw_assist) { + switch (af) { + case AF_INET: + if (p == IPPROTO_ICMP) { + if (m->m_len < off) + return (1); + m->m_data += off; + m->m_len -= off; + sum = in_cksum(m, len); + m->m_data -= off; + m->m_len += off; + } else { + if (m->m_len < sizeof(struct ip)) + return (1); + sum = in4_cksum(m, p, off, len); + } + break; +#ifdef INET6 + case AF_INET6: + if (m->m_len < sizeof(struct ip6_hdr)) + return (1); + sum = in6_cksum(m, p, off, len); + break; +#endif /* INET6 */ + default: + return (1); + } + } + if (sum) { + switch (p) { + case IPPROTO_TCP: + tcpstat.tcps_rcvbadsum++; + break; + case IPPROTO_UDP: + udpstat.udps_badsum++; + break; + case IPPROTO_ICMP: + icmpstat.icps_checksum++; + break; +#ifdef INET6 + case IPPROTO_ICMPV6: + icmp6stat.icp6s_checksum++; + break; +#endif /* INET6 */ + } + return (1); + } else { + if (p == IPPROTO_TCP || p == IPPROTO_UDP) { + m->m_pkthdr.csum_flags |= + (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); + m->m_pkthdr.csum_data = 0xffff; + } + } + return (0); +} +#else /* * check protocol (tcp/udp/icmp/icmp6) checksum and set mbuf flag * off is the offset where the protocol header starts @@ -5846,9 +6315,9 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, default: return (1); } - if (m->m_pkthdr.csum_flags & flag_ok) + if (m->m_pkthdr.csum & flag_ok) return (0); - if (m->m_pkthdr.csum_flags & flag_bad) + if (m->m_pkthdr.csum & flag_bad) return (1); if (off < sizeof(struct ip) || len < sizeof(struct udphdr)) return (1); @@ -5883,7 +6352,7 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, return (1); } if (sum) { - m->m_pkthdr.csum_flags |= flag_bad; + m->m_pkthdr.csum |= flag_bad; switch (p) { case IPPROTO_TCP: tcpstat.tcps_rcvbadsum++; @@ -5902,54 +6371,91 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, } return (1); } - m->m_pkthdr.csum_flags |= flag_ok; + m->m_pkthdr.csum |= flag_ok; + return (0); +} +#endif + +static int +pf_add_mbuf_tag(struct mbuf *m, u_int tag) +{ + struct m_tag *mtag; + + if (m_tag_find(m, tag, NULL) != NULL) + return (0); + mtag = m_tag_get(tag, 0, M_NOWAIT); + if (mtag == NULL) + return (1); + m_tag_prepend(m, mtag); return (0); } #ifdef INET int +#ifdef __FreeBSD__ +pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, + struct ether_header *eh, struct inpcb *inp) +#else pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct ether_header *eh) +#endif { struct pfi_kif *kif; u_short action, reason = 0, log = 0; struct mbuf *m = *m0; - struct ip *h; + struct ip *h = NULL; /* make the compiler happy */ struct pf_rule *a = NULL, *r = &pf_default_rule, *tr, *nr; struct pf_state *s = NULL; struct pf_ruleset *ruleset = NULL; struct pf_pdesc pd; int off, dirndx, pqid = 0; - if (!pf_status.running) - return (PF_PASS); - - memset(&pd, 0, sizeof(pd)); - if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) { - DPFPRINTF(PF_DEBUG_URGENT, - ("pf_test: pf_get_mtag returned NULL\n")); - return (PF_DROP); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif + if (!pf_status.running || +#ifdef __FreeBSD__ + (m->m_flags & M_SKIP_FIREWALL)) { + PF_UNLOCK(); +#else + (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) { +#endif + return (PF_PASS); } - if (pd.pf_mtag->flags & PF_TAG_GENERATED) - return (PF_PASS); +#ifdef __FreeBSD__ + /* XXX_IMPORT: later */ +#else if (ifp->if_type == IFT_CARP && ifp->if_carpdev) ifp = ifp->if_carpdev; +#endif - kif = (struct pfi_kif *)ifp->if_pf_kif; + kif = pfi_index2kif[ifp->if_index]; if (kif == NULL) { +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif DPFPRINTF(PF_DEBUG_URGENT, ("pf_test: kif == NULL, if_xname %s\n", ifp->if_xname)); return (PF_DROP); } - if (kif->pfik_flags & PFI_IFLAG_SKIP) + if (kif->pfik_flags & PFI_IFLAG_SKIP) { +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif return (PF_PASS); + } +#ifdef __FreeBSD__ + M_ASSERTPKTHDR(m); +#else #ifdef DIAGNOSTIC if ((m->m_flags & M_PKTHDR) == 0) panic("non-M_PKTHDR is passed to pf_test"); #endif /* DIAGNOSTIC */ +#endif /* __FreeBSD__ */ + memset(&pd, 0, sizeof(pd)); if (m->m_pkthdr.len < (int)sizeof(*h)) { action = PF_DROP; REASON_SET(&reason, PFRES_SHORT); @@ -6003,7 +6509,6 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, } if (dir == PF_IN && pf_check_proto_cksum(m, off, ntohs(h->ip_len) - off, IPPROTO_TCP, AF_INET)) { - REASON_SET(&reason, PFRES_PROTCKSUM); action = PF_DROP; goto done; } @@ -6023,8 +6528,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, a = s->anchor.ptr; log = s->log; } else if (s == NULL) +#ifdef __FreeBSD__ + action = pf_test_tcp(&r, &s, dir, kif, + m, off, h, &pd, &a, &ruleset, NULL, inp); +#else action = pf_test_tcp(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ipintrq); +#endif break; } @@ -6040,14 +6550,12 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m, off, ntohs(h->ip_len) - off, IPPROTO_UDP, AF_INET)) { action = PF_DROP; - REASON_SET(&reason, PFRES_PROTCKSUM); goto done; } if (uh.uh_dport == 0 || ntohs(uh.uh_ulen) > m->m_pkthdr.len - off || ntohs(uh.uh_ulen) < sizeof(struct udphdr)) { action = PF_DROP; - REASON_SET(&reason, PFRES_SHORT); goto done; } action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd); @@ -6059,8 +6567,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, a = s->anchor.ptr; log = s->log; } else if (s == NULL) +#ifdef __FreeBSD__ + action = pf_test_udp(&r, &s, dir, kif, + m, off, h, &pd, &a, &ruleset, NULL, inp); +#else action = pf_test_udp(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ipintrq); +#endif break; } @@ -6076,7 +6589,6 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, if (dir == PF_IN && pf_check_proto_cksum(m, off, ntohs(h->ip_len) - off, IPPROTO_ICMP, AF_INET)) { action = PF_DROP; - REASON_SET(&reason, PFRES_PROTCKSUM); goto done; } action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd, @@ -6089,8 +6601,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, a = s->anchor.ptr; log = s->log; } else if (s == NULL) +#ifdef __FreeBSD__ + action = pf_test_icmp(&r, &s, dir, kif, + m, off, h, &pd, &a, &ruleset, NULL); +#else action = pf_test_icmp(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ipintrq); +#endif break; } @@ -6104,8 +6621,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, a = s->anchor.ptr; log = s->log; } else if (s == NULL) +#ifdef __FreeBSD__ + action = pf_test_other(&r, &s, dir, kif, m, off, h, + &pd, &a, &ruleset, NULL); +#else action = pf_test_other(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ipintrq); +#endif break; } @@ -6119,18 +6641,26 @@ done: ("pf: dropping packet with ip options\n")); } - if ((s && s->tag) || r->rtableid) - pf_tag_packet(m, pd.pf_mtag, s ? s->tag : 0, r->rtableid); + if (s && s->tag) + pf_tag_packet(m, pf_get_tag(m), s->tag); #ifdef ALTQ if (action == PF_PASS && r->qid) { - if (pqid || (pd.tos & IPTOS_LOWDELAY)) - pd.pf_mtag->qid = r->pqid; - else - pd.pf_mtag->qid = r->qid; - /* add hints for ecn */ - pd.pf_mtag->af = AF_INET; - pd.pf_mtag->hdr = h; + struct m_tag *mtag; + struct altq_tag *atag; + + mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT); + if (mtag != NULL) { + atag = (struct altq_tag *)(mtag + 1); + if (pqid || pd.tos == IPTOS_LOWDELAY) + atag->qid = r->pqid; + else + atag->qid = r->qid; + /* add hints for ecn */ + atag->af = AF_INET; + atag->hdr = h; + m_tag_prepend(m, mtag); + } } #endif /* ALTQ */ @@ -6143,48 +6673,41 @@ done: pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL && (s->nat_rule.ptr->action == PF_RDR || s->nat_rule.ptr->action == PF_BINAT) && - (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) - pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST; - - if (log) { - struct pf_rule *lr; - - if (s != NULL && s->nat_rule.ptr != NULL && - s->nat_rule.ptr->log & PF_LOG_ALL) - lr = s->nat_rule.ptr; - else - lr = r; - PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, lr, a, ruleset, - &pd); + (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET && + pf_add_mbuf_tag(m, PACKET_TAG_PF_TRANSLATE_LOCALHOST)) { + action = PF_DROP; + REASON_SET(&reason, PFRES_MEMORY); } + if (log) + PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, r, a, ruleset); + kif->pfik_bytes[0][dir == PF_OUT][action != PF_PASS] += pd.tot_len; kif->pfik_packets[0][dir == PF_OUT][action != PF_PASS]++; if (action == PF_PASS || r->action == PF_DROP) { - dirndx = (dir == PF_OUT); - r->packets[dirndx]++; - r->bytes[dirndx] += pd.tot_len; + r->packets++; + r->bytes += pd.tot_len; if (a != NULL) { - a->packets[dirndx]++; - a->bytes[dirndx] += pd.tot_len; + a->packets++; + a->bytes += pd.tot_len; } if (s != NULL) { + dirndx = (dir == s->direction) ? 0 : 1; + s->packets[dirndx]++; + s->bytes[dirndx] += pd.tot_len; if (s->nat_rule.ptr != NULL) { - s->nat_rule.ptr->packets[dirndx]++; - s->nat_rule.ptr->bytes[dirndx] += pd.tot_len; + s->nat_rule.ptr->packets++; + s->nat_rule.ptr->bytes += pd.tot_len; } if (s->src_node != NULL) { - s->src_node->packets[dirndx]++; - s->src_node->bytes[dirndx] += pd.tot_len; + s->src_node->packets++; + s->src_node->bytes += pd.tot_len; } if (s->nat_src_node != NULL) { - s->nat_src_node->packets[dirndx]++; - s->nat_src_node->bytes[dirndx] += pd.tot_len; + s->nat_src_node->packets++; + s->nat_src_node->bytes += pd.tot_len; } - dirndx = (dir == s->direction) ? 0 : 1; - s->packets[dirndx]++; - s->bytes[dirndx] += pd.tot_len; } tr = r; nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule; @@ -6229,7 +6752,11 @@ done: action = PF_PASS; } else if (r->rt) /* pf_route can free the mbuf causing *m0 to become NULL */ - pf_route(m0, r, dir, ifp, s, &pd); + pf_route(m0, r, dir, ifp, s); + +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif return (action); } @@ -6237,48 +6764,71 @@ done: #ifdef INET6 int +#ifdef __FreeBSD__ +pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, + struct ether_header *eh, struct inpcb *inp) +#else pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct ether_header *eh) +#endif { struct pfi_kif *kif; u_short action, reason = 0, log = 0; - struct mbuf *m = *m0, *n = NULL; - struct ip6_hdr *h; + struct mbuf *m = *m0; + struct ip6_hdr *h = NULL; /* make the compiler happy */ struct pf_rule *a = NULL, *r = &pf_default_rule, *tr, *nr; struct pf_state *s = NULL; struct pf_ruleset *ruleset = NULL; struct pf_pdesc pd; - int off, terminal = 0, dirndx; + int off, terminal = 0, dirndx, rh_cnt = 0; - if (!pf_status.running) - return (PF_PASS); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif - memset(&pd, 0, sizeof(pd)); - if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) { - DPFPRINTF(PF_DEBUG_URGENT, - ("pf_test6: pf_get_mtag returned NULL\n")); - return (PF_DROP); - } - if (pd.pf_mtag->flags & PF_TAG_GENERATED) + if (!pf_status.running || +#ifdef __FreeBSD__ + (m->m_flags & M_SKIP_FIREWALL)) { + PF_UNLOCK(); +#else + (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) { +#endif return (PF_PASS); + } +#ifdef __FreeBSD__ + /* XXX_IMPORT: later */ +#else if (ifp->if_type == IFT_CARP && ifp->if_carpdev) ifp = ifp->if_carpdev; +#endif - kif = (struct pfi_kif *)ifp->if_pf_kif; + kif = pfi_index2kif[ifp->if_index]; if (kif == NULL) { +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif DPFPRINTF(PF_DEBUG_URGENT, ("pf_test6: kif == NULL, if_xname %s\n", ifp->if_xname)); return (PF_DROP); } - if (kif->pfik_flags & PFI_IFLAG_SKIP) + if (kif->pfik_flags & PFI_IFLAG_SKIP) { +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif return (PF_PASS); + } +#ifdef __FreeBSD__ + M_ASSERTPKTHDR(m); +#else #ifdef DIAGNOSTIC if ((m->m_flags & M_PKTHDR) == 0) panic("non-M_PKTHDR is passed to pf_test6"); #endif /* DIAGNOSTIC */ +#endif + memset(&pd, 0, sizeof(pd)); if (m->m_pkthdr.len < (int)sizeof(*h)) { action = PF_DROP; REASON_SET(&reason, PFRES_SHORT); @@ -6327,62 +6877,33 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, goto done; case IPPROTO_ROUTING: { struct ip6_rthdr rthdr; - struct ip6_rthdr0 rthdr0; - struct in6_addr finaldst; - struct ip6_hdr *ip6; + if (rh_cnt++) { + DPFPRINTF(PF_DEBUG_MISC, + ("pf: IPv6 more than one rthdr\n")); + action = PF_DROP; + REASON_SET(&reason, PFRES_IPOPTIONS); + log = 1; + goto done; + } if (!pf_pull_hdr(m, off, &rthdr, sizeof(rthdr), NULL, &reason, pd.af)) { DPFPRINTF(PF_DEBUG_MISC, ("pf: IPv6 short rthdr\n")); action = PF_DROP; + REASON_SET(&reason, PFRES_SHORT); log = 1; goto done; } if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) { - if (!pf_pull_hdr(m, off, &rthdr0, - sizeof(rthdr0), NULL, &reason, pd.af)) { - DPFPRINTF(PF_DEBUG_MISC, - ("pf: IPv6 short rthdr0\n")); - action = PF_DROP; - log = 1; - goto done; - } - if (rthdr0.ip6r0_segleft != 0) { - if (!pf_pull_hdr(m, off + - sizeof(rthdr0) + - rthdr0.ip6r0_len * 8 - - sizeof(finaldst), &finaldst, - sizeof(finaldst), NULL, - &reason, pd.af)) { - DPFPRINTF(PF_DEBUG_MISC, - ("pf: IPv6 short rthdr0\n")); - action = PF_DROP; - log = 1; - goto done; - } - - n = m_copym(m, 0, M_COPYALL, M_DONTWAIT); - if (!n) { - DPFPRINTF(PF_DEBUG_MISC, - ("pf: mbuf shortage\n")); - action = PF_DROP; - log = 1; - goto done; - } - n = m_pullup(n, sizeof(struct ip6_hdr)); - if (!n) { - DPFPRINTF(PF_DEBUG_MISC, - ("pf: mbuf shortage\n")); - action = PF_DROP; - log = 1; - goto done; - } - ip6 = mtod(n, struct ip6_hdr *); - ip6->ip6_dst = finaldst; - } + DPFPRINTF(PF_DEBUG_MISC, + ("pf: IPv6 rthdr0\n")); + action = PF_DROP; + REASON_SET(&reason, PFRES_IPOPTIONS); + log = 1; + goto done; } - /* FALLTHROUGH */ + /* fallthrough */ } case IPPROTO_AH: case IPPROTO_HOPOPTS: @@ -6412,10 +6933,6 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, } } while (!terminal); - /* if there's no routing header, use unmodified mbuf for checksumming */ - if (!n) - n = m; - switch (pd.proto) { case IPPROTO_TCP: { @@ -6427,7 +6944,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, log = action != PF_PASS; goto done; } - if (dir == PF_IN && pf_check_proto_cksum(n, off, + if (dir == PF_IN && pf_check_proto_cksum(m, off, ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)), IPPROTO_TCP, AF_INET6)) { action = PF_DROP; @@ -6448,8 +6965,13 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, a = s->anchor.ptr; log = s->log; } else if (s == NULL) +#ifdef __FreeBSD__ + action = pf_test_tcp(&r, &s, dir, kif, + m, off, h, &pd, &a, &ruleset, NULL, inp); +#else action = pf_test_tcp(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ip6intrq); +#endif break; } @@ -6462,7 +6984,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, log = action != PF_PASS; goto done; } - if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(n, + if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m, off, ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)), IPPROTO_UDP, AF_INET6)) { action = PF_DROP; @@ -6473,7 +6995,6 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, ntohs(uh.uh_ulen) > m->m_pkthdr.len - off || ntohs(uh.uh_ulen) < sizeof(struct udphdr)) { action = PF_DROP; - REASON_SET(&reason, PFRES_SHORT); goto done; } action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd); @@ -6485,8 +7006,13 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, a = s->anchor.ptr; log = s->log; } else if (s == NULL) +#ifdef __FreeBSD__ + action = pf_test_udp(&r, &s, dir, kif, + m, off, h, &pd, &a, &ruleset, NULL, inp); +#else action = pf_test_udp(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ip6intrq); +#endif break; } @@ -6499,7 +7025,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, log = action != PF_PASS; goto done; } - if (dir == PF_IN && pf_check_proto_cksum(n, off, + if (dir == PF_IN && pf_check_proto_cksum(m, off, ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)), IPPROTO_ICMPV6, AF_INET6)) { action = PF_DROP; @@ -6516,8 +7042,13 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, a = s->anchor.ptr; log = s->log; } else if (s == NULL) +#ifdef __FreeBSD__ + action = pf_test_icmp(&r, &s, dir, kif, + m, off, h, &pd, &a, &ruleset, NULL); +#else action = pf_test_icmp(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ip6intrq); +#endif break; } @@ -6531,31 +7062,47 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, a = s->anchor.ptr; log = s->log; } else if (s == NULL) +#ifdef __FreeBSD__ + action = pf_test_other(&r, &s, dir, kif, m, off, h, + &pd, &a, &ruleset, NULL); +#else action = pf_test_other(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ip6intrq); +#endif break; } done: - if (n != m) { - m_freem(n); - n = NULL; + /* handle dangerous IPv6 extension headers. */ + if (action == PF_PASS && rh_cnt && + !((s && s->allow_opts) || r->allow_opts)) { + action = PF_DROP; + REASON_SET(&reason, PFRES_IPOPTIONS); + log = 1; + DPFPRINTF(PF_DEBUG_MISC, + ("pf: dropping packet with dangerous v6 headers\n")); } - /* XXX handle IPv6 options, if not allowed. not implemented. */ - - if ((s && s->tag) || r->rtableid) - pf_tag_packet(m, pd.pf_mtag, s ? s->tag : 0, r->rtableid); + if (s && s->tag) + pf_tag_packet(m, pf_get_tag(m), s->tag); #ifdef ALTQ if (action == PF_PASS && r->qid) { - if (pd.tos & IPTOS_LOWDELAY) - pd.pf_mtag->qid = r->pqid; - else - pd.pf_mtag->qid = r->qid; - /* add hints for ecn */ - pd.pf_mtag->af = AF_INET6; - pd.pf_mtag->hdr = h; + struct m_tag *mtag; + struct altq_tag *atag; + + mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT); + if (mtag != NULL) { + atag = (struct altq_tag *)(mtag + 1); + if (pd.tos == IPTOS_LOWDELAY) + atag->qid = r->pqid; + else + atag->qid = r->qid; + /* add hints for ecn */ + atag->af = AF_INET6; + atag->hdr = h; + m_tag_prepend(m, mtag); + } } #endif /* ALTQ */ @@ -6563,48 +7110,41 @@ done: pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL && (s->nat_rule.ptr->action == PF_RDR || s->nat_rule.ptr->action == PF_BINAT) && - IN6_IS_ADDR_LOOPBACK(&pd.dst->v6)) - pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST; - - if (log) { - struct pf_rule *lr; - - if (s != NULL && s->nat_rule.ptr != NULL && - s->nat_rule.ptr->log & PF_LOG_ALL) - lr = s->nat_rule.ptr; - else - lr = r; - PFLOG_PACKET(kif, h, m, AF_INET6, dir, reason, lr, a, ruleset, - &pd); + IN6_IS_ADDR_LOOPBACK(&pd.dst->v6) && + pf_add_mbuf_tag(m, PACKET_TAG_PF_TRANSLATE_LOCALHOST)) { + action = PF_DROP; + REASON_SET(&reason, PFRES_MEMORY); } + if (log) + PFLOG_PACKET(kif, h, m, AF_INET6, dir, reason, r, a, ruleset); + kif->pfik_bytes[1][dir == PF_OUT][action != PF_PASS] += pd.tot_len; kif->pfik_packets[1][dir == PF_OUT][action != PF_PASS]++; if (action == PF_PASS || r->action == PF_DROP) { - dirndx = (dir == PF_OUT); - r->packets[dirndx]++; - r->bytes[dirndx] += pd.tot_len; + r->packets++; + r->bytes += pd.tot_len; if (a != NULL) { - a->packets[dirndx]++; - a->bytes[dirndx] += pd.tot_len; + a->packets++; + a->bytes += pd.tot_len; } if (s != NULL) { + dirndx = (dir == s->direction) ? 0 : 1; + s->packets[dirndx]++; + s->bytes[dirndx] += pd.tot_len; if (s->nat_rule.ptr != NULL) { - s->nat_rule.ptr->packets[dirndx]++; - s->nat_rule.ptr->bytes[dirndx] += pd.tot_len; + s->nat_rule.ptr->packets++; + s->nat_rule.ptr->bytes += pd.tot_len; } if (s->src_node != NULL) { - s->src_node->packets[dirndx]++; - s->src_node->bytes[dirndx] += pd.tot_len; + s->src_node->packets++; + s->src_node->bytes += pd.tot_len; } if (s->nat_src_node != NULL) { - s->nat_src_node->packets[dirndx]++; - s->nat_src_node->bytes[dirndx] += pd.tot_len; + s->nat_src_node->packets++; + s->nat_src_node->bytes += pd.tot_len; } - dirndx = (dir == s->direction) ? 0 : 1; - s->packets[dirndx]++; - s->bytes[dirndx] += pd.tot_len; } tr = r; nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule; @@ -6649,8 +7189,11 @@ done: action = PF_PASS; } else if (r->rt) /* pf_route6 can free the mbuf causing *m0 to become NULL */ - pf_route6(m0, r, dir, ifp, s, &pd); + pf_route6(m0, r, dir, ifp, s); +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif return (action); } #endif /* INET6 */ @@ -6658,8 +7201,13 @@ done: int pf_check_congestion(struct ifqueue *ifq) { +#ifdef __FreeBSD__ + /* XXX_IMPORT: later */ + return (0); +#else if (ifq->ifq_congestion) return (1); else return (0); +#endif } diff --git a/sys/contrib/pf/net/pf_if.c b/sys/contrib/pf/net/pf_if.c index 6a15a89..8e35070 100644 --- a/sys/contrib/pf/net/pf_if.c +++ b/sys/contrib/pf/net/pf_if.c @@ -1,8 +1,7 @@ -/* $OpenBSD: pf_if.c,v 1.46 2006/12/13 09:01:59 itojun Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: pf_if.c,v 1.23 2004/12/22 17:17:55 dhartmei Exp $ */ /* - * Copyright 2005 Henning Brauer <henning@openbsd.org> - * Copyright 2005 Ryan McBride <mcbride@openbsd.org> * Copyright (c) 2001 Daniel Hartmeier * Copyright (c) 2003 Cedric Berger * All rights reserved. @@ -32,14 +31,24 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#if defined(__FreeBSD__) +#include "opt_inet.h" +#include "opt_inet6.h" +#endif + #include <sys/param.h> #include <sys/systm.h> +#ifdef __FreeBSD__ +#include <sys/malloc.h> +#endif #include <sys/mbuf.h> #include <sys/filio.h> #include <sys/socket.h> #include <sys/socketvar.h> #include <sys/kernel.h> +#ifndef __FreeBSD__ #include <sys/device.h> +#endif #include <sys/time.h> #include <net/if.h> @@ -57,273 +66,440 @@ #include <netinet/ip6.h> #endif /* INET6 */ -struct pfi_kif *pfi_all = NULL; +#define ACCEPT_FLAGS(oklist) \ + do { \ + if ((flags & ~(oklist)) & \ + PFI_FLAG_ALLMASK) \ + return (EINVAL); \ + } while (0) + +#define senderr(e) do { rv = (e); goto _bad; } while (0) + +struct pfi_kif **pfi_index2kif; +struct pfi_kif *pfi_self, *pfi_dummy; +int pfi_indexlim; +struct pfi_ifhead pfi_ifs; struct pfi_statehead pfi_statehead; +int pfi_ifcnt; +#ifdef __FreeBSD__ +uma_zone_t pfi_addr_pl; +#else struct pool pfi_addr_pl; -struct pfi_ifhead pfi_ifs; +#endif long pfi_update = 1; struct pfr_addr *pfi_buffer; int pfi_buffer_cnt; int pfi_buffer_max; +#ifdef __FreeBSD__ +eventhandler_tag pfi_clone_cookie = NULL; +eventhandler_tag pfi_attach_cookie = NULL; +eventhandler_tag pfi_detach_cookie = NULL; +#endif -void pfi_kif_update(struct pfi_kif *); -void pfi_dynaddr_update(struct pfi_dynaddr *dyn); +void pfi_dynaddr_update(void *); +void pfi_kifaddr_update(void *); void pfi_table_update(struct pfr_ktable *, struct pfi_kif *, int, int); -void pfi_kifaddr_update(void *); void pfi_instance_add(struct ifnet *, int, int); void pfi_address_add(struct sockaddr *, int, int); int pfi_if_compare(struct pfi_kif *, struct pfi_kif *); -int pfi_skip_if(const char *, struct pfi_kif *); +struct pfi_kif *pfi_if_create(const char *, struct pfi_kif *, int); +void pfi_copy_group(char *, const char *, int); +void pfi_newgroup(const char *, int); +int pfi_skip_if(const char *, struct pfi_kif *, int); int pfi_unmask(void *); +void pfi_dohooks(struct pfi_kif *); +#ifdef __FreeBSD__ +void pfi_kifaddr_update_event(void *, struct ifnet *); +void pfi_attach_clone_event(void * __unused, struct if_clone *); +void pfi_attach_ifnet_event(void * __unused, struct ifnet *); +void pfi_detach_ifnet_event(void * __unused, struct ifnet *); +#endif RB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); #define PFI_BUFFER_MAX 0x10000 +#ifdef __FreeBSD__ +MALLOC_DEFINE(PFI_MTYPE, "pf_if", "pf interface table"); +#else #define PFI_MTYPE M_IFADDR +#endif void pfi_initialize(void) { - if (pfi_all != NULL) /* already initialized */ +#ifdef __FreeBSD__ + struct ifnet *ifp; +#endif + + if (pfi_self != NULL) /* already initialized */ return; TAILQ_INIT(&pfi_statehead); +#ifndef __FreeBSD__ pool_init(&pfi_addr_pl, sizeof(struct pfi_dynaddr), 0, 0, 0, "pfiaddrpl", &pool_allocator_nointr); +#endif pfi_buffer_max = 64; pfi_buffer = malloc(pfi_buffer_max * sizeof(*pfi_buffer), PFI_MTYPE, M_WAITOK); - - if ((pfi_all = pfi_kif_get(IFG_ALL)) == NULL) - panic("pfi_kif_get for pfi_all failed"); + pfi_self = pfi_if_create("self", NULL, PFI_IFLAG_GROUP); +#ifdef __FreeBSD__ + /* XXX_IMPORT */ + PF_LOCK(); + IFNET_RLOCK(); + TAILQ_FOREACH(ifp, &ifnet, if_link) { + IFNET_RUNLOCK(); + pfi_attach_ifnet(ifp); + IFNET_RLOCK(); + } + IFNET_RUNLOCK(); + PF_UNLOCK(); + pfi_dummy = pfi_if_create("notyet", pfi_self, + PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC); + pfi_attach_cookie = EVENTHANDLER_REGISTER(ifnet_arrival_event, + pfi_attach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY); + pfi_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event, + pfi_detach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY); + pfi_clone_cookie = EVENTHANDLER_REGISTER(if_clone_event, + pfi_attach_clone_event, NULL, EVENTHANDLER_PRI_ANY); +#endif } -struct pfi_kif * -pfi_kif_get(const char *kif_name) +#ifdef __FreeBSD__ +void +pfi_cleanup(void) { - struct pfi_kif *kif; - struct pfi_kif_cmp s; - - bzero(&s, sizeof(s)); - strlcpy(s.pfik_name, kif_name, sizeof(s.pfik_name)); - if ((kif = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&s)) != NULL) - return (kif); - - /* create new one */ - if ((kif = malloc(sizeof(*kif), PFI_MTYPE, M_DONTWAIT)) == NULL) - return (NULL); + struct pfi_kif *p, key; + struct ifnet *ifp; + + PF_ASSERT(MA_OWNED); + + PF_UNLOCK(); + EVENTHANDLER_DEREGISTER(ifnet_arrival_event, pfi_attach_cookie); + EVENTHANDLER_DEREGISTER(ifnet_departure_event, pfi_detach_cookie); + EVENTHANDLER_DEREGISTER(if_clone_event, pfi_clone_cookie); + PF_LOCK(); + + IFNET_RLOCK(); + /* release PFI_IFLAG_INSTANCE */ + TAILQ_FOREACH(ifp, &ifnet, if_link) { + strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name)); + p = RB_FIND(pfi_ifhead, &pfi_ifs, &key); + if (p != NULL) { + IFNET_RUNLOCK(); + pfi_detach_ifnet(ifp); + IFNET_RLOCK(); + } + } + IFNET_RUNLOCK(); - bzero(kif, sizeof(*kif)); - strlcpy(kif->pfik_name, kif_name, sizeof(kif->pfik_name)); - kif->pfik_tzero = time_second; - TAILQ_INIT(&kif->pfik_dynaddrs); + /* XXX clear all other interface group */ + while ((p = RB_MIN(pfi_ifhead, &pfi_ifs))) { + RB_REMOVE(pfi_ifhead, &pfi_ifs, p); - RB_INSERT(pfi_ifhead, &pfi_ifs, kif); - return (kif); + free(p->pfik_ah_head, PFI_MTYPE); + free(p, PFI_MTYPE); + } + free(pfi_index2kif, PFI_MTYPE); + free(pfi_buffer, PFI_MTYPE); + pfi_index2kif = NULL; + pfi_buffer = NULL; + pfi_self = NULL; } +/* + * Wrapper functions for FreeBSD eventhandler + */ void -pfi_kif_ref(struct pfi_kif *kif, enum pfi_kif_refs what) +pfi_kifaddr_update_event(void *arg, struct ifnet *ifp) { - switch (what) { - case PFI_KIF_REF_RULE: - kif->pfik_rules++; - break; - case PFI_KIF_REF_STATE: - if (!kif->pfik_states++) - TAILQ_INSERT_TAIL(&pfi_statehead, kif, pfik_w_states); - break; - default: - panic("pfi_kif_ref with unknown type"); - } + struct pfi_kif *p = arg; + + PF_LOCK(); + /* + * Check to see if it is 'our' interface as we do not have per + * interface hooks and thus get an update for every interface. + */ + if (p && p->pfik_ifp == ifp) + pfi_kifaddr_update(p); + PF_UNLOCK(); } void -pfi_kif_unref(struct pfi_kif *kif, enum pfi_kif_refs what) +pfi_attach_clone_event(void *arg __unused, struct if_clone *ifc) { - if (kif == NULL) - return; - - switch (what) { - case PFI_KIF_REF_NONE: - break; - case PFI_KIF_REF_RULE: - if (kif->pfik_rules <= 0) { - printf("pfi_kif_unref: rules refcount <= 0\n"); - return; - } - kif->pfik_rules--; - break; - case PFI_KIF_REF_STATE: - if (kif->pfik_states <= 0) { - printf("pfi_kif_unref: state refcount <= 0\n"); - return; - } - if (!--kif->pfik_states) - TAILQ_REMOVE(&pfi_statehead, kif, pfik_w_states); - break; - default: - panic("pfi_kif_unref with unknown type"); - } - - if (kif->pfik_ifp != NULL || kif->pfik_group != NULL || kif == pfi_all) - return; - - if (kif->pfik_rules || kif->pfik_states) - return; - - RB_REMOVE(pfi_ifhead, &pfi_ifs, kif); - free(kif, PFI_MTYPE); + PF_LOCK(); + pfi_attach_clone(ifc); + PF_UNLOCK(); } -int -pfi_kif_match(struct pfi_kif *rule_kif, struct pfi_kif *packet_kif) +void +pfi_attach_ifnet_event(void *arg __unused, struct ifnet *ifp) { - struct ifg_list *p; - - if (rule_kif == NULL || rule_kif == packet_kif) - return (1); + PF_LOCK(); + pfi_attach_ifnet(ifp); + PF_UNLOCK(); +} - if (rule_kif->pfik_group != NULL) - TAILQ_FOREACH(p, &packet_kif->pfik_ifp->if_groups, ifgl_next) - if (p->ifgl_group == rule_kif->pfik_group) - return (1); +void +pfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp) +{ + PF_LOCK(); + pfi_detach_ifnet(ifp); + PF_UNLOCK(); +} +#endif /* __FreeBSD__ */ - return (0); +void +pfi_attach_clone(struct if_clone *ifc) +{ + pfi_initialize(); + pfi_newgroup(ifc->ifc_name, PFI_IFLAG_CLONABLE); } void pfi_attach_ifnet(struct ifnet *ifp) { - struct pfi_kif *kif; - int s; + struct pfi_kif *p, *q, key; + int s; +#ifdef __FreeBSD__ + int realname; +#endif pfi_initialize(); s = splsoftnet(); pfi_update++; - if ((kif = pfi_kif_get(ifp->if_xname)) == NULL) - panic("pfi_kif_get failed"); - - kif->pfik_ifp = ifp; - ifp->if_pf_kif = (caddr_t)kif; - - if ((kif->pfik_ah_cookie = hook_establish(ifp->if_addrhooks, 1, - pfi_kifaddr_update, kif)) == NULL) - panic("pfi_attach_ifnet: cannot allocate '%s' address hook", - ifp->if_xname); - - pfi_kif_update(kif); + if (ifp->if_index >= pfi_indexlim) { + /* + * grow pfi_index2kif, similar to ifindex2ifnet code in if.c + */ + size_t m, n, oldlim; + struct pfi_kif **mp, **np; + + oldlim = pfi_indexlim; + if (pfi_indexlim == 0) + pfi_indexlim = 64; + while (ifp->if_index >= pfi_indexlim) + pfi_indexlim <<= 1; + + m = oldlim * sizeof(struct pfi_kif *); + mp = pfi_index2kif; + n = pfi_indexlim * sizeof(struct pfi_kif *); +#ifdef __FreeBSD__ + np = malloc(n, PFI_MTYPE, M_NOWAIT); +#else + np = malloc(n, PFI_MTYPE, M_DONTWAIT); +#endif + if (np == NULL) + panic("pfi_attach_ifnet: " + "cannot allocate translation table"); + bzero(np, n); + if (mp != NULL) + bcopy(mp, np, m); + pfi_index2kif = np; + if (mp != NULL) + free(mp, PFI_MTYPE); + } + strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name)); + p = RB_FIND(pfi_ifhead, &pfi_ifs, &key); +#ifdef __FreeBSD__ + /* some additional trickery for placeholders */ + if ((p == NULL) || (p->pfik_parent == pfi_dummy)) { + /* are we looking at a renamed instance or not? */ + pfi_copy_group(key.pfik_name, ifp->if_xname, + sizeof(key.pfik_name)); + realname = (strncmp(key.pfik_name, ifp->if_dname, + sizeof(key.pfik_name)) == 0); + /* add group */ + /* we can change if_xname, hence use if_dname as group id */ + pfi_copy_group(key.pfik_name, ifp->if_dname, + sizeof(key.pfik_name)); + q = RB_FIND(pfi_ifhead, &pfi_ifs, &key); + if (q == NULL) + q = pfi_if_create(key.pfik_name, pfi_self, + PFI_IFLAG_GROUP|PFI_IFLAG_DYNAMIC); + else if (q->pfik_parent == pfi_dummy) { + q->pfik_parent = pfi_self; + q->pfik_flags = (PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC); + } + if (q == NULL) + panic("pfi_attach_ifnet: " + "cannot allocate '%s' group", key.pfik_name); + + /* add/modify interface */ + if (p == NULL) + p = pfi_if_create(ifp->if_xname, q, PFI_IFLAG_INSTANCE | + (realname?0:PFI_IFLAG_PLACEHOLDER)); + else { + /* remove from the dummy group */ + /* XXX: copy stats? We should not have any!!! */ + pfi_dummy->pfik_delcnt++; + TAILQ_REMOVE(&pfi_dummy->pfik_grouphead, p, + pfik_instances); + /* move to the right group */ + p->pfik_parent = q; + q->pfik_addcnt++; + TAILQ_INSERT_TAIL(&q->pfik_grouphead, p, + pfik_instances); + if (realname) + p->pfik_flags &= ~PFI_IFLAG_PLACEHOLDER; + p->pfik_flags |= PFI_IFLAG_INSTANCE; + } + if (p == NULL) + panic("pfi_attach_ifnet: " + "cannot allocate '%s' interface", ifp->if_xname); +#else + if (p == NULL) { + /* add group */ + pfi_copy_group(key.pfik_name, ifp->if_xname, + sizeof(key.pfik_name)); + q = RB_FIND(pfi_ifhead, &pfi_ifs, &key); + if (q == NULL) + q = pfi_if_create(key.pfik_name, pfi_self, PFI_IFLAG_GROUP); + else if (q->pfik_parent == pfi_dummy) { + q->pfik_parent = pfi_self; + q->pfik_flags = (PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC); + } + if (q == NULL) + panic("pfi_attach_ifnet: " + "cannot allocate '%s' group", key.pfik_name); + + /* add interface */ + p = pfi_if_create(ifp->if_xname, q, PFI_IFLAG_INSTANCE); + if (p == NULL) + panic("pfi_attach_ifnet: " + "cannot allocate '%s' interface", ifp->if_xname); +#endif + } else + q = p->pfik_parent; + p->pfik_ifp = ifp; + p->pfik_flags |= PFI_IFLAG_ATTACHED; +#ifdef __FreeBSD__ + PF_UNLOCK(); + p->pfik_ah_cookie = EVENTHANDLER_REGISTER(ifaddr_event, + pfi_kifaddr_update_event, p, EVENTHANDLER_PRI_ANY); + PF_LOCK(); +#else + p->pfik_ah_cookie = + hook_establish(ifp->if_addrhooks, 1, pfi_kifaddr_update, p); +#endif + pfi_index2kif[ifp->if_index] = p; + pfi_dohooks(p); splx(s); } void pfi_detach_ifnet(struct ifnet *ifp) { - int s; - struct pfi_kif *kif; + struct pfi_kif *p, *q, key; + int s; - if ((kif = (struct pfi_kif *)ifp->if_pf_kif) == NULL) - return; + strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name)); s = splsoftnet(); pfi_update++; - hook_disestablish(ifp->if_addrhooks, kif->pfik_ah_cookie); - pfi_kif_update(kif); - - kif->pfik_ifp = NULL; - ifp->if_pf_kif = NULL; - pfi_kif_unref(kif, PFI_KIF_REF_NONE); + p = RB_FIND(pfi_ifhead, &pfi_ifs, &key); + if (p == NULL) { + printf("pfi_detach_ifnet: cannot find %s", ifp->if_xname); + splx(s); + return; + } +#ifdef __FreeBSD__ + PF_UNLOCK(); + EVENTHANDLER_DEREGISTER(ifaddr_event, p->pfik_ah_cookie); + PF_LOCK(); +#else + hook_disestablish(p->pfik_ifp->if_addrhooks, p->pfik_ah_cookie); +#endif + q = p->pfik_parent; + p->pfik_ifp = NULL; + p->pfik_flags &= ~PFI_IFLAG_ATTACHED; + pfi_index2kif[ifp->if_index] = NULL; + pfi_dohooks(p); + pfi_maybe_destroy(p); splx(s); } -void -pfi_attach_ifgroup(struct ifg_group *ifg) +struct pfi_kif * +pfi_lookup_create(const char *name) { - struct pfi_kif *kif; + struct pfi_kif *p, *q, key; int s; - pfi_initialize(); s = splsoftnet(); - pfi_update++; - if ((kif = pfi_kif_get(ifg->ifg_group)) == NULL) - panic("pfi_kif_get failed"); + p = pfi_lookup_if(name); + if (p == NULL) { + pfi_copy_group(key.pfik_name, name, sizeof(key.pfik_name)); + q = pfi_lookup_if(key.pfik_name); +#ifdef __FreeBSD__ + /* XXX_IMPORT */ + if ((q != NULL) && (q->pfik_parent != pfi_dummy)) + p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE); + else { + if (pfi_dummy == NULL) + panic("no 'notyet' dummy group"); + p = pfi_if_create(name, pfi_dummy, + PFI_IFLAG_PLACEHOLDER); + } +#else + if (q == NULL) { + pfi_newgroup(key.pfik_name, PFI_IFLAG_DYNAMIC); + q = pfi_lookup_if(key.pfik_name); + } + p = pfi_lookup_if(name); + if (p == NULL && q != NULL) + p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE); +#endif + } + splx(s); + return (p); +} - kif->pfik_group = ifg; - ifg->ifg_pf_kif = (caddr_t)kif; +struct pfi_kif * +pfi_attach_rule(const char *name) +{ + struct pfi_kif *p; - splx(s); + p = pfi_lookup_create(name); + if (p != NULL) + p->pfik_rules++; + return (p); } void -pfi_detach_ifgroup(struct ifg_group *ifg) +pfi_detach_rule(struct pfi_kif *p) { - int s; - struct pfi_kif *kif; - - if ((kif = (struct pfi_kif *)ifg->ifg_pf_kif) == NULL) + if (p == NULL) return; - - s = splsoftnet(); - pfi_update++; - - kif->pfik_group = NULL; - ifg->ifg_pf_kif = NULL; - pfi_kif_unref(kif, PFI_KIF_REF_NONE); - splx(s); + if (p->pfik_rules > 0) + p->pfik_rules--; + else + printf("pfi_detach_rule: reference count at 0\n"); + pfi_maybe_destroy(p); } void -pfi_group_change(const char *group) +pfi_attach_state(struct pfi_kif *p) { - struct pfi_kif *kif; - int s; - - s = splsoftnet(); - pfi_update++; - if ((kif = pfi_kif_get(group)) == NULL) - panic("pfi_kif_get failed"); - - pfi_kif_update(kif); - - splx(s); + if (!p->pfik_states++) + TAILQ_INSERT_TAIL(&pfi_statehead, p, pfik_w_states); } -int -pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af) +void +pfi_detach_state(struct pfi_kif *p) { - switch (af) { -#ifdef INET - case AF_INET: - switch (dyn->pfid_acnt4) { - case 0: - return (0); - case 1: - return (PF_MATCHA(0, &dyn->pfid_addr4, - &dyn->pfid_mask4, a, AF_INET)); - default: - return (pfr_match_addr(dyn->pfid_kt, a, AF_INET)); - } - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - switch (dyn->pfid_acnt6) { - case 0: - return (0); - case 1: - return (PF_MATCHA(0, &dyn->pfid_addr6, - &dyn->pfid_mask6, a, AF_INET6)); - default: - return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6)); - } - break; -#endif /* INET6 */ - default: - return (0); + if (p == NULL) + return; + if (p->pfik_states <= 0) { + printf("pfi_detach_state: reference count <= 0\n"); + return; } + if (!--p->pfik_states) + TAILQ_REMOVE(&pfi_statehead, p, pfik_w_states); + pfi_maybe_destroy(p); } int @@ -336,20 +512,15 @@ pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af) if (aw->type != PF_ADDR_DYNIFTL) return (0); - if ((dyn = pool_get(&pfi_addr_pl, PR_NOWAIT)) == NULL) + dyn = pool_get(&pfi_addr_pl, PR_NOWAIT); + if (dyn == NULL) return (1); bzero(dyn, sizeof(*dyn)); s = splsoftnet(); - if (!strcmp(aw->v.ifname, "self")) - dyn->pfid_kif = pfi_kif_get(IFG_ALL); - else - dyn->pfid_kif = pfi_kif_get(aw->v.ifname); - if (dyn->pfid_kif == NULL) { - rv = 1; - goto _bad; - } - pfi_kif_ref(dyn->pfid_kif, PFI_KIF_REF_RULE); + dyn->pfid_kif = pfi_attach_rule(aw->v.ifname); + if (dyn->pfid_kif == NULL) + senderr(1); dyn->pfid_net = pfi_unmask(&aw->v.a.mask); if (af == AF_INET && dyn->pfid_net == 32) @@ -366,23 +537,24 @@ pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af) if (dyn->pfid_net != 128) snprintf(tblname + strlen(tblname), sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net); - if ((ruleset = pf_find_or_create_ruleset(PF_RESERVED_ANCHOR)) == NULL) { - rv = 1; - goto _bad; - } + ruleset = pf_find_or_create_ruleset(PF_RESERVED_ANCHOR); + if (ruleset == NULL) + senderr(1); - if ((dyn->pfid_kt = pfr_attach_table(ruleset, tblname)) == NULL) { - rv = 1; - goto _bad; - } + dyn->pfid_kt = pfr_attach_table(ruleset, tblname); + if (dyn->pfid_kt == NULL) + senderr(1); dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE; dyn->pfid_iflags = aw->iflags; dyn->pfid_af = af; + dyn->pfid_hook_cookie = hook_establish(dyn->pfid_kif->pfik_ah_head, 1, + pfi_dynaddr_update, dyn); + if (dyn->pfid_hook_cookie == NULL) + senderr(1); - TAILQ_INSERT_TAIL(&dyn->pfid_kif->pfik_dynaddrs, dyn, entry); aw->p.dyn = dyn; - pfi_kif_update(dyn->pfid_kif); + pfi_dynaddr_update(aw->p.dyn); splx(s); return (0); @@ -392,32 +564,16 @@ _bad: if (ruleset != NULL) pf_remove_if_empty_ruleset(ruleset); if (dyn->pfid_kif != NULL) - pfi_kif_unref(dyn->pfid_kif, PFI_KIF_REF_RULE); + pfi_detach_rule(dyn->pfid_kif); pool_put(&pfi_addr_pl, dyn); splx(s); return (rv); } void -pfi_kif_update(struct pfi_kif *kif) -{ - struct ifg_list *ifgl; - struct pfi_dynaddr *p; - - /* update all dynaddr */ - TAILQ_FOREACH(p, &kif->pfik_dynaddrs, entry) - pfi_dynaddr_update(p); - - /* again for all groups kif is member of */ - if (kif->pfik_ifp != NULL) - TAILQ_FOREACH(ifgl, &kif->pfik_ifp->if_groups, ifgl_next) - pfi_kif_update((struct pfi_kif *) - ifgl->ifgl_group->ifg_pf_kif); -} - -void -pfi_dynaddr_update(struct pfi_dynaddr *dyn) +pfi_dynaddr_update(void *p) { + struct pfi_dynaddr *dyn = (struct pfi_dynaddr *)p; struct pfi_kif *kif; struct pfr_ktable *kt; @@ -426,7 +582,6 @@ pfi_dynaddr_update(struct pfi_dynaddr *dyn) kif = dyn->pfid_kif; kt = dyn->pfid_kt; - if (kt->pfrkt_larg != pfi_update) { /* this table needs to be brought up-to-date */ pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags); @@ -439,18 +594,28 @@ void pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags) { int e, size2 = 0; - struct ifg_member *ifgm; + struct pfi_kif *p; + struct pfr_table t; + if ((kif->pfik_flags & PFI_IFLAG_INSTANCE) && kif->pfik_ifp == NULL) { + pfr_clr_addrs(&kt->pfrkt_t, NULL, 0); + return; + } pfi_buffer_cnt = 0; - - if (kif->pfik_ifp != NULL) + if ((kif->pfik_flags & PFI_IFLAG_INSTANCE)) pfi_instance_add(kif->pfik_ifp, net, flags); - else if (kif->pfik_group != NULL) - TAILQ_FOREACH(ifgm, &kif->pfik_group->ifg_members, ifgm_next) - pfi_instance_add(ifgm->ifgm_ifp, net, flags); - - if ((e = pfr_set_addrs(&kt->pfrkt_t, pfi_buffer, pfi_buffer_cnt, &size2, - NULL, NULL, NULL, 0, PFR_TFLAG_ALLMASK))) + else if (strcmp(kif->pfik_name, "self")) { + TAILQ_FOREACH(p, &kif->pfik_grouphead, pfik_instances) + pfi_instance_add(p->pfik_ifp, net, flags); + } else { + RB_FOREACH(p, pfi_ifhead, &pfi_ifs) + if (p->pfik_flags & PFI_IFLAG_INSTANCE) + pfi_instance_add(p->pfik_ifp, net, flags); + } + t = kt->pfrkt_t; + t.pfrt_flags = 0; + if ((e = pfr_set_addrs(&t, pfi_buffer, pfi_buffer_cnt, &size2, + NULL, NULL, NULL, 0))) printf("pfi_table_update: cannot set %d new addresses " "into table %s: %d\n", pfi_buffer_cnt, kt->pfrkt_name, e); } @@ -470,6 +635,18 @@ pfi_instance_add(struct ifnet *ifp, int net, int flags) af = ia->ifa_addr->sa_family; if (af != AF_INET && af != AF_INET6) continue; +#ifdef __FreeBSD__ + /* + * XXX: For point-to-point interfaces, (ifname:0) and IPv4, + * jump over addresses without a proper route to work + * around a problem with ppp not fully removing the + * address used during IPCP. + */ + if ((ifp->if_flags & IFF_POINTOPOINT) && + !(ia->ifa_flags & IFA_ROUTE) && + (flags & PFI_AFLAG_NOALIAS) && (af == AF_INET)) + continue; +#endif if ((flags & PFI_AFLAG_BROADCAST) && af == AF_INET6) continue; if ((flags & PFI_AFLAG_BROADCAST) && @@ -494,12 +671,13 @@ pfi_instance_add(struct ifnet *ifp, int net, int flags) got6 = 1; net2 = net; if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) { - if (af == AF_INET) + if (af == AF_INET) { net2 = pfi_unmask(&((struct sockaddr_in *) ia->ifa_netmask)->sin_addr); - else if (af == AF_INET6) + } else if (af == AF_INET6) { net2 = pfi_unmask(&((struct sockaddr_in6 *) ia->ifa_netmask)->sin6_addr); + } } if (af == AF_INET && net2 > 32) net2 = 32; @@ -526,8 +704,13 @@ pfi_address_add(struct sockaddr *sa, int af, int net) pfi_buffer_cnt, PFI_BUFFER_MAX); return; } +#ifdef __FreeBSD__ + p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE, + M_NOWAIT); +#else p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE, M_DONTWAIT); +#endif if (p == NULL) { printf("pfi_address_add: no memory to grow buffer " "(%d/%d)\n", pfi_buffer_cnt, PFI_BUFFER_MAX); @@ -547,9 +730,9 @@ pfi_address_add(struct sockaddr *sa, int af, int net) p->pfra_net = net; if (af == AF_INET) p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr; - else if (af == AF_INET6) { + if (af == AF_INET6) { p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr; - if (IN6_IS_SCOPE_EMBED(&p->pfra_ip6addr)) + if (IN6_IS_ADDR_LINKLOCAL(&p->pfra_ip6addr)) p->pfra_ip6addr.s6_addr16[1] = 0; } /* mask network address bits */ @@ -569,8 +752,9 @@ pfi_dynaddr_remove(struct pf_addr_wrap *aw) return; s = splsoftnet(); - TAILQ_REMOVE(&aw->p.dyn->pfid_kif->pfik_dynaddrs, aw->p.dyn, entry); - pfi_kif_unref(aw->p.dyn->pfid_kif, PFI_KIF_REF_RULE); + hook_disestablish(aw->p.dyn->pfid_kif->pfik_ah_head, + aw->p.dyn->pfid_hook_cookie); + pfi_detach_rule(aw->p.dyn->pfid_kif); aw->p.dyn->pfid_kif = NULL; pfr_detach_table(aw->p.dyn->pfid_kt); aw->p.dyn->pfid_kt = NULL; @@ -591,12 +775,11 @@ pfi_dynaddr_copyout(struct pf_addr_wrap *aw) void pfi_kifaddr_update(void *v) { - int s; - struct pfi_kif *kif = (struct pfi_kif *)v; + int s; s = splsoftnet(); pfi_update++; - pfi_kif_update(kif); + pfi_dohooks(v); splx(s); } @@ -606,16 +789,149 @@ pfi_if_compare(struct pfi_kif *p, struct pfi_kif *q) return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ)); } +struct pfi_kif * +pfi_if_create(const char *name, struct pfi_kif *q, int flags) +{ + struct pfi_kif *p; + +#ifdef __FreeBSD__ + p = malloc(sizeof(*p), PFI_MTYPE, M_NOWAIT); +#else + p = malloc(sizeof(*p), PFI_MTYPE, M_DONTWAIT); +#endif + if (p == NULL) + return (NULL); + bzero(p, sizeof(*p)); +#ifdef __FreeBSD__ + p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE, + M_NOWAIT); +#else + p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE, + M_DONTWAIT); +#endif + if (p->pfik_ah_head == NULL) { + free(p, PFI_MTYPE); + return (NULL); + } + bzero(p->pfik_ah_head, sizeof(*p->pfik_ah_head)); + TAILQ_INIT(p->pfik_ah_head); + TAILQ_INIT(&p->pfik_grouphead); + strlcpy(p->pfik_name, name, sizeof(p->pfik_name)); + RB_INIT(&p->pfik_lan_ext); + RB_INIT(&p->pfik_ext_gwy); + p->pfik_flags = flags; + p->pfik_parent = q; +#ifdef __FreeBSD__ + /* + * It seems that the value of time_second is in unintialzied state when + * pf sets interface statistics clear time in boot phase if pf was + * statically linked to kernel. Instead of setting the bogus time value + * have pfi_get_ifaces handle this case. In pfi_get_ifaces it uses + * boottime.tv_sec if it sees the time is 0. + */ + p->pfik_tzero = time_second > 1 ? time_second : 0; +#else + p->pfik_tzero = time_second; +#endif + + RB_INSERT(pfi_ifhead, &pfi_ifs, p); + if (q != NULL) { + q->pfik_addcnt++; + TAILQ_INSERT_TAIL(&q->pfik_grouphead, p, pfik_instances); + } + pfi_ifcnt++; + return (p); +} + +int +pfi_maybe_destroy(struct pfi_kif *p) +{ + int i, j, k, s; + struct pfi_kif *q = p->pfik_parent; + +#ifdef __FreeBSD__ + if ((p->pfik_flags & (PFI_IFLAG_ATTACHED | PFI_IFLAG_GROUP)) || + ((p->pfik_rules > 0 || p->pfik_states > 0) && + (p->pfik_flags & PFI_IFLAG_PLACEHOLDER) == 0)) +#else + if ((p->pfik_flags & (PFI_IFLAG_ATTACHED | PFI_IFLAG_GROUP)) || + p->pfik_rules > 0 || p->pfik_states > 0) +#endif + return (0); + + s = splsoftnet(); + if (q != NULL) { + for (i = 0; i < 2; i++) + for (j = 0; j < 2; j++) + for (k = 0; k < 2; k++) { + q->pfik_bytes[i][j][k] += + p->pfik_bytes[i][j][k]; + q->pfik_packets[i][j][k] += + p->pfik_packets[i][j][k]; +#ifdef __FreeBSD__ + /* clear stats in case we return to the dummy group */ + p->pfik_bytes[i][j][k] = 0; + p->pfik_packets[i][j][k] = 0; +#endif + } + q->pfik_delcnt++; + TAILQ_REMOVE(&q->pfik_grouphead, p, pfik_instances); + } +#ifdef __FreeBSD__ + if (p->pfik_rules > 0 || p->pfik_states > 0) { + /* move back to the dummy group */ + p->pfik_parent = pfi_dummy; + p->pfik_flags &= ~PFI_IFLAG_INSTANCE; + pfi_dummy->pfik_addcnt++; + TAILQ_INSERT_TAIL(&pfi_dummy->pfik_grouphead, p, + pfik_instances); + return (0); + } +#endif + pfi_ifcnt--; + RB_REMOVE(pfi_ifhead, &pfi_ifs, p); + splx(s); + + free(p->pfik_ah_head, PFI_MTYPE); + free(p, PFI_MTYPE); + return (1); +} + +void +pfi_copy_group(char *p, const char *q, int m) +{ + while (m > 1 && *q && !(*q >= '0' && *q <= '9')) { + *p++ = *q++; + m--; + } + if (m > 0) + *p++ = '\0'; +} + +void +pfi_newgroup(const char *name, int flags) +{ + struct pfi_kif *p; + + p = pfi_lookup_if(name); + if (p == NULL) + p = pfi_if_create(name, pfi_self, PFI_IFLAG_GROUP); + if (p == NULL) { + printf("pfi_newgroup: cannot allocate '%s' group", name); + return; + } + p->pfik_flags |= flags; +} + void pfi_fill_oldstatus(struct pf_status *pfs) { - struct pfi_kif *p; - struct pfi_kif_cmp key; - int i, j, k, s; + struct pfi_kif *p, key; + int i, j, k, s; strlcpy(key.pfik_name, pfs->ifname, sizeof(key.pfik_name)); s = splsoftnet(); - p = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&key); + p = RB_FIND(pfi_ifhead, &pfi_ifs, &key); if (p == NULL) { splx(s); return; @@ -634,46 +950,92 @@ pfi_fill_oldstatus(struct pf_status *pfs) } int -pfi_clr_istats(const char *name) +pfi_clr_istats(const char *name, int *nzero, int flags) { struct pfi_kif *p; - int s; + int n = 0, s; + long tzero = time_second; + ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE); s = splsoftnet(); RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { - if (pfi_skip_if(name, p)) + if (pfi_skip_if(name, p, flags)) continue; bzero(p->pfik_packets, sizeof(p->pfik_packets)); bzero(p->pfik_bytes, sizeof(p->pfik_bytes)); - p->pfik_tzero = time_second; + p->pfik_tzero = tzero; + n++; } splx(s); + if (nzero != NULL) + *nzero = n; + return (0); +} +int +pfi_set_flags(const char *name, int flags) +{ + struct pfi_kif *p; + int s; + + if (flags & ~PFI_IFLAG_SETABLE_MASK) + return (EINVAL); + + s = splsoftnet(); + RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { + if (pfi_skip_if(name, p, PFI_FLAG_GROUP|PFI_FLAG_INSTANCE)) + continue; + p->pfik_flags |= flags; + } + splx(s); return (0); } int -pfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size) +pfi_clear_flags(const char *name, int flags) +{ + struct pfi_kif *p; + int s; + + if (flags & ~PFI_IFLAG_SETABLE_MASK) + return (EINVAL); + + s = splsoftnet(); + RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { + if (pfi_skip_if(name, p, PFI_FLAG_GROUP|PFI_FLAG_INSTANCE)) + continue; + p->pfik_flags &= ~flags; + } + splx(s); + return (0); +} + +int +pfi_get_ifaces(const char *name, struct pfi_if *buf, int *size, int flags) { - struct pfi_kif *p, *nextp; + struct pfi_kif *p; int s, n = 0; +#ifdef __FreeBSD__ + int ec; +#endif + ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE); s = splsoftnet(); - for (p = RB_MIN(pfi_ifhead, &pfi_ifs); p; p = nextp) { - nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p); - if (pfi_skip_if(name, p)) + RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { + if (pfi_skip_if(name, p, flags)) continue; if (*size > n++) { if (!p->pfik_tzero) p->pfik_tzero = time_second; - pfi_kif_ref(p, PFI_KIF_REF_RULE); +#ifdef __FreeBSD__ + PF_COPYOUT(p, buf++, sizeof(*buf), ec); + if (ec) { +#else if (copyout(p, buf++, sizeof(*buf))) { - pfi_kif_unref(p, PFI_KIF_REF_RULE); +#endif splx(s); return (EFAULT); } - nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p); - pfi_kif_unref(p, PFI_KIF_REF_RULE); } } splx(s); @@ -681,11 +1043,25 @@ pfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size) return (0); } +struct pfi_kif * +pfi_lookup_if(const char *name) +{ + struct pfi_kif *p, key; + + strlcpy(key.pfik_name, name, sizeof(key.pfik_name)); + p = RB_FIND(pfi_ifhead, &pfi_ifs, &key); + return (p); +} + int -pfi_skip_if(const char *filter, struct pfi_kif *p) +pfi_skip_if(const char *filter, struct pfi_kif *p, int f) { int n; + if ((p->pfik_flags & PFI_IFLAG_GROUP) && !(f & PFI_FLAG_GROUP)) + return (1); + if ((p->pfik_flags & PFI_IFLAG_INSTANCE) && !(f & PFI_FLAG_INSTANCE)) + return (1); if (filter == NULL || !*filter) return (0); if (!strcmp(p->pfik_name, filter)) @@ -700,38 +1076,6 @@ pfi_skip_if(const char *filter, struct pfi_kif *p) return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9'); } -int -pfi_set_flags(const char *name, int flags) -{ - struct pfi_kif *p; - int s; - - s = splsoftnet(); - RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { - if (pfi_skip_if(name, p)) - continue; - p->pfik_flags |= flags; - } - splx(s); - return (0); -} - -int -pfi_clear_flags(const char *name, int flags) -{ - struct pfi_kif *p; - int s; - - s = splsoftnet(); - RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { - if (pfi_skip_if(name, p)) - continue; - p->pfik_flags &= ~flags; - } - splx(s); - return (0); -} - /* from pf_print_state.c */ int pfi_unmask(void *addr) @@ -752,3 +1096,44 @@ pfi_unmask(void *addr) return (b); } +void +pfi_dohooks(struct pfi_kif *p) +{ + for (; p != NULL; p = p->pfik_parent) + dohooks(p->pfik_ah_head, 0); +} + +int +pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af) +{ + switch (af) { +#ifdef INET + case AF_INET: + switch (dyn->pfid_acnt4) { + case 0: + return (0); + case 1: + return (PF_MATCHA(0, &dyn->pfid_addr4, + &dyn->pfid_mask4, a, AF_INET)); + default: + return (pfr_match_addr(dyn->pfid_kt, a, AF_INET)); + } + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + switch (dyn->pfid_acnt6) { + case 0: + return (0); + case 1: + return (PF_MATCHA(0, &dyn->pfid_addr6, + &dyn->pfid_mask6, a, AF_INET6)); + default: + return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6)); + } + break; +#endif /* INET6 */ + default: + return (0); + } +} diff --git a/sys/contrib/pf/net/pf_ioctl.c b/sys/contrib/pf/net/pf_ioctl.c index 5694717..ddb2fec 100644 --- a/sys/contrib/pf/net/pf_ioctl.c +++ b/sys/contrib/pf/net/pf_ioctl.c @@ -1,4 +1,6 @@ -/* $OpenBSD: pf_ioctl.c,v 1.175 2007/02/26 22:47:43 deraadt Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: pf_ioctl.c,v 1.139 2005/03/03 07:13:39 dhartmei Exp $ */ +/* add: $OpenBSD: pf_ioctl.c,v 1.168 2006/07/21 01:21:17 dhartmei Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -35,7 +37,38 @@ * */ +#ifdef __FreeBSD__ +#include "opt_inet.h" +#include "opt_inet6.h" +#endif + +#ifdef __FreeBSD__ +#include "opt_bpf.h" +#include "opt_pf.h" + +#ifdef DEV_BPF +#define NBPFILTER DEV_BPF +#else +#define NBPFILTER 0 +#endif + +#ifdef DEV_PFLOG +#define NPFLOG DEV_PFLOG +#else +#define NPFLOG 0 +#endif + +#ifdef DEV_PFSYNC +#define NPFSYNC DEV_PFSYNC +#else +#define NPFSYNC 0 +#endif + +#else +#include "bpfilter.h" +#include "pflog.h" #include "pfsync.h" +#endif #include <sys/param.h> #include <sys/systm.h> @@ -46,13 +79,15 @@ #include <sys/socketvar.h> #include <sys/kernel.h> #include <sys/time.h> +#include <sys/malloc.h> +#ifdef __FreeBSD__ +#include <sys/module.h> +#include <sys/conf.h> +#include <sys/proc.h> +#else #include <sys/timeout.h> #include <sys/pool.h> -#include <sys/proc.h> -#include <sys/malloc.h> -#include <sys/kthread.h> -#include <sys/rwlock.h> -#include <uvm/uvm_extern.h> +#endif #include <net/if.h> #include <net/if_types.h> @@ -65,17 +100,18 @@ #include <netinet/ip_var.h> #include <netinet/ip_icmp.h> +#ifndef __FreeBSD__ #include <dev/rndvar.h> -#include <crypto/md5.h> +#endif #include <net/pfvar.h> #if NPFSYNC > 0 #include <net/if_pfsync.h> #endif /* NPFSYNC > 0 */ -#if NPFLOG > 0 +#ifdef __FreeBSD__ #include <net/if_pflog.h> -#endif /* NPFLOG > 0 */ +#endif #ifdef INET6 #include <netinet/ip6.h> @@ -86,16 +122,39 @@ #include <altq/altq.h> #endif +#ifdef __FreeBSD__ +#include <sys/limits.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <net/pfil.h> +#endif /* __FreeBSD__ */ + +#ifdef __FreeBSD__ +void init_zone_var(void); +void cleanup_pf_zone(void); +int pfattach(void); +#else void pfattach(int); -void pf_thread_create(void *); int pfopen(dev_t, int, int, struct proc *); int pfclose(dev_t, int, int, struct proc *); +#endif struct pf_pool *pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t, u_int8_t, u_int8_t, u_int8_t); +int pf_get_ruleset_number(u_int8_t); +void pf_init_ruleset(struct pf_ruleset *); +int pf_anchor_setup(struct pf_rule *, + const struct pf_ruleset *, const char *); +int pf_anchor_copyout(const struct pf_ruleset *, + const struct pf_rule *, struct pfioc_rule *); +void pf_anchor_remove(struct pf_rule *); void pf_mv_pool(struct pf_palist *, struct pf_palist *); void pf_empty_pool(struct pf_palist *); -int pfioctl(dev_t, u_long, caddr_t, int, struct proc *); +#ifdef __FreeBSD__ +int pfioctl(struct cdev *, u_long, caddr_t, int, struct thread *); +#else +int pfioctl(struct cdev *, u_long, caddr_t, int, struct proc *); +#endif #ifdef ALTQ int pf_begin_altq(u_int32_t *); int pf_rollback_altq(u_int32_t); @@ -105,13 +164,15 @@ int pf_disable_altq(struct pf_altq *); #endif /* ALTQ */ int pf_begin_rules(u_int32_t *, int, const char *); int pf_rollback_rules(u_int32_t, int, char *); -int pf_setup_pfsync_matching(struct pf_ruleset *); -void pf_hash_rule(MD5_CTX *, struct pf_rule *); -void pf_hash_rule_addr(MD5_CTX *, struct pf_rule_addr *); int pf_commit_rules(u_int32_t, int, char *); +#ifdef __FreeBSD__ +extern struct callout pf_expire_to; +#else +extern struct timeout pf_expire_to; +#endif + struct pf_rule pf_default_rule; -struct rwlock pf_consistency_lock = RWLOCK_INITIALIZER; #ifdef ALTQ static int pf_altq_running; #endif @@ -123,15 +184,194 @@ TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags), #if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE) #error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE #endif -u_int16_t tagname2tag(struct pf_tags *, char *); -void tag2tagname(struct pf_tags *, u_int16_t, char *); -void tag_unref(struct pf_tags *, u_int16_t); +static u_int16_t tagname2tag(struct pf_tags *, char *); +static void tag2tagname(struct pf_tags *, u_int16_t, char *); +static void tag_unref(struct pf_tags *, u_int16_t); int pf_rtlabel_add(struct pf_addr_wrap *); void pf_rtlabel_remove(struct pf_addr_wrap *); void pf_rtlabel_copyout(struct pf_addr_wrap *); #define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x + +#ifdef __FreeBSD__ +static struct cdev *pf_dev; + +/* + * XXX - These are new and need to be checked when moveing to a new version + */ +static void pf_clear_states(void); +static int pf_clear_tables(void); +static void pf_clear_srcnodes(void); +/* + * XXX - These are new and need to be checked when moveing to a new version + */ + +/* + * Wrapper functions for pfil(9) hooks + */ +static int pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, + int dir, struct inpcb *inp); +static int pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, + int dir, struct inpcb *inp); +#ifdef INET6 +static int pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, + int dir, struct inpcb *inp); +static int pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, + int dir, struct inpcb *inp); +#endif + +static int hook_pf(void); +static int dehook_pf(void); +static int shutdown_pf(void); +static int pf_load(void); +static int pf_unload(void); + +static struct cdevsw pf_cdevsw = { + .d_ioctl = pfioctl, + .d_name = PF_NAME, + .d_version = D_VERSION, +}; + +static volatile int pf_pfil_hooked = 0; +struct mtx pf_task_mtx; +pflog_packet_t *pflog_packet_ptr = NULL; + +void +init_pf_mutex(void) +{ + mtx_init(&pf_task_mtx, "pf task mtx", NULL, MTX_DEF); +} + +void +destroy_pf_mutex(void) +{ + mtx_destroy(&pf_task_mtx); +} + +void +init_zone_var(void) +{ + pf_src_tree_pl = pf_rule_pl = NULL; + pf_state_pl = pf_altq_pl = pf_pooladdr_pl = NULL; + pf_frent_pl = pf_frag_pl = pf_cache_pl = pf_cent_pl = NULL; + pf_state_scrub_pl = NULL; + pfr_ktable_pl = pfr_kentry_pl = NULL; +} + +void +cleanup_pf_zone(void) +{ + UMA_DESTROY(pf_src_tree_pl); + UMA_DESTROY(pf_rule_pl); + UMA_DESTROY(pf_state_pl); + UMA_DESTROY(pf_altq_pl); + UMA_DESTROY(pf_pooladdr_pl); + UMA_DESTROY(pf_frent_pl); + UMA_DESTROY(pf_frag_pl); + UMA_DESTROY(pf_cache_pl); + UMA_DESTROY(pf_cent_pl); + UMA_DESTROY(pfr_ktable_pl); + UMA_DESTROY(pfr_kentry_pl2); + UMA_DESTROY(pfr_kentry_pl); + UMA_DESTROY(pf_state_scrub_pl); + UMA_DESTROY(pfi_addr_pl); +} + +int +pfattach(void) +{ + u_int32_t *my_timeout = pf_default_rule.timeout; + int error = 1; + + do { + UMA_CREATE(pf_src_tree_pl,struct pf_src_node, "pfsrctrpl"); + UMA_CREATE(pf_rule_pl, struct pf_rule, "pfrulepl"); + UMA_CREATE(pf_state_pl, struct pf_state, "pfstatepl"); + UMA_CREATE(pf_altq_pl, struct pf_altq, "pfaltqpl"); + UMA_CREATE(pf_pooladdr_pl, struct pf_pooladdr, "pfpooladdrpl"); + UMA_CREATE(pfr_ktable_pl, struct pfr_ktable, "pfrktable"); + UMA_CREATE(pfr_kentry_pl, struct pfr_kentry, "pfrkentry"); + UMA_CREATE(pfr_kentry_pl2, struct pfr_kentry, "pfrkentry2"); + UMA_CREATE(pf_frent_pl, struct pf_frent, "pffrent"); + UMA_CREATE(pf_frag_pl, struct pf_fragment, "pffrag"); + UMA_CREATE(pf_cache_pl, struct pf_fragment, "pffrcache"); + UMA_CREATE(pf_cent_pl, struct pf_frcache, "pffrcent"); + UMA_CREATE(pf_state_scrub_pl, struct pf_state_scrub, + "pfstatescrub"); + UMA_CREATE(pfi_addr_pl, struct pfi_dynaddr, "pfiaddrpl"); + error = 0; + } while(0); + if (error) { + cleanup_pf_zone(); + return (error); + } + pfr_initialize(); + pfi_initialize(); + if ( (error = pf_osfp_initialize()) ) { + cleanup_pf_zone(); + pf_osfp_cleanup(); + return (error); + } + + pf_pool_limits[PF_LIMIT_STATES].pp = pf_state_pl; + pf_pool_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT; + pf_pool_limits[PF_LIMIT_SRC_NODES].pp = pf_src_tree_pl; + pf_pool_limits[PF_LIMIT_SRC_NODES].limit = PFSNODE_HIWAT; + pf_pool_limits[PF_LIMIT_FRAGS].pp = pf_frent_pl; + pf_pool_limits[PF_LIMIT_FRAGS].limit = PFFRAG_FRENT_HIWAT; + uma_zone_set_max(pf_pool_limits[PF_LIMIT_STATES].pp, + pf_pool_limits[PF_LIMIT_STATES].limit); + + RB_INIT(&tree_src_tracking); + RB_INIT(&pf_anchors); + pf_init_ruleset(&pf_main_ruleset); + TAILQ_INIT(&pf_altqs[0]); + TAILQ_INIT(&pf_altqs[1]); + TAILQ_INIT(&pf_pabuf); + pf_altqs_active = &pf_altqs[0]; + pf_altqs_inactive = &pf_altqs[1]; + TAILQ_INIT(&state_updates); + + /* default rule should never be garbage collected */ + pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next; + pf_default_rule.action = PF_PASS; + pf_default_rule.nr = -1; + + /* initialize default timeouts */ + my_timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; + my_timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL; + my_timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL; + my_timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL; + my_timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL; + my_timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL; + my_timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL; + my_timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL; + my_timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL; + my_timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL; + my_timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL; + my_timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL; + my_timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL; + my_timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL; + my_timeout[PFTM_FRAG] = PFTM_FRAG_VAL; + my_timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL; + my_timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL; + my_timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL; + + callout_init(&pf_expire_to, NET_CALLOUT_MPSAFE); + callout_reset(&pf_expire_to, my_timeout[PFTM_INTERVAL] * hz, + pf_purge_timeout, &pf_expire_to); + + pf_normalize_init(); + bzero(&pf_status, sizeof(pf_status)); + pf_pfil_hooked = 0; + + /* XXX do our best to avoid a conflict */ + pf_status.hostid = arc4random(); + + return (error); +} +#else /* !__FreeBSD__ */ void pfattach(int num) { @@ -154,10 +394,6 @@ pfattach(int num) pool_sethardlimit(pf_pool_limits[PF_LIMIT_STATES].pp, pf_pool_limits[PF_LIMIT_STATES].limit, NULL, 0); - if (ctob(physmem) <= 100*1024*1024) - pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit = - PFR_KENTRY_HIWAT_SMALL; - RB_INIT(&tree_src_tracking); RB_INIT(&pf_anchors); pf_init_ruleset(&pf_main_ruleset); @@ -166,13 +402,12 @@ pfattach(int num) TAILQ_INIT(&pf_pabuf); pf_altqs_active = &pf_altqs[0]; pf_altqs_inactive = &pf_altqs[1]; - TAILQ_INIT(&state_list); + TAILQ_INIT(&state_updates); /* default rule should never be garbage collected */ pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next; pf_default_rule.action = PF_PASS; pf_default_rule.nr = -1; - pf_default_rule.rtableid = -1; /* initialize default timeouts */ timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; @@ -193,8 +428,9 @@ pfattach(int num) timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL; timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL; timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL; - timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START; - timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END; + + timeout_set(&pf_expire_to, pf_purge_timeout, &pf_expire_to); + timeout_add(&pf_expire_to, timeout[PFTM_INTERVAL] * hz); pf_normalize_init(); bzero(&pf_status, sizeof(pf_status)); @@ -202,20 +438,10 @@ pfattach(int num) /* XXX do our best to avoid a conflict */ pf_status.hostid = arc4random(); - - /* require process context to purge states, so perform in a thread */ - kthread_create_deferred(pf_thread_create, NULL); -} - -void -pf_thread_create(void *v) -{ - if (kthread_create(pf_purge_thread, NULL, NULL, "pfpurge")) - panic("pfpurge thread"); } int -pfopen(dev_t dev, int flags, int fmt, struct proc *p) +pfopen(struct cdev *dev, int flags, int fmt, struct proc *p) { if (minor(dev) >= 1) return (ENXIO); @@ -223,12 +449,13 @@ pfopen(dev_t dev, int flags, int fmt, struct proc *p) } int -pfclose(dev_t dev, int flags, int fmt, struct proc *p) +pfclose(struct cdev *dev, int flags, int fmt, struct proc *p) { if (minor(dev) >= 1) return (ENXIO); return (0); } +#endif /* __FreeBSD__ */ struct pf_pool * pf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action, @@ -274,6 +501,312 @@ pf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action, return (&rule->rpool); } +int +pf_get_ruleset_number(u_int8_t action) +{ + switch (action) { + case PF_SCRUB: + case PF_NOSCRUB: + return (PF_RULESET_SCRUB); + break; + case PF_PASS: + case PF_DROP: + return (PF_RULESET_FILTER); + break; + case PF_NAT: + case PF_NONAT: + return (PF_RULESET_NAT); + break; + case PF_BINAT: + case PF_NOBINAT: + return (PF_RULESET_BINAT); + break; + case PF_RDR: + case PF_NORDR: + return (PF_RULESET_RDR); + break; + default: + return (PF_RULESET_MAX); + break; + } +} + +void +pf_init_ruleset(struct pf_ruleset *ruleset) +{ + int i; + + memset(ruleset, 0, sizeof(struct pf_ruleset)); + for (i = 0; i < PF_RULESET_MAX; i++) { + TAILQ_INIT(&ruleset->rules[i].queues[0]); + TAILQ_INIT(&ruleset->rules[i].queues[1]); + ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0]; + ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1]; + } +} + +struct pf_anchor * +pf_find_anchor(const char *path) +{ + static struct pf_anchor key; + + memset(&key, 0, sizeof(key)); + strlcpy(key.path, path, sizeof(key.path)); + return (RB_FIND(pf_anchor_global, &pf_anchors, &key)); +} + +struct pf_ruleset * +pf_find_ruleset(const char *path) +{ + struct pf_anchor *anchor; + + while (*path == '/') + path++; + if (!*path) + return (&pf_main_ruleset); + anchor = pf_find_anchor(path); + if (anchor == NULL) + return (NULL); + else + return (&anchor->ruleset); +} + +struct pf_ruleset * +pf_find_or_create_ruleset(const char *path) +{ + static char p[MAXPATHLEN]; + char *q = NULL, *r; /* make the compiler happy */ + struct pf_ruleset *ruleset; + struct pf_anchor *anchor = NULL, *dup, *parent = NULL; + + while (*path == '/') + path++; + ruleset = pf_find_ruleset(path); + if (ruleset != NULL) + return (ruleset); + strlcpy(p, path, sizeof(p)); +#ifdef __FreeBSD__ + while (parent == NULL && (q = rindex(p, '/')) != NULL) { +#else + while (parent == NULL && (q = strrchr(p, '/')) != NULL) { +#endif + *q = 0; + if ((ruleset = pf_find_ruleset(p)) != NULL) { + parent = ruleset->anchor; + break; + } + } + if (q == NULL) + q = p; + else + q++; + strlcpy(p, path, sizeof(p)); + if (!*q) + return (NULL); +#ifdef __FreeBSD__ + while ((r = index(q, '/')) != NULL || *q) { +#else + while ((r = strchr(q, '/')) != NULL || *q) { +#endif + if (r != NULL) + *r = 0; + if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE || + (parent != NULL && strlen(parent->path) >= + MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)) + return (NULL); + anchor = (struct pf_anchor *)malloc(sizeof(*anchor), M_TEMP, + M_NOWAIT); + if (anchor == NULL) + return (NULL); + memset(anchor, 0, sizeof(*anchor)); + RB_INIT(&anchor->children); + strlcpy(anchor->name, q, sizeof(anchor->name)); + if (parent != NULL) { + strlcpy(anchor->path, parent->path, + sizeof(anchor->path)); + strlcat(anchor->path, "/", sizeof(anchor->path)); + } + strlcat(anchor->path, anchor->name, sizeof(anchor->path)); + if ((dup = RB_INSERT(pf_anchor_global, &pf_anchors, anchor)) != + NULL) { + printf("pf_find_or_create_ruleset: RB_INSERT1 " + "'%s' '%s' collides with '%s' '%s'\n", + anchor->path, anchor->name, dup->path, dup->name); + free(anchor, M_TEMP); + return (NULL); + } + if (parent != NULL) { + anchor->parent = parent; + if ((dup = RB_INSERT(pf_anchor_node, &parent->children, + anchor)) != NULL) { + printf("pf_find_or_create_ruleset: " + "RB_INSERT2 '%s' '%s' collides with " + "'%s' '%s'\n", anchor->path, anchor->name, + dup->path, dup->name); + RB_REMOVE(pf_anchor_global, &pf_anchors, + anchor); + free(anchor, M_TEMP); + return (NULL); + } + } + pf_init_ruleset(&anchor->ruleset); + anchor->ruleset.anchor = anchor; + parent = anchor; + if (r != NULL) + q = r + 1; + else + *q = 0; + } + return (&anchor->ruleset); +} + +void +pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset) +{ + struct pf_anchor *parent; + int i; + + while (ruleset != NULL) { + if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL || + !RB_EMPTY(&ruleset->anchor->children) || + ruleset->anchor->refcnt > 0 || ruleset->tables > 0 || + ruleset->topen) + return; + for (i = 0; i < PF_RULESET_MAX; ++i) + if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) || + !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) || + ruleset->rules[i].inactive.open) + return; + RB_REMOVE(pf_anchor_global, &pf_anchors, ruleset->anchor); + if ((parent = ruleset->anchor->parent) != NULL) + RB_REMOVE(pf_anchor_node, &parent->children, + ruleset->anchor); + free(ruleset->anchor, M_TEMP); + if (parent == NULL) + return; + ruleset = &parent->ruleset; + } +} + +int +pf_anchor_setup(struct pf_rule *r, const struct pf_ruleset *s, + const char *name) +{ + static char *p, path[MAXPATHLEN]; + struct pf_ruleset *ruleset; + + r->anchor = NULL; + r->anchor_relative = 0; + r->anchor_wildcard = 0; + if (!name[0]) + return (0); + if (name[0] == '/') + strlcpy(path, name + 1, sizeof(path)); + else { + /* relative path */ + r->anchor_relative = 1; + if (s->anchor == NULL || !s->anchor->path[0]) + path[0] = 0; + else + strlcpy(path, s->anchor->path, sizeof(path)); + while (name[0] == '.' && name[1] == '.' && name[2] == '/') { + if (!path[0]) { + printf("pf_anchor_setup: .. beyond root\n"); + return (1); + } +#ifdef __FreeBSD__ + if ((p = rindex(path, '/')) != NULL) +#else + if ((p = strrchr(path, '/')) != NULL) +#endif + *p = 0; + else + path[0] = 0; + r->anchor_relative++; + name += 3; + } + if (path[0]) + strlcat(path, "/", sizeof(path)); + strlcat(path, name, sizeof(path)); + } +#ifdef __FreeBSD__ + if ((p = rindex(path, '/')) != NULL && !strcmp(p, "/*")) { +#else + if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) { +#endif + r->anchor_wildcard = 1; + *p = 0; + } + ruleset = pf_find_or_create_ruleset(path); + if (ruleset == NULL || ruleset->anchor == NULL) { + printf("pf_anchor_setup: ruleset\n"); + return (1); + } + r->anchor = ruleset->anchor; + r->anchor->refcnt++; + return (0); +} + +int +pf_anchor_copyout(const struct pf_ruleset *rs, const struct pf_rule *r, + struct pfioc_rule *pr) +{ + pr->anchor_call[0] = 0; + if (r->anchor == NULL) + return (0); + if (!r->anchor_relative) { + strlcpy(pr->anchor_call, "/", sizeof(pr->anchor_call)); + strlcat(pr->anchor_call, r->anchor->path, + sizeof(pr->anchor_call)); + } else { + char a[MAXPATHLEN], b[MAXPATHLEN], *p; + int i; + + if (rs->anchor == NULL) + a[0] = 0; + else + strlcpy(a, rs->anchor->path, sizeof(a)); + strlcpy(b, r->anchor->path, sizeof(b)); + for (i = 1; i < r->anchor_relative; ++i) { +#ifdef __FreeBSD__ + if ((p = rindex(a, '/')) == NULL) +#else + if ((p = strrchr(a, '/')) == NULL) +#endif + p = a; + *p = 0; + strlcat(pr->anchor_call, "../", + sizeof(pr->anchor_call)); + } + if (strncmp(a, b, strlen(a))) { + printf("pf_anchor_copyout: '%s' '%s'\n", a, b); + return (1); + } + if (strlen(b) > strlen(a)) + strlcat(pr->anchor_call, b + (a[0] ? strlen(a) + 1 : 0), + sizeof(pr->anchor_call)); + } + if (r->anchor_wildcard) + strlcat(pr->anchor_call, pr->anchor_call[0] ? "/*" : "*", + sizeof(pr->anchor_call)); + return (0); +} + +void +pf_anchor_remove(struct pf_rule *r) +{ + if (r->anchor == NULL) + return; + if (r->anchor->refcnt <= 0) { + printf("pf_anchor_remove: broken refcount"); + r->anchor = NULL; + return; + } + if (!--r->anchor->refcnt) + pf_remove_if_empty_ruleset(&r->anchor->ruleset); + r->anchor = NULL; +} + void pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb) { @@ -293,7 +826,7 @@ pf_empty_pool(struct pf_palist *poola) while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) { pfi_dynaddr_remove(&empty_pool_pa->addr); pf_tbladdr_remove(&empty_pool_pa->addr); - pfi_kif_unref(empty_pool_pa->kif, PFI_KIF_REF_RULE); + pfi_detach_rule(empty_pool_pa->kif); TAILQ_REMOVE(poola, empty_pool_pa, entries); pool_put(&pf_pooladdr_pl, empty_pool_pa); } @@ -339,13 +872,13 @@ pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule) if (rule->overload_tbl) pfr_detach_table(rule->overload_tbl); } - pfi_kif_unref(rule->kif, PFI_KIF_REF_RULE); + pfi_detach_rule(rule->kif); pf_anchor_remove(rule); pf_empty_pool(&rule->rpool.list); pool_put(&pf_rule_pl, rule); } -u_int16_t +static u_int16_t tagname2tag(struct pf_tags *head, char *tagname) { struct pf_tagname *tag, *p = NULL; @@ -390,7 +923,7 @@ tagname2tag(struct pf_tags *head, char *tagname) return (tag->tag); } -void +static void tag2tagname(struct pf_tags *head, u_int16_t tagid, char *p) { struct pf_tagname *tag; @@ -402,7 +935,7 @@ tag2tagname(struct pf_tags *head, u_int16_t tagid, char *p) } } -void +static void tag_unref(struct pf_tags *head, u_int16_t tag) { struct pf_tagname *p, *next; @@ -431,7 +964,7 @@ pf_tagname2tag(char *tagname) void pf_tag2tagname(u_int16_t tagid, char *p) { - tag2tagname(&pf_tags, tagid, p); + return (tag2tagname(&pf_tags, tagid, p)); } void @@ -449,28 +982,42 @@ pf_tag_ref(u_int16_t tag) void pf_tag_unref(u_int16_t tag) { - tag_unref(&pf_tags, tag); + return (tag_unref(&pf_tags, tag)); } int pf_rtlabel_add(struct pf_addr_wrap *a) { +#ifdef __FreeBSD__ + /* XXX_IMPORT: later */ + return (0); +#else if (a->type == PF_ADDR_RTLABEL && (a->v.rtlabel = rtlabel_name2id(a->v.rtlabelname)) == 0) return (-1); return (0); +#endif } void pf_rtlabel_remove(struct pf_addr_wrap *a) { +#ifdef __FreeBSD__ + /* XXX_IMPORT: later */ +#else if (a->type == PF_ADDR_RTLABEL) rtlabel_unref(a->v.rtlabel); +#endif } void pf_rtlabel_copyout(struct pf_addr_wrap *a) { +#ifdef __FreeBSD__ + /* XXX_IMPORT: later */ + if (a->type == PF_ADDR_RTLABEL && a->v.rtlabel) + strlcpy(a->v.rtlabelname, "?", sizeof(a->v.rtlabelname)); +#else const char *name; if (a->type == PF_ADDR_RTLABEL && a->v.rtlabel) { @@ -481,6 +1028,7 @@ pf_rtlabel_copyout(struct pf_addr_wrap *a) strlcpy(a->v.rtlabelname, name, sizeof(a->v.rtlabelname)); } +#endif } #ifdef ALTQ @@ -493,13 +1041,13 @@ pf_qname2qid(char *qname) void pf_qid2qname(u_int32_t qid, char *p) { - tag2tagname(&pf_qids, (u_int16_t)qid, p); + return (tag2tagname(&pf_qids, (u_int16_t)qid, p)); } void pf_qid_unref(u_int32_t qid) { - tag_unref(&pf_qids, (u_int16_t)qid); + return (tag_unref(&pf_qids, (u_int16_t)qid)); } int @@ -618,8 +1166,14 @@ pf_enable_altq(struct pf_altq *altq) if (error == 0 && ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) { tb.rate = altq->ifbandwidth; tb.depth = altq->tbrsize; - s = splnet(); + s = splimp(); +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif error = tbr_set(&ifp->if_snd, &tb); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif splx(s); } @@ -648,8 +1202,14 @@ pf_disable_altq(struct pf_altq *altq) if (error == 0) { /* clear tokenbucket regulator */ tb.rate = 0; - s = splnet(); + s = splimp(); +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif error = tbr_set(&ifp->if_snd, &tb); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif splx(s); } @@ -668,10 +1228,8 @@ pf_begin_rules(u_int32_t *ticket, int rs_num, const char *anchor) rs = pf_find_or_create_ruleset(anchor); if (rs == NULL) return (EINVAL); - while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) { + while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule); - rs->rules[rs_num].inactive.rcount--; - } *ticket = ++rs->rules[rs_num].inactive.ticket; rs->rules[rs_num].inactive.open = 1; return (0); @@ -689,105 +1247,19 @@ pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor) if (rs == NULL || !rs->rules[rs_num].inactive.open || rs->rules[rs_num].inactive.ticket != ticket) return (0); - while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) { + while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule); - rs->rules[rs_num].inactive.rcount--; - } rs->rules[rs_num].inactive.open = 0; return (0); } -#define PF_MD5_UPD(st, elm) \ - MD5Update(ctx, (u_int8_t *) &(st)->elm, sizeof((st)->elm)) - -#define PF_MD5_UPD_STR(st, elm) \ - MD5Update(ctx, (u_int8_t *) (st)->elm, strlen((st)->elm)) - -#define PF_MD5_UPD_HTONL(st, elm, stor) do { \ - (stor) = htonl((st)->elm); \ - MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int32_t));\ -} while (0) - -#define PF_MD5_UPD_HTONS(st, elm, stor) do { \ - (stor) = htons((st)->elm); \ - MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int16_t));\ -} while (0) - -void -pf_hash_rule_addr(MD5_CTX *ctx, struct pf_rule_addr *pfr) -{ - PF_MD5_UPD(pfr, addr.type); - switch (pfr->addr.type) { - case PF_ADDR_DYNIFTL: - PF_MD5_UPD(pfr, addr.v.ifname); - PF_MD5_UPD(pfr, addr.iflags); - break; - case PF_ADDR_TABLE: - PF_MD5_UPD(pfr, addr.v.tblname); - break; - case PF_ADDR_ADDRMASK: - /* XXX ignore af? */ - PF_MD5_UPD(pfr, addr.v.a.addr.addr32); - PF_MD5_UPD(pfr, addr.v.a.mask.addr32); - break; - case PF_ADDR_RTLABEL: - PF_MD5_UPD(pfr, addr.v.rtlabelname); - break; - } - - PF_MD5_UPD(pfr, port[0]); - PF_MD5_UPD(pfr, port[1]); - PF_MD5_UPD(pfr, neg); - PF_MD5_UPD(pfr, port_op); -} - -void -pf_hash_rule(MD5_CTX *ctx, struct pf_rule *rule) -{ - u_int16_t x; - u_int32_t y; - - pf_hash_rule_addr(ctx, &rule->src); - pf_hash_rule_addr(ctx, &rule->dst); - PF_MD5_UPD_STR(rule, label); - PF_MD5_UPD_STR(rule, ifname); - PF_MD5_UPD_STR(rule, match_tagname); - PF_MD5_UPD_HTONS(rule, match_tag, x); /* dup? */ - PF_MD5_UPD_HTONL(rule, os_fingerprint, y); - PF_MD5_UPD_HTONL(rule, prob, y); - PF_MD5_UPD_HTONL(rule, uid.uid[0], y); - PF_MD5_UPD_HTONL(rule, uid.uid[1], y); - PF_MD5_UPD(rule, uid.op); - PF_MD5_UPD_HTONL(rule, gid.gid[0], y); - PF_MD5_UPD_HTONL(rule, gid.gid[1], y); - PF_MD5_UPD(rule, gid.op); - PF_MD5_UPD_HTONL(rule, rule_flag, y); - PF_MD5_UPD(rule, action); - PF_MD5_UPD(rule, direction); - PF_MD5_UPD(rule, af); - PF_MD5_UPD(rule, quick); - PF_MD5_UPD(rule, ifnot); - PF_MD5_UPD(rule, match_tag_not); - PF_MD5_UPD(rule, natpass); - PF_MD5_UPD(rule, keep_state); - PF_MD5_UPD(rule, proto); - PF_MD5_UPD(rule, type); - PF_MD5_UPD(rule, code); - PF_MD5_UPD(rule, flags); - PF_MD5_UPD(rule, flagset); - PF_MD5_UPD(rule, allow_opts); - PF_MD5_UPD(rule, rt); - PF_MD5_UPD(rule, tos); -} - int pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor) { struct pf_ruleset *rs; - struct pf_rule *rule, **old_array; + struct pf_rule *rule; struct pf_rulequeue *old_rules; - int s, error; - u_int32_t old_rcount; + int s; if (rs_num < 0 || rs_num >= PF_RULESET_MAX) return (EINVAL); @@ -796,97 +1268,46 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor) ticket != rs->rules[rs_num].inactive.ticket) return (EBUSY); - /* Calculate checksum for the main ruleset */ - if (rs == &pf_main_ruleset) { - error = pf_setup_pfsync_matching(rs); - if (error != 0) - return (error); - } - /* Swap rules, keep the old. */ s = splsoftnet(); old_rules = rs->rules[rs_num].active.ptr; - old_rcount = rs->rules[rs_num].active.rcount; - old_array = rs->rules[rs_num].active.ptr_array; - rs->rules[rs_num].active.ptr = rs->rules[rs_num].inactive.ptr; - rs->rules[rs_num].active.ptr_array = - rs->rules[rs_num].inactive.ptr_array; - rs->rules[rs_num].active.rcount = - rs->rules[rs_num].inactive.rcount; rs->rules[rs_num].inactive.ptr = old_rules; - rs->rules[rs_num].inactive.ptr_array = old_array; - rs->rules[rs_num].inactive.rcount = old_rcount; - rs->rules[rs_num].active.ticket = rs->rules[rs_num].inactive.ticket; pf_calc_skip_steps(rs->rules[rs_num].active.ptr); - /* Purge the old rule list. */ while ((rule = TAILQ_FIRST(old_rules)) != NULL) pf_rm_rule(old_rules, rule); - if (rs->rules[rs_num].inactive.ptr_array) - free(rs->rules[rs_num].inactive.ptr_array, M_TEMP); - rs->rules[rs_num].inactive.ptr_array = NULL; - rs->rules[rs_num].inactive.rcount = 0; rs->rules[rs_num].inactive.open = 0; pf_remove_if_empty_ruleset(rs); splx(s); return (0); } +#ifdef __FreeBSD__ int -pf_setup_pfsync_matching(struct pf_ruleset *rs) -{ - MD5_CTX ctx; - struct pf_rule *rule; - int rs_cnt; - u_int8_t digest[PF_MD5_DIGEST_LENGTH]; - - MD5Init(&ctx); - for (rs_cnt = 0; rs_cnt < PF_RULESET_MAX; rs_cnt++) { - /* XXX PF_RULESET_SCRUB as well? */ - if (rs_cnt == PF_RULESET_SCRUB) - continue; - - if (rs->rules[rs_cnt].inactive.ptr_array) - free(rs->rules[rs_cnt].inactive.ptr_array, M_TEMP); - rs->rules[rs_cnt].inactive.ptr_array = NULL; - - if (rs->rules[rs_cnt].inactive.rcount) { - rs->rules[rs_cnt].inactive.ptr_array = - malloc(sizeof(caddr_t) * - rs->rules[rs_cnt].inactive.rcount, - M_TEMP, M_NOWAIT); - - if (!rs->rules[rs_cnt].inactive.ptr_array) - return (ENOMEM); - } - - TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr, - entries) { - pf_hash_rule(&ctx, rule); - (rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule; - } - } - - MD5Final(digest, &ctx); - memcpy(pf_status.pf_chksum, digest, sizeof(pf_status.pf_chksum)); - return (0); -} - +pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) +#else int -pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) +pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct proc *p) +#endif { struct pf_pooladdr *pa = NULL; struct pf_pool *pool = NULL; +#ifndef __FreeBSD__ int s; +#endif int error = 0; /* XXX keep in sync with switch() below */ +#ifdef __FreeBSD__ + if (securelevel_gt(td->td_ucred, 2)) +#else if (securelevel > 1) +#endif switch (cmd) { case DIOCGETRULES: case DIOCGETRULE: @@ -922,6 +1343,10 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCGETSRCNODES: case DIOCCLRSRCNODES: case DIOCIGETIFACES: + case DIOCICLRISTATS: +#ifdef __FreeBSD__ + case DIOCGIFSPEED: +#endif case DIOCSETIFFLAG: case DIOCCLRIFFLAG: break; @@ -940,6 +1365,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (!(flags & FWRITE)) switch (cmd) { case DIOCGETRULES: + case DIOCGETRULE: case DIOCGETADDRS: case DIOCGETADDR: case DIOCGETSTATE: @@ -952,7 +1378,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCGETQSTATS: case DIOCGETRULESETS: case DIOCGETRULESET: - case DIOCNATLOOK: case DIOCRGETTABLES: case DIOCRGETTSTATS: case DIOCRGETADDRS: @@ -961,6 +1386,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCOSFPGET: case DIOCGETSRCNODES: case DIOCIGETIFACES: +#ifdef __FreeBSD__ + case DIOCGIFSPEED: +#endif break; case DIOCRCLRTABLES: case DIOCRADDTABLES: @@ -972,31 +1400,34 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCRSETADDRS: case DIOCRSETTFLAGS: if (((struct pfioc_table *)addr)->pfrio_flags & - PFR_FLAG_DUMMY) { - flags |= FWRITE; /* need write lock for dummy */ + PFR_FLAG_DUMMY) break; /* dummy operation ok */ - } return (EACCES); - case DIOCGETRULE: - if (((struct pfioc_rule *)addr)->action == PF_GET_CLR_CNTR) - return (EACCES); - break; default: return (EACCES); } - if (flags & FWRITE) - rw_enter_write(&pf_consistency_lock); - else - rw_enter_read(&pf_consistency_lock); - +#ifdef __FreeBSD__ + PF_LOCK(); +#else s = splsoftnet(); +#endif switch (cmd) { case DIOCSTART: if (pf_status.running) error = EEXIST; else { +#ifdef __FreeBSD__ + PF_UNLOCK(); + error = hook_pf(); + PF_LOCK(); + if (error) { + DPFPRINTF(PF_DEBUG_MISC, + ("pf: pfil registeration fail\n")); + break; + } +#endif pf_status.running = 1; pf_status.since = time_second; if (pf_status.stateid == 0) { @@ -1012,6 +1443,16 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = ENOENT; else { pf_status.running = 0; +#ifdef __FreeBSD__ + PF_UNLOCK(); + error = dehook_pf(); + PF_LOCK(); + if (error) { + pf_status.running = 1; + DPFPRINTF(PF_DEBUG_MISC, + ("pf: pfil unregisteration failed\n")); + } +#endif pf_status.since = time_second; DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n")); } @@ -1040,10 +1481,20 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) { +#ifdef __FreeBSD__ + DPFPRINTF(PF_DEBUG_MISC, + ("ticket: %d != [%d]%d\n", pr->ticket, rs_num, + ruleset->rules[rs_num].inactive.ticket)); +#endif error = EBUSY; break; } if (pr->pool_ticket != ticket_pabuf) { +#ifdef __FreeBSD__ + DPFPRINTF(PF_DEBUG_MISC, + ("pool_ticket: %d != %d\n", pr->pool_ticket, + ticket_pabuf)); +#endif error = EBUSY; break; } @@ -1053,8 +1504,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } bcopy(&pr->rule, rule, sizeof(struct pf_rule)); - rule->cuid = p->p_cred->p_ruid; - rule->cpid = p->p_pid; rule->anchor = NULL; rule->kif = NULL; TAILQ_INIT(&rule->rpool.list); @@ -1083,18 +1532,14 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) else rule->nr = 0; if (rule->ifname[0]) { - rule->kif = pfi_kif_get(rule->ifname); + rule->kif = pfi_attach_rule(rule->ifname); if (rule->kif == NULL) { pool_put(&pf_rule_pl, rule); error = EINVAL; break; } - pfi_kif_ref(rule->kif, PFI_KIF_REF_RULE); } - if (rule->rtableid > 0 && !rtable_exists(rule->rtableid)) - error = EBUSY; - #ifdef ALTQ /* set queue IDs */ if (rule->qname[0] != 0) { @@ -1117,10 +1562,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EBUSY; if (rule->rt && !rule->direction) error = EINVAL; -#if NPFLOG > 0 - if (rule->logif >= PFLOGIFS_MAX) - error = EINVAL; -#endif if (pf_rtlabel_add(&rule->src.addr) || pf_rtlabel_add(&rule->dst.addr)) error = EBUSY; @@ -1159,11 +1600,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list); - rule->evaluations = rule->packets[0] = rule->packets[1] = - rule->bytes[0] = rule->bytes[1] = 0; + rule->evaluations = rule->packets = rule->bytes = 0; TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr, rule, entries); - ruleset->rules[rs_num].inactive.rcount++; break; } @@ -1239,12 +1678,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) else pr->rule.skip[i].nr = rule->skip[i].ptr->nr; - - if (pr->action == PF_GET_CLR_CNTR) { - rule->evaluations = 0; - rule->packets[0] = rule->packets[1] = 0; - rule->bytes[0] = rule->bytes[1] = 0; - } break; } @@ -1300,8 +1733,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } bcopy(&pcr->rule, newrule, sizeof(struct pf_rule)); - newrule->cuid = p->p_cred->p_ruid; - newrule->cpid = p->p_pid; TAILQ_INIT(&newrule->rpool.list); /* initialize refcounting */ newrule->states = 0; @@ -1321,20 +1752,15 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } #endif /* INET6 */ if (newrule->ifname[0]) { - newrule->kif = pfi_kif_get(newrule->ifname); + newrule->kif = pfi_attach_rule(newrule->ifname); if (newrule->kif == NULL) { pool_put(&pf_rule_pl, newrule); error = EINVAL; break; } - pfi_kif_ref(newrule->kif, PFI_KIF_REF_RULE); } else newrule->kif = NULL; - if (newrule->rtableid > 0 && - !rtable_exists(newrule->rtableid)) - error = EBUSY; - #ifdef ALTQ /* set queue IDs */ if (newrule->qname[0] != 0) { @@ -1400,9 +1826,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list); - newrule->evaluations = 0; - newrule->packets[0] = newrule->packets[1] = 0; - newrule->bytes[0] = newrule->bytes[1] = 0; + newrule->evaluations = newrule->packets = 0; + newrule->bytes = 0; } pf_empty_pool(&pf_pabuf); @@ -1425,10 +1850,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } } - if (pcr->action == PF_CHANGE_REMOVE) { + if (pcr->action == PF_CHANGE_REMOVE) pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule); - ruleset->rules[rs_num].active.rcount--; - } else { + else { if (oldrule == NULL) TAILQ_INSERT_TAIL( ruleset->rules[rs_num].active.ptr, @@ -1440,7 +1864,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) TAILQ_INSERT_AFTER( ruleset->rules[rs_num].active.ptr, oldrule, newrule, entries); - ruleset->rules[rs_num].active.rcount++; } nr = 0; @@ -1457,24 +1880,23 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } case DIOCCLRSTATES: { - struct pf_state *state, *nexts; + struct pf_state *state; struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; int killed = 0; - for (state = RB_MIN(pf_state_tree_id, &tree_id); state; - state = nexts) { - nexts = RB_NEXT(pf_state_tree_id, &tree_id, state); - + RB_FOREACH(state, pf_state_tree_id, &tree_id) { if (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname, state->u.s.kif->pfik_name)) { + state->timeout = PFTM_PURGE; #if NPFSYNC /* don't send out individual delete messages */ state->sync_flags = PFSTATE_NOSYNC; #endif - pf_unlink_state(state); killed++; } } + pf_purge_expired_states(); + pf_status.states = 0; psk->psk_af = killed; #if NPFSYNC pfsync_clear_states(pf_status.hostid, psk->psk_ifname); @@ -1483,52 +1905,37 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } case DIOCKILLSTATES: { - struct pf_state *state, *nexts; - struct pf_state_host *src, *dst; + struct pf_state *state; struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; int killed = 0; - for (state = RB_MIN(pf_state_tree_id, &tree_id); state; - state = nexts) { - nexts = RB_NEXT(pf_state_tree_id, &tree_id, state); - - if (state->direction == PF_OUT) { - src = &state->lan; - dst = &state->ext; - } else { - src = &state->ext; - dst = &state->lan; - } + RB_FOREACH(state, pf_state_tree_id, &tree_id) { if ((!psk->psk_af || state->af == psk->psk_af) && (!psk->psk_proto || psk->psk_proto == state->proto) && PF_MATCHA(psk->psk_src.neg, &psk->psk_src.addr.v.a.addr, &psk->psk_src.addr.v.a.mask, - &src->addr, state->af) && + &state->lan.addr, state->af) && PF_MATCHA(psk->psk_dst.neg, &psk->psk_dst.addr.v.a.addr, &psk->psk_dst.addr.v.a.mask, - &dst->addr, state->af) && + &state->ext.addr, state->af) && (psk->psk_src.port_op == 0 || pf_match_port(psk->psk_src.port_op, psk->psk_src.port[0], psk->psk_src.port[1], - src->port)) && + state->lan.port)) && (psk->psk_dst.port_op == 0 || pf_match_port(psk->psk_dst.port_op, psk->psk_dst.port[0], psk->psk_dst.port[1], - dst->port)) && + state->ext.port)) && (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname, state->u.s.kif->pfik_name))) { -#if NPFSYNC > 0 - /* send immediate delete of state */ - pfsync_delete_state(state); - state->sync_flags |= PFSTATE_NOSYNC; -#endif - pf_unlink_state(state); + state->timeout = PFTM_PURGE; killed++; } } + pf_purge_expired_states(); psk->psk_af = killed; break; } @@ -1548,7 +1955,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = ENOMEM; break; } - kif = pfi_kif_get(ps->state.u.ifname); + kif = pfi_lookup_create(ps->state.u.ifname); if (kif == NULL) { pool_put(&pf_state_pl, state); error = ENOENT; @@ -1566,7 +1973,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) state->bytes[0] = state->bytes[1] = 0; if (pf_insert_state(kif, state)) { - pfi_kif_unref(kif, PFI_KIF_REF_NONE); + pfi_maybe_destroy(kif); pool_put(&pf_state_pl, state); error = ENOMEM; } @@ -1577,7 +1984,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) struct pfioc_state *ps = (struct pfioc_state *)addr; struct pf_state *state; u_int32_t nr; - int secs; nr = 0; RB_FOREACH(state, pf_state_tree_id, &tree_id) { @@ -1589,19 +1995,15 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EBUSY; break; } - secs = time_second; - bcopy(state, &ps->state, sizeof(ps->state)); - strlcpy(ps->state.u.ifname, state->u.s.kif->pfik_name, - sizeof(ps->state.u.ifname)); + bcopy(state, &ps->state, sizeof(struct pf_state)); ps->state.rule.nr = state->rule.ptr->nr; ps->state.nat_rule.nr = (state->nat_rule.ptr == NULL) ? -1 : state->nat_rule.ptr->nr; ps->state.anchor.nr = (state->anchor.ptr == NULL) ? -1 : state->anchor.ptr->nr; - ps->state.creation = secs - ps->state.creation; ps->state.expire = pf_state_expires(state); - if (ps->state.expire > secs) - ps->state.expire -= secs; + if (ps->state.expire > time_second) + ps->state.expire -= time_second; else ps->state.expire = 0; break; @@ -1610,57 +2012,52 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCGETSTATES: { struct pfioc_states *ps = (struct pfioc_states *)addr; struct pf_state *state; - struct pf_state *p, *pstore; + struct pf_state *p, pstore; + struct pfi_kif *kif; u_int32_t nr = 0; int space = ps->ps_len; if (space == 0) { - nr = pf_status.states; + TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) + nr += kif->pfik_states; ps->ps_len = sizeof(struct pf_state) * nr; break; } - pstore = malloc(sizeof(*pstore), M_TEMP, M_WAITOK); - p = ps->ps_states; - - state = TAILQ_FIRST(&state_list); - while (state) { - if (state->timeout != PFTM_UNLINKED) { + TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) + RB_FOREACH(state, pf_state_tree_ext_gwy, + &kif->pfik_ext_gwy) { int secs = time_second; if ((nr+1) * sizeof(*p) > (unsigned)ps->ps_len) break; - bcopy(state, pstore, sizeof(*pstore)); - strlcpy(pstore->u.ifname, - state->u.s.kif->pfik_name, - sizeof(pstore->u.ifname)); - pstore->rule.nr = state->rule.ptr->nr; - pstore->nat_rule.nr = (state->nat_rule.ptr == + bcopy(state, &pstore, sizeof(pstore)); + strlcpy(pstore.u.ifname, kif->pfik_name, + sizeof(pstore.u.ifname)); + pstore.rule.nr = state->rule.ptr->nr; + pstore.nat_rule.nr = (state->nat_rule.ptr == NULL) ? -1 : state->nat_rule.ptr->nr; - pstore->anchor.nr = (state->anchor.ptr == + pstore.anchor.nr = (state->anchor.ptr == NULL) ? -1 : state->anchor.ptr->nr; - pstore->creation = secs - pstore->creation; - pstore->expire = pf_state_expires(state); - if (pstore->expire > secs) - pstore->expire -= secs; + pstore.creation = secs - pstore.creation; + pstore.expire = pf_state_expires(state); + if (pstore.expire > secs) + pstore.expire -= secs; else - pstore->expire = 0; - error = copyout(pstore, p, sizeof(*p)); - if (error) { - free(pstore, M_TEMP); + pstore.expire = 0; +#ifdef __FreeBSD__ + PF_COPYOUT(&pstore, p, sizeof(*p), error); +#else + error = copyout(&pstore, p, sizeof(*p)); +#endif + if (error) goto fail; - } p++; nr++; } - state = TAILQ_NEXT(state, u.s.entry_list); - } - ps->ps_len = sizeof(struct pf_state) * nr; - - free(pstore, M_TEMP); break; } @@ -1690,16 +2087,16 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) bzero(pf_status.counters, sizeof(pf_status.counters)); bzero(pf_status.fcounters, sizeof(pf_status.fcounters)); bzero(pf_status.scounters, sizeof(pf_status.scounters)); - pf_status.since = time_second; if (*pf_status.ifname) - pfi_clr_istats(pf_status.ifname); + pfi_clr_istats(pf_status.ifname, NULL, + PFI_FLAG_INSTANCE); break; } case DIOCNATLOOK: { struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr; struct pf_state *state; - struct pf_state_cmp key; + struct pf_state key; int m = 0, direction = pnl->direction; key.af = pnl->af; @@ -1708,9 +2105,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (!pnl->proto || PF_AZERO(&pnl->saddr, pnl->af) || PF_AZERO(&pnl->daddr, pnl->af) || - ((pnl->proto == IPPROTO_TCP || - pnl->proto == IPPROTO_UDP) && - (!pnl->dport || !pnl->sport))) + !pnl->dport || !pnl->sport) error = EINVAL; else { /* @@ -1766,11 +2161,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) goto fail; } old = pf_default_rule.timeout[pt->timeout]; - if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0) - pt->seconds = 1; pf_default_rule.timeout[pt->timeout] = pt->seconds; - if (pt->timeout == PFTM_INTERVAL && pt->seconds < old) - wakeup(pf_purge_thread); pt->seconds = old; break; } @@ -1806,11 +2197,15 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; goto fail; } +#ifdef __FreeBSD__ + uma_zone_set_max(pf_pool_limits[pl->index].pp, pl->limit); +#else if (pool_sethardlimit(pf_pool_limits[pl->index].pp, pl->limit, NULL, 0) != 0) { error = EBUSY; goto fail; } +#endif old_limit = pf_pool_limits[pl->index].limit; pf_pool_limits[pl->index].limit = pl->limit; pl->limit = old_limit; @@ -1825,18 +2220,35 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } case DIOCCLRRULECTRS: { - /* obsoleted by DIOCGETRULE with action=PF_GET_CLR_CNTR */ struct pf_ruleset *ruleset = &pf_main_ruleset; struct pf_rule *rule; TAILQ_FOREACH(rule, - ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) { - rule->evaluations = 0; - rule->packets[0] = rule->packets[1] = 0; - rule->bytes[0] = rule->bytes[1] = 0; - } + ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) + rule->evaluations = rule->packets = + rule->bytes = 0; + break; + } + +#ifdef __FreeBSD__ + case DIOCGIFSPEED: { + struct pf_ifspeed *psp = (struct pf_ifspeed *)addr; + struct pf_ifspeed ps; + struct ifnet *ifp; + + if (psp->ifname[0] != 0) { + /* Can we completely trust user-land? */ + strlcpy(ps.ifname, psp->ifname, IFNAMSIZ); + ifp = ifunit(ps.ifname); + if (ifp != NULL) + psp->baudrate = ifp->if_baudrate; + else + error = EINVAL; + } else + error = EINVAL; break; } +#endif /* __FreeBSD__ */ #ifdef ALTQ case DIOCSTARTALTQ: { @@ -1907,7 +2319,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } } +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif error = altq_add(altq); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif if (error) { pool_put(&pf_altq_pl, altq); break; @@ -1978,7 +2396,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EBUSY; break; } +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif error = altq_getqstats(altq, pq->buf, &nbytes); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif if (error == 0) { pq->scheduler = altq->scheduler; pq->nbytes = nbytes; @@ -2027,17 +2451,16 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr)); if (pa->ifname[0]) { - pa->kif = pfi_kif_get(pa->ifname); + pa->kif = pfi_attach_rule(pa->ifname); if (pa->kif == NULL) { pool_put(&pf_pooladdr_pl, pa); error = EINVAL; break; } - pfi_kif_ref(pa->kif, PFI_KIF_REF_RULE); } if (pfi_dynaddr_setup(&pa->addr, pp->af)) { pfi_dynaddr_remove(&pa->addr); - pfi_kif_unref(pa->kif, PFI_KIF_REF_RULE); + pfi_detach_rule(pa->kif); pool_put(&pf_pooladdr_pl, pa); error = EINVAL; break; @@ -2137,19 +2560,18 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } #endif /* INET6 */ if (newpa->ifname[0]) { - newpa->kif = pfi_kif_get(newpa->ifname); + newpa->kif = pfi_attach_rule(newpa->ifname); if (newpa->kif == NULL) { pool_put(&pf_pooladdr_pl, newpa); error = EINVAL; break; } - pfi_kif_ref(newpa->kif, PFI_KIF_REF_RULE); } else newpa->kif = NULL; if (pfi_dynaddr_setup(&newpa->addr, pca->af) || pf_tbladdr_setup(ruleset, &newpa->addr)) { pfi_dynaddr_remove(&newpa->addr); - pfi_kif_unref(newpa->kif, PFI_KIF_REF_RULE); + pfi_detach_rule(newpa->kif); pool_put(&pf_pooladdr_pl, newpa); error = EINVAL; break; @@ -2178,7 +2600,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) TAILQ_REMOVE(&pool->list, oldpa, entries); pfi_dynaddr_remove(&oldpa->addr); pf_tbladdr_remove(&oldpa->addr); - pfi_kif_unref(oldpa->kif, PFI_KIF_REF_RULE); + pfi_detach_rule(oldpa->kif); pool_put(&pf_pooladdr_pl, oldpa); } else { if (oldpa == NULL) @@ -2388,7 +2810,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer, io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd, &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags | - PFR_FLAG_USERIOCTL, 0); + PFR_FLAG_USERIOCTL); break; } @@ -2468,203 +2890,171 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } case DIOCXBEGIN: { - struct pfioc_trans *io = (struct pfioc_trans *)addr; - struct pfioc_trans_e *ioe; - struct pfr_table *table; - int i; + struct pfioc_trans *io = (struct pfioc_trans *) + addr; + static struct pfioc_trans_e ioe; + static struct pfr_table table; + int i; - if (io->esize != sizeof(*ioe)) { + if (io->esize != sizeof(ioe)) { error = ENODEV; goto fail; } - ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe), - M_TEMP, M_WAITOK); - table = (struct pfr_table *)malloc(sizeof(*table), - M_TEMP, M_WAITOK); for (i = 0; i < io->size; i++) { - if (copyin(io->array+i, ioe, sizeof(*ioe))) { - free(table, M_TEMP); - free(ioe, M_TEMP); +#ifdef __FreeBSD__ + PF_COPYIN(io->array+i, &ioe, sizeof(ioe), error); + if (error) { +#else + if (copyin(io->array+i, &ioe, sizeof(ioe))) { +#endif error = EFAULT; goto fail; } - switch (ioe->rs_num) { + switch (ioe.rs_num) { #ifdef ALTQ case PF_RULESET_ALTQ: - if (ioe->anchor[0]) { - free(table, M_TEMP); - free(ioe, M_TEMP); + if (ioe.anchor[0]) { error = EINVAL; goto fail; } - if ((error = pf_begin_altq(&ioe->ticket))) { - free(table, M_TEMP); - free(ioe, M_TEMP); + if ((error = pf_begin_altq(&ioe.ticket))) goto fail; - } break; #endif /* ALTQ */ case PF_RULESET_TABLE: - bzero(table, sizeof(*table)); - strlcpy(table->pfrt_anchor, ioe->anchor, - sizeof(table->pfrt_anchor)); - if ((error = pfr_ina_begin(table, - &ioe->ticket, NULL, 0))) { - free(table, M_TEMP); - free(ioe, M_TEMP); + bzero(&table, sizeof(table)); + strlcpy(table.pfrt_anchor, ioe.anchor, + sizeof(table.pfrt_anchor)); + if ((error = pfr_ina_begin(&table, + &ioe.ticket, NULL, 0))) goto fail; - } break; default: - if ((error = pf_begin_rules(&ioe->ticket, - ioe->rs_num, ioe->anchor))) { - free(table, M_TEMP); - free(ioe, M_TEMP); + if ((error = pf_begin_rules(&ioe.ticket, + ioe.rs_num, ioe.anchor))) goto fail; - } break; } - if (copyout(ioe, io->array+i, sizeof(io->array[i]))) { - free(table, M_TEMP); - free(ioe, M_TEMP); +#ifdef __FreeBSD__ + PF_COPYOUT(&ioe, io->array+i, sizeof(io->array[i]), + error); + if (error) { +#else + if (copyout(&ioe, io->array+i, sizeof(io->array[i]))) { +#endif error = EFAULT; goto fail; } } - free(table, M_TEMP); - free(ioe, M_TEMP); break; } case DIOCXROLLBACK: { - struct pfioc_trans *io = (struct pfioc_trans *)addr; - struct pfioc_trans_e *ioe; - struct pfr_table *table; - int i; + struct pfioc_trans *io = (struct pfioc_trans *) + addr; + static struct pfioc_trans_e ioe; + static struct pfr_table table; + int i; - if (io->esize != sizeof(*ioe)) { + if (io->esize != sizeof(ioe)) { error = ENODEV; goto fail; } - ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe), - M_TEMP, M_WAITOK); - table = (struct pfr_table *)malloc(sizeof(*table), - M_TEMP, M_WAITOK); for (i = 0; i < io->size; i++) { - if (copyin(io->array+i, ioe, sizeof(*ioe))) { - free(table, M_TEMP); - free(ioe, M_TEMP); +#ifdef __FreeBSD__ + PF_COPYIN(io->array+i, &ioe, sizeof(ioe), error); + if (error) { +#else + if (copyin(io->array+i, &ioe, sizeof(ioe))) { +#endif error = EFAULT; goto fail; } - switch (ioe->rs_num) { + switch (ioe.rs_num) { #ifdef ALTQ case PF_RULESET_ALTQ: - if (ioe->anchor[0]) { - free(table, M_TEMP); - free(ioe, M_TEMP); + if (ioe.anchor[0]) { error = EINVAL; goto fail; } - if ((error = pf_rollback_altq(ioe->ticket))) { - free(table, M_TEMP); - free(ioe, M_TEMP); + if ((error = pf_rollback_altq(ioe.ticket))) goto fail; /* really bad */ - } break; #endif /* ALTQ */ case PF_RULESET_TABLE: - bzero(table, sizeof(*table)); - strlcpy(table->pfrt_anchor, ioe->anchor, - sizeof(table->pfrt_anchor)); - if ((error = pfr_ina_rollback(table, - ioe->ticket, NULL, 0))) { - free(table, M_TEMP); - free(ioe, M_TEMP); + bzero(&table, sizeof(table)); + strlcpy(table.pfrt_anchor, ioe.anchor, + sizeof(table.pfrt_anchor)); + if ((error = pfr_ina_rollback(&table, + ioe.ticket, NULL, 0))) goto fail; /* really bad */ - } break; default: - if ((error = pf_rollback_rules(ioe->ticket, - ioe->rs_num, ioe->anchor))) { - free(table, M_TEMP); - free(ioe, M_TEMP); + if ((error = pf_rollback_rules(ioe.ticket, + ioe.rs_num, ioe.anchor))) goto fail; /* really bad */ - } break; } } - free(table, M_TEMP); - free(ioe, M_TEMP); break; } case DIOCXCOMMIT: { - struct pfioc_trans *io = (struct pfioc_trans *)addr; - struct pfioc_trans_e *ioe; - struct pfr_table *table; - struct pf_ruleset *rs; - int i; - - if (io->esize != sizeof(*ioe)) { + struct pfioc_trans *io = (struct pfioc_trans *) + addr; + static struct pfioc_trans_e ioe; + static struct pfr_table table; + struct pf_ruleset *rs; + int i; + + if (io->esize != sizeof(ioe)) { error = ENODEV; goto fail; } - ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe), - M_TEMP, M_WAITOK); - table = (struct pfr_table *)malloc(sizeof(*table), - M_TEMP, M_WAITOK); /* first makes sure everything will succeed */ for (i = 0; i < io->size; i++) { - if (copyin(io->array+i, ioe, sizeof(*ioe))) { - free(table, M_TEMP); - free(ioe, M_TEMP); +#ifdef __FreeBSD__ + PF_COPYIN(io->array+i, &ioe, sizeof(ioe), error); + if (error) { +#else + if (copyin(io->array+i, &ioe, sizeof(ioe))) { +#endif error = EFAULT; goto fail; } - switch (ioe->rs_num) { + switch (ioe.rs_num) { #ifdef ALTQ case PF_RULESET_ALTQ: - if (ioe->anchor[0]) { - free(table, M_TEMP); - free(ioe, M_TEMP); + if (ioe.anchor[0]) { error = EINVAL; goto fail; } - if (!altqs_inactive_open || ioe->ticket != + if (!altqs_inactive_open || ioe.ticket != ticket_altqs_inactive) { - free(table, M_TEMP); - free(ioe, M_TEMP); error = EBUSY; goto fail; } break; #endif /* ALTQ */ case PF_RULESET_TABLE: - rs = pf_find_ruleset(ioe->anchor); - if (rs == NULL || !rs->topen || ioe->ticket != + rs = pf_find_ruleset(ioe.anchor); + if (rs == NULL || !rs->topen || ioe.ticket != rs->tticket) { - free(table, M_TEMP); - free(ioe, M_TEMP); error = EBUSY; goto fail; } break; default: - if (ioe->rs_num < 0 || ioe->rs_num >= + if (ioe.rs_num < 0 || ioe.rs_num >= PF_RULESET_MAX) { - free(table, M_TEMP); - free(ioe, M_TEMP); error = EINVAL; goto fail; } - rs = pf_find_ruleset(ioe->anchor); + rs = pf_find_ruleset(ioe.anchor); if (rs == NULL || - !rs->rules[ioe->rs_num].inactive.open || - rs->rules[ioe->rs_num].inactive.ticket != - ioe->ticket) { - free(table, M_TEMP); - free(ioe, M_TEMP); + !rs->rules[ioe.rs_num].inactive.open || + rs->rules[ioe.rs_num].inactive.ticket != + ioe.ticket) { error = EBUSY; goto fail; } @@ -2673,51 +3063,44 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } /* now do the commit - no errors should happen here */ for (i = 0; i < io->size; i++) { - if (copyin(io->array+i, ioe, sizeof(*ioe))) { - free(table, M_TEMP); - free(ioe, M_TEMP); +#ifdef __FreeBSD__ + PF_COPYIN(io->array+i, &ioe, sizeof(ioe), error); + if (error) { +#else + if (copyin(io->array+i, &ioe, sizeof(ioe))) { +#endif error = EFAULT; goto fail; } - switch (ioe->rs_num) { + switch (ioe.rs_num) { #ifdef ALTQ case PF_RULESET_ALTQ: - if ((error = pf_commit_altq(ioe->ticket))) { - free(table, M_TEMP); - free(ioe, M_TEMP); + if ((error = pf_commit_altq(ioe.ticket))) goto fail; /* really bad */ - } break; #endif /* ALTQ */ case PF_RULESET_TABLE: - bzero(table, sizeof(*table)); - strlcpy(table->pfrt_anchor, ioe->anchor, - sizeof(table->pfrt_anchor)); - if ((error = pfr_ina_commit(table, ioe->ticket, - NULL, NULL, 0))) { - free(table, M_TEMP); - free(ioe, M_TEMP); + bzero(&table, sizeof(table)); + strlcpy(table.pfrt_anchor, ioe.anchor, + sizeof(table.pfrt_anchor)); + if ((error = pfr_ina_commit(&table, ioe.ticket, + NULL, NULL, 0))) goto fail; /* really bad */ - } break; default: - if ((error = pf_commit_rules(ioe->ticket, - ioe->rs_num, ioe->anchor))) { - free(table, M_TEMP); - free(ioe, M_TEMP); + if ((error = pf_commit_rules(ioe.ticket, + ioe.rs_num, ioe.anchor))) goto fail; /* really bad */ - } break; } } - free(table, M_TEMP); - free(ioe, M_TEMP); break; } case DIOCGETSRCNODES: { struct pfioc_src_nodes *psn = (struct pfioc_src_nodes *)addr; - struct pf_src_node *n, *p, *pstore; + struct pf_src_node *n; + struct pf_src_node *p, pstore; u_int32_t nr = 0; int space = psn->psn_len; @@ -2728,8 +3111,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } - pstore = malloc(sizeof(*pstore), M_TEMP, M_WAITOK); - p = psn->psn_src_nodes; RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { int secs = time_second, diff; @@ -2737,35 +3118,35 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if ((nr + 1) * sizeof(*p) > (unsigned)psn->psn_len) break; - bcopy(n, pstore, sizeof(*pstore)); + bcopy(n, &pstore, sizeof(pstore)); if (n->rule.ptr != NULL) - pstore->rule.nr = n->rule.ptr->nr; - pstore->creation = secs - pstore->creation; - if (pstore->expire > secs) - pstore->expire -= secs; + pstore.rule.nr = n->rule.ptr->nr; + pstore.creation = secs - pstore.creation; + if (pstore.expire > secs) + pstore.expire -= secs; else - pstore->expire = 0; + pstore.expire = 0; /* adjust the connection rate estimate */ diff = secs - n->conn_rate.last; if (diff >= n->conn_rate.seconds) - pstore->conn_rate.count = 0; + pstore.conn_rate.count = 0; else - pstore->conn_rate.count -= + pstore.conn_rate.count -= n->conn_rate.count * diff / n->conn_rate.seconds; - error = copyout(pstore, p, sizeof(*p)); - if (error) { - free(pstore, M_TEMP); +#ifdef __FreeBSD__ + PF_COPYOUT(&pstore, p, sizeof(*p), error); +#else + error = copyout(&pstore, p, sizeof(*p)); +#endif + if (error) goto fail; - } p++; nr++; } psn->psn_len = sizeof(struct pf_src_node) * nr; - - free(pstore, M_TEMP); break; } @@ -2781,50 +3162,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) n->expire = 1; n->states = 0; } - pf_purge_expired_src_nodes(1); + pf_purge_expired_src_nodes(); pf_status.src_nodes = 0; break; } - case DIOCKILLSRCNODES: { - struct pf_src_node *sn; - struct pf_state *s; - struct pfioc_src_node_kill *psnk = \ - (struct pfioc_src_node_kill *) addr; - int killed = 0; - - RB_FOREACH(sn, pf_src_tree, &tree_src_tracking) { - if (PF_MATCHA(psnk->psnk_src.neg, \ - &psnk->psnk_src.addr.v.a.addr, \ - &psnk->psnk_src.addr.v.a.mask, \ - &sn->addr, sn->af) && - PF_MATCHA(psnk->psnk_dst.neg, \ - &psnk->psnk_dst.addr.v.a.addr, \ - &psnk->psnk_dst.addr.v.a.mask, \ - &sn->raddr, sn->af)) { - /* Handle state to src_node linkage */ - if (sn->states != 0) { - RB_FOREACH(s, pf_state_tree_id, - &tree_id) { - if (s->src_node == sn) - s->src_node = NULL; - if (s->nat_src_node == sn) - s->nat_src_node = NULL; - } - sn->states = 0; - } - sn->expire = 1; - killed++; - } - } - - if (killed > 0) - pf_purge_expired_src_nodes(1); - - psnk->psnk_af = killed; - break; - } - case DIOCSETHOSTID: { u_int32_t *hostid = (u_int32_t *)addr; @@ -2842,12 +3184,20 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCIGETIFACES: { struct pfioc_iface *io = (struct pfioc_iface *)addr; - if (io->pfiio_esize != sizeof(struct pfi_kif)) { + if (io->pfiio_esize != sizeof(struct pfi_if)) { error = ENODEV; break; } error = pfi_get_ifaces(io->pfiio_name, io->pfiio_buffer, - &io->pfiio_size); + &io->pfiio_size, io->pfiio_flags); + break; + } + + case DIOCICLRISTATS: { + struct pfioc_iface *io = (struct pfioc_iface *)addr; + + error = pfi_clr_istats(io->pfiio_name, &io->pfiio_nzero, + io->pfiio_flags); break; } @@ -2870,10 +3220,405 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } fail: +#ifdef __FreeBSD__ + PF_UNLOCK(); +#else splx(s); - if (flags & FWRITE) - rw_exit_write(&pf_consistency_lock); - else - rw_exit_read(&pf_consistency_lock); +#endif return (error); } + +#ifdef __FreeBSD__ +/* + * XXX - Check for version missmatch!!! + */ +static void +pf_clear_states(void) +{ + struct pf_state *state; + + RB_FOREACH(state, pf_state_tree_id, &tree_id) { + state->timeout = PFTM_PURGE; +#if NPFSYNC + /* don't send out individual delete messages */ + state->sync_flags = PFSTATE_NOSYNC; +#endif + } + pf_purge_expired_states(); + pf_status.states = 0; +#if 0 /* NPFSYNC */ +/* + * XXX This is called on module unload, we do not want to sync that over? */ + */ + pfsync_clear_states(pf_status.hostid, psk->psk_ifname); +#endif +} + +static int +pf_clear_tables(void) +{ + struct pfioc_table io; + int error; + + bzero(&io, sizeof(io)); + + error = pfr_clr_tables(&io.pfrio_table, &io.pfrio_ndel, + io.pfrio_flags); + + return (error); +} + +static void +pf_clear_srcnodes(void) +{ + struct pf_src_node *n; + struct pf_state *state; + + RB_FOREACH(state, pf_state_tree_id, &tree_id) { + state->src_node = NULL; + state->nat_src_node = NULL; + } + RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { + n->expire = 1; + n->states = 0; + } + pf_purge_expired_src_nodes(); + pf_status.src_nodes = 0; +} +/* + * XXX - Check for version missmatch!!! + */ + +/* + * Duplicate pfctl -Fa operation to get rid of as much as we can. + */ +static int +shutdown_pf(void) +{ + int error = 0; + u_int32_t t[5]; + char nn = '\0'; + + callout_stop(&pf_expire_to); + + pf_status.running = 0; + do { + if ((error = pf_begin_rules(&t[0], PF_RULESET_SCRUB, &nn)) + != 0) { + DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: SCRUB\n")); + break; + } + if ((error = pf_begin_rules(&t[1], PF_RULESET_FILTER, &nn)) + != 0) { + DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: FILTER\n")); + break; /* XXX: rollback? */ + } + if ((error = pf_begin_rules(&t[2], PF_RULESET_NAT, &nn)) + != 0) { + DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: NAT\n")); + break; /* XXX: rollback? */ + } + if ((error = pf_begin_rules(&t[3], PF_RULESET_BINAT, &nn)) + != 0) { + DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: BINAT\n")); + break; /* XXX: rollback? */ + } + if ((error = pf_begin_rules(&t[4], PF_RULESET_RDR, &nn)) + != 0) { + DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: RDR\n")); + break; /* XXX: rollback? */ + } + + /* XXX: these should always succeed here */ + pf_commit_rules(t[0], PF_RULESET_SCRUB, &nn); + pf_commit_rules(t[1], PF_RULESET_FILTER, &nn); + pf_commit_rules(t[2], PF_RULESET_NAT, &nn); + pf_commit_rules(t[3], PF_RULESET_BINAT, &nn); + pf_commit_rules(t[4], PF_RULESET_RDR, &nn); + + if ((error = pf_clear_tables()) != 0) + break; + +#ifdef ALTQ + if ((error = pf_begin_altq(&t[0])) != 0) { + DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: ALTQ\n")); + break; + } + pf_commit_altq(t[0]); +#endif + + pf_clear_states(); + + pf_clear_srcnodes(); + + /* status does not use malloced mem so no need to cleanup */ + /* fingerprints and interfaces have thier own cleanup code */ + } while(0); + + return (error); +} + +static int +pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, + struct inpcb *inp) +{ + /* + * XXX Wed Jul 9 22:03:16 2003 UTC + * OpenBSD has changed its byte ordering convention on ip_len/ip_off + * in network stack. OpenBSD's network stack have converted + * ip_len/ip_off to host byte order frist as FreeBSD. + * Now this is not true anymore , so we should convert back to network + * byte order. + */ + struct ip *h = NULL; + int chk; + + if ((*m)->m_pkthdr.len >= (int)sizeof(struct ip)) { + /* if m_pkthdr.len is less than ip header, pf will handle. */ + h = mtod(*m, struct ip *); + HTONS(h->ip_len); + HTONS(h->ip_off); + } + chk = pf_test(PF_IN, ifp, m, NULL, inp); + if (chk && *m) { + m_freem(*m); + *m = NULL; + } + if (*m != NULL) { + /* pf_test can change ip header location */ + h = mtod(*m, struct ip *); + NTOHS(h->ip_len); + NTOHS(h->ip_off); + } + return chk; +} + +static int +pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, + struct inpcb *inp) +{ + /* + * XXX Wed Jul 9 22:03:16 2003 UTC + * OpenBSD has changed its byte ordering convention on ip_len/ip_off + * in network stack. OpenBSD's network stack have converted + * ip_len/ip_off to host byte order frist as FreeBSD. + * Now this is not true anymore , so we should convert back to network + * byte order. + */ + struct ip *h = NULL; + int chk; + + /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */ + if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { + in_delayed_cksum(*m); + (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; + } + if ((*m)->m_pkthdr.len >= (int)sizeof(*h)) { + /* if m_pkthdr.len is less than ip header, pf will handle. */ + h = mtod(*m, struct ip *); + HTONS(h->ip_len); + HTONS(h->ip_off); + } + chk = pf_test(PF_OUT, ifp, m, NULL, inp); + if (chk && *m) { + m_freem(*m); + *m = NULL; + } + if (*m != NULL) { + /* pf_test can change ip header location */ + h = mtod(*m, struct ip *); + NTOHS(h->ip_len); + NTOHS(h->ip_off); + } + return chk; +} + +#ifdef INET6 +static int +pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, + struct inpcb *inp) +{ + /* + * IPv6 is not affected by ip_len/ip_off byte order changes. + */ + int chk; + + /* + * In case of loopback traffic IPv6 uses the real interface in + * order to support scoped addresses. In order to support stateful + * filtering we have change this to lo0 as it is the case in IPv4. + */ + chk = pf_test6(PF_IN, (*m)->m_flags & M_LOOP ? &loif[0] : ifp, m, + NULL, inp); + if (chk && *m) { + m_freem(*m); + *m = NULL; + } + return chk; +} + +static int +pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, + struct inpcb *inp) +{ + /* + * IPv6 does not affected ip_len/ip_off byte order changes. + */ + int chk; + + /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */ + if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { + in_delayed_cksum(*m); + (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; + } + chk = pf_test6(PF_OUT, ifp, m, NULL, inp); + if (chk && *m) { + m_freem(*m); + *m = NULL; + } + return chk; +} +#endif /* INET6 */ + +static int +hook_pf(void) +{ + struct pfil_head *pfh_inet; +#ifdef INET6 + struct pfil_head *pfh_inet6; +#endif + + PF_ASSERT(MA_NOTOWNED); + + if (pf_pfil_hooked) + return (0); + + pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); + if (pfh_inet == NULL) + return (ESRCH); /* XXX */ + pfil_add_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet); + pfil_add_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet); +#ifdef INET6 + pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); + if (pfh_inet6 == NULL) { + pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, + pfh_inet); + pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, + pfh_inet); + return (ESRCH); /* XXX */ + } + pfil_add_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6); + pfil_add_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6); +#endif + + pf_pfil_hooked = 1; + return (0); +} + +static int +dehook_pf(void) +{ + struct pfil_head *pfh_inet; +#ifdef INET6 + struct pfil_head *pfh_inet6; +#endif + + PF_ASSERT(MA_NOTOWNED); + + if (pf_pfil_hooked == 0) + return (0); + + pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); + if (pfh_inet == NULL) + return (ESRCH); /* XXX */ + pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, + pfh_inet); + pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, + pfh_inet); +#ifdef INET6 + pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); + if (pfh_inet6 == NULL) + return (ESRCH); /* XXX */ + pfil_remove_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, + pfh_inet6); + pfil_remove_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, + pfh_inet6); +#endif + + pf_pfil_hooked = 0; + return (0); +} + +static int +pf_load(void) +{ + init_zone_var(); + init_pf_mutex(); + pf_dev = make_dev(&pf_cdevsw, 0, 0, 0, 0600, PF_NAME); + if (pfattach() < 0) { + destroy_dev(pf_dev); + destroy_pf_mutex(); + return (ENOMEM); + } + return (0); +} + +static int +pf_unload(void) +{ + int error = 0; + + PF_LOCK(); + pf_status.running = 0; + PF_UNLOCK(); + error = dehook_pf(); + if (error) { + /* + * Should not happen! + * XXX Due to error code ESRCH, kldunload will show + * a message like 'No such process'. + */ + printf("%s : pfil unregisteration fail\n", __FUNCTION__); + return error; + } + PF_LOCK(); + shutdown_pf(); + pfi_cleanup(); + pf_osfp_flush(); + pf_osfp_cleanup(); + cleanup_pf_zone(); + PF_UNLOCK(); + destroy_dev(pf_dev); + destroy_pf_mutex(); + return error; +} + +static int +pf_modevent(module_t mod, int type, void *data) +{ + int error = 0; + + switch(type) { + case MOD_LOAD: + error = pf_load(); + break; + + case MOD_UNLOAD: + error = pf_unload(); + break; + default: + error = EINVAL; + break; + } + return error; +} + +static moduledata_t pf_mod = { + "pf", + pf_modevent, + 0 +}; + +DECLARE_MODULE(pf, pf_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_FIRST); +MODULE_VERSION(pf, PF_MODVER); +#endif /* __FreeBSD__ */ diff --git a/sys/contrib/pf/net/pf_norm.c b/sys/contrib/pf/net/pf_norm.c index df339ae..0153644 100644 --- a/sys/contrib/pf/net/pf_norm.c +++ b/sys/contrib/pf/net/pf_norm.c @@ -1,4 +1,6 @@ -/* $OpenBSD: pf_norm.c,v 1.107 2006/04/16 00:59:52 pascoe Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: pf_norm.c,v 1.97 2004/09/21 16:59:12 aaron Exp $ */ +/* add: $OpenBSD: pf_norm.c,v 1.106 2006/03/25 20:55:24 dhartmei Exp $ */ /* * Copyright 2001 Niels Provos <provos@citi.umich.edu> @@ -25,7 +27,18 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifdef __FreeBSD__ +#include "opt_inet.h" +#include "opt_inet6.h" +#include "opt_pf.h" +#ifdef DEV_PFLOG +#define NPFLOG DEV_PFLOG +#else +#define NPFLOG 0 +#endif +#else #include "pflog.h" +#endif #include <sys/param.h> #include <sys/systm.h> @@ -35,9 +48,11 @@ #include <sys/socket.h> #include <sys/kernel.h> #include <sys/time.h> +#ifndef __FreeBSD__ #include <sys/pool.h> #include <dev/rndvar.h> +#endif #include <net/if.h> #include <net/if_types.h> #include <net/bpf.h> @@ -60,6 +75,9 @@ #include <net/pfvar.h> +#ifndef __FreeBSD__ +#include <inttypes.h> + struct pf_frent { LIST_ENTRY(pf_frent) fr_next; struct ip *fr_ip; @@ -71,12 +89,14 @@ struct pf_frcache { uint16_t fr_off; uint16_t fr_end; }; +#endif #define PFFRAG_SEENLAST 0x0001 /* Seen the last fragment for this */ #define PFFRAG_NOBUFFER 0x0002 /* Non-buffering fragment cache */ #define PFFRAG_DROP 0x0004 /* Drop all fragments */ #define BUFFER_FRAGMENTS(fr) (!((fr)->fr_flags & PFFRAG_NOBUFFER)) +#ifndef __FreeBSD__ struct pf_fragment { RB_ENTRY(pf_fragment) fr_entry; TAILQ_ENTRY(pf_fragment) frag_next; @@ -94,12 +114,18 @@ struct pf_fragment { LIST_HEAD(pf_cacheq, pf_frcache) fru_cache; /* non-buf */ } fr_u; }; +#endif TAILQ_HEAD(pf_fragqueue, pf_fragment) pf_fragqueue; TAILQ_HEAD(pf_cachequeue, pf_fragment) pf_cachequeue; +#ifndef __FreeBSD__ static __inline int pf_frag_compare(struct pf_fragment *, struct pf_fragment *); +#else +static int pf_frag_compare(struct pf_fragment *, + struct pf_fragment *); +#endif RB_HEAD(pf_frag_tree, pf_fragment) pf_frag_tree, pf_cache_tree; RB_PROTOTYPE(pf_frag_tree, pf_fragment, fr_entry, pf_frag_compare); RB_GENERATE(pf_frag_tree, pf_fragment, fr_entry, pf_frag_compare); @@ -125,13 +151,28 @@ int pf_normalize_tcpopt(struct pf_rule *, struct mbuf *, } while(0) /* Globals */ +#ifdef __FreeBSD__ +uma_zone_t pf_frent_pl, pf_frag_pl, pf_cache_pl, pf_cent_pl; +uma_zone_t pf_state_scrub_pl; +#else struct pool pf_frent_pl, pf_frag_pl, pf_cache_pl, pf_cent_pl; struct pool pf_state_scrub_pl; +#endif int pf_nfrents, pf_ncache; void pf_normalize_init(void) { +#ifdef __FreeBSD__ + /* + * XXX + * No high water mark support(It's hint not hard limit). + * uma_zone_set_max(pf_frag_pl, PFFRAG_FRAG_HIWAT); + */ + uma_zone_set_max(pf_frent_pl, PFFRAG_FRENT_HIWAT); + uma_zone_set_max(pf_cache_pl, PFFRAG_FRCACHE_HIWAT); + uma_zone_set_max(pf_cent_pl, PFFRAG_FRCENT_HIWAT); +#else pool_init(&pf_frent_pl, sizeof(struct pf_frent), 0, 0, 0, "pffrent", NULL); pool_init(&pf_frag_pl, sizeof(struct pf_fragment), 0, 0, 0, "pffrag", @@ -147,12 +188,17 @@ pf_normalize_init(void) pool_sethardlimit(&pf_frent_pl, PFFRAG_FRENT_HIWAT, NULL, 0); pool_sethardlimit(&pf_cache_pl, PFFRAG_FRCACHE_HIWAT, NULL, 0); pool_sethardlimit(&pf_cent_pl, PFFRAG_FRCENT_HIWAT, NULL, 0); +#endif TAILQ_INIT(&pf_fragqueue); TAILQ_INIT(&pf_cachequeue); } +#ifdef __FreeBSD__ +static int +#else static __inline int +#endif pf_frag_compare(struct pf_fragment *a, struct pf_fragment *b) { int diff; @@ -180,7 +226,12 @@ pf_purge_expired_fragments(void) pf_default_rule.timeout[PFTM_FRAG]; while ((frag = TAILQ_LAST(&pf_fragqueue, pf_fragqueue)) != NULL) { +#ifdef __FreeBSD__ + KASSERT((BUFFER_FRAGMENTS(frag)), + ("BUFFER_FRAGMENTS(frag) == 0: %s", __FUNCTION__)); +#else KASSERT(BUFFER_FRAGMENTS(frag)); +#endif if (frag->fr_timeout > expire) break; @@ -189,14 +240,26 @@ pf_purge_expired_fragments(void) } while ((frag = TAILQ_LAST(&pf_cachequeue, pf_cachequeue)) != NULL) { +#ifdef __FreeBSD__ + KASSERT((!BUFFER_FRAGMENTS(frag)), + ("BUFFER_FRAGMENTS(frag) != 0: %s", __FUNCTION__)); +#else KASSERT(!BUFFER_FRAGMENTS(frag)); +#endif if (frag->fr_timeout > expire) break; DPFPRINTF(("expiring %d(%p)\n", frag->fr_id, frag)); pf_free_fragment(frag); +#ifdef __FreeBSD__ + KASSERT((TAILQ_EMPTY(&pf_cachequeue) || + TAILQ_LAST(&pf_cachequeue, pf_cachequeue) != frag), + ("!(TAILQ_EMPTY() || TAILQ_LAST() == farg): %s", + __FUNCTION__)); +#else KASSERT(TAILQ_EMPTY(&pf_cachequeue) || TAILQ_LAST(&pf_cachequeue, pf_cachequeue) != frag); +#endif } } @@ -255,9 +318,17 @@ pf_free_fragment(struct pf_fragment *frag) frcache = LIST_FIRST(&frag->fr_cache)) { LIST_REMOVE(frcache, fr_next); +#ifdef __FreeBSD__ + KASSERT((LIST_EMPTY(&frag->fr_cache) || + LIST_FIRST(&frag->fr_cache)->fr_off > + frcache->fr_end), + ("! (LIST_EMPTY() || LIST_FIRST()->fr_off >" + " frcache->fr_end): %s", __FUNCTION__)); +#else KASSERT(LIST_EMPTY(&frag->fr_cache) || LIST_FIRST(&frag->fr_cache)->fr_off > frcache->fr_end); +#endif pool_put(&pf_cent_pl, frcache); pf_ncache--; @@ -330,7 +401,12 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag, u_int16_t ip_len = ntohs(ip->ip_len) - ip->ip_hl * 4; u_int16_t max = ip_len + off; +#ifdef __FreeBSD__ + KASSERT((*frag == NULL || BUFFER_FRAGMENTS(*frag)), + ("! (*frag == NULL || BUFFER_FRAGMENTS(*frag)): %s", __FUNCTION__)); +#else KASSERT(*frag == NULL || BUFFER_FRAGMENTS(*frag)); +#endif /* Strip off ip header */ m->m_data += hlen; @@ -373,7 +449,12 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag, frep = frea; } +#ifdef __FreeBSD__ + KASSERT((frep != NULL || frea != NULL), + ("!(frep != NULL || frea != NULL): %s", __FUNCTION__));; +#else KASSERT(frep != NULL || frea != NULL); +#endif if (frep != NULL && FR_IP_OFF(frep) + ntohs(frep->fr_ip->ip_len) - frep->fr_ip->ip_hl * @@ -412,7 +493,7 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag, break; } - /* This fragment is completely overlapped, lose it */ + /* This fragment is completely overlapped, loose it */ next = LIST_NEXT(frea, fr_next); m_freem(frea->fr_m); LIST_REMOVE(frea, fr_next); @@ -458,7 +539,11 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag, /* We have all the data */ frent = LIST_FIRST(&(*frag)->fr_queue); +#ifdef __FreeBSD__ + KASSERT((frent != NULL), ("frent == NULL: %s", __FUNCTION__)); +#else KASSERT(frent != NULL); +#endif if ((frent->fr_ip->ip_hl << 2) + off > IP_MAXPACKET) { DPFPRINTF(("drop: too big: %d\n", off)); pf_free_fragment(*frag); @@ -481,8 +566,17 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag, m2 = frent->fr_m; pool_put(&pf_frent_pl, frent); pf_nfrents--; +#ifdef __FreeBSD__ + m->m_pkthdr.csum_flags &= m2->m_pkthdr.csum_flags; + m->m_pkthdr.csum_data += m2->m_pkthdr.csum_data; +#endif m_cat(m, m2); } +#ifdef __FreeBSD__ + while (m->m_pkthdr.csum_data & 0xffff0000) + m->m_pkthdr.csum_data = (m->m_pkthdr.csum_data & 0xffff) + + (m->m_pkthdr.csum_data >> 16); +#endif ip->ip_src = (*frag)->fr_src; ip->ip_dst = (*frag)->fr_dst; @@ -527,7 +621,12 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff, u_int16_t max = ip_len + off; int hosed = 0; +#ifdef __FreeBSD__ + KASSERT((*frag == NULL || !BUFFER_FRAGMENTS(*frag)), + ("!(*frag == NULL || !BUFFER_FRAGMENTS(*frag)): %s", __FUNCTION__)); +#else KASSERT(*frag == NULL || !BUFFER_FRAGMENTS(*frag)); +#endif /* Create a new range queue for this packet */ if (*frag == NULL) { @@ -580,7 +679,12 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff, frp = fra; } +#ifdef __FreeBSD__ + KASSERT((frp != NULL || fra != NULL), + ("!(frp != NULL || fra != NULL): %s", __FUNCTION__)); +#else KASSERT(frp != NULL || fra != NULL); +#endif if (frp != NULL) { int precut; @@ -622,10 +726,24 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff, * than this mbuf magic. For my next trick, * I'll pull a rabbit out of my laptop. */ +#ifdef __FreeBSD__ + *m0 = m_dup(m, M_DONTWAIT); +#else *m0 = m_copym2(m, 0, h->ip_hl << 2, M_NOWAIT); +#endif if (*m0 == NULL) goto no_mem; +#ifdef __FreeBSD__ + /* From KAME Project : We have missed this! */ + m_adj(*m0, (h->ip_hl << 2) - + (*m0)->m_pkthdr.len); + + KASSERT(((*m0)->m_next == NULL), + ("(*m0)->m_next != NULL: %s", + __FUNCTION__)); +#else KASSERT((*m0)->m_next == NULL); +#endif m_adj(m, precut + (h->ip_hl << 2)); m_cat(*m0, m); m = *m0; @@ -640,9 +758,15 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff, h = mtod(m, struct ip *); - +#ifdef __FreeBSD__ + KASSERT(((int)m->m_len == + ntohs(h->ip_len) - precut), + ("m->m_len != ntohs(h->ip_len) - precut: %s", + __FUNCTION__)); +#else KASSERT((int)m->m_len == ntohs(h->ip_len) - precut); +#endif h->ip_off = htons(ntohs(h->ip_off) + (precut >> 3)); h->ip_len = htons(ntohs(h->ip_len) - precut); @@ -698,8 +822,14 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff, m->m_pkthdr.len = plen; } h = mtod(m, struct ip *); +#ifdef __FreeBSD__ + KASSERT(((int)m->m_len == ntohs(h->ip_len) - aftercut), + ("m->m_len != ntohs(h->ip_len) - aftercut: %s", + __FUNCTION__)); +#else KASSERT((int)m->m_len == ntohs(h->ip_len) - aftercut); +#endif h->ip_len = htons(ntohs(h->ip_len) - aftercut); } else { hosed++; @@ -737,7 +867,12 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff, } else if (frp && fra->fr_off <= frp->fr_end) { /* Need to merge in a modified 'frp' */ +#ifdef __FreeBSD__ + KASSERT((cur == NULL), ("cur != NULL: %s", + __FUNCTION__)); +#else KASSERT(cur == NULL); +#endif DPFPRINTF(("fragcache[%d]: adjacent(merge " "%d-%d) %d-%d (%d-%d)\n", h->ip_id, frp->fr_off, frp->fr_end, off, @@ -831,7 +966,8 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason, r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr); while (r != NULL) { r->evaluations++; - if (pfi_kif_match(r->kif, kif) == r->ifnot) + if (r->kif != NULL && + (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != dir) r = r->skip[PF_SKIP_DIR].ptr; @@ -840,23 +976,19 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason, else if (r->proto && r->proto != h->ip_p) r = r->skip[PF_SKIP_PROTO].ptr; else if (PF_MISMATCHAW(&r->src.addr, - (struct pf_addr *)&h->ip_src.s_addr, AF_INET, - r->src.neg, kif)) + (struct pf_addr *)&h->ip_src.s_addr, AF_INET, r->src.neg)) r = r->skip[PF_SKIP_SRC_ADDR].ptr; else if (PF_MISMATCHAW(&r->dst.addr, - (struct pf_addr *)&h->ip_dst.s_addr, AF_INET, - r->dst.neg, NULL)) + (struct pf_addr *)&h->ip_dst.s_addr, AF_INET, r->dst.neg)) r = r->skip[PF_SKIP_DST_ADDR].ptr; else break; } - if (r == NULL || r->action == PF_NOSCRUB) + if (r == NULL) return (PF_PASS); - else { - r->packets[dir == PF_OUT]++; - r->bytes[dir == PF_OUT] += pd->tot_len; - } + else + r->packets++; /* Check for illegal packets */ if (hlen < (int)sizeof(struct ip)) @@ -929,18 +1061,6 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason, if (m == NULL) return (PF_DROP); - /* use mtag from concatenated mbuf chain */ - pd->pf_mtag = pf_find_mtag(m); -#ifdef DIAGNOSTIC - if (pd->pf_mtag == NULL) { - printf("%s: pf_find_mtag returned NULL(1)\n", __func__); - if ((pd->pf_mtag = pf_get_mtag(m)) == NULL) { - m_freem(m); - *m0 = NULL; - goto no_mem; - } - } -#endif if (frag != NULL && (frag->fr_flags & PFFRAG_DROP)) goto drop; @@ -949,13 +1069,15 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason, /* non-buffering fragment cache (drops or masks overlaps) */ int nomem = 0; - if (dir == PF_OUT && pd->pf_mtag->flags & PF_TAG_FRAGCACHE) { - /* - * Already passed the fragment cache in the - * input direction. If we continued, it would - * appear to be a dup and would be dropped. - */ - goto fragment_pass; + if (dir == PF_OUT) { + if (m_tag_find(m, PACKET_TAG_PF_FRAGCACHE, NULL) != + NULL) { + /* Already passed the fragment cache in the + * input direction. If we continued, it would + * appear to be a dup and would be dropped. + */ + goto fragment_pass; + } } frag = pf_find_fragment(h, &pf_cache_tree); @@ -976,21 +1098,14 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason, goto drop; } - /* use mtag from copied and trimmed mbuf chain */ - pd->pf_mtag = pf_find_mtag(m); -#ifdef DIAGNOSTIC - if (pd->pf_mtag == NULL) { - printf("%s: pf_find_mtag returned NULL(2)\n", __func__); - if ((pd->pf_mtag = pf_get_mtag(m)) == NULL) { - m_freem(m); - *m0 = NULL; + if (dir == PF_IN) { + struct m_tag *mtag; + + mtag = m_tag_get(PACKET_TAG_PF_FRAGCACHE, 0, M_NOWAIT); + if (mtag == NULL) goto no_mem; - } + m_tag_prepend(m, mtag); } -#endif - if (dir == PF_IN) - pd->pf_mtag->flags |= PF_TAG_FRAGCACHE; - if (frag != NULL && (frag->fr_flags & PFFRAG_DROP)) goto drop; goto fragment_pass; @@ -1039,13 +1154,13 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason, no_mem: REASON_SET(reason, PFRES_MEMORY); if (r != NULL && r->log) - PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL, pd); + PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL); return (PF_DROP); drop: REASON_SET(reason, PFRES_NORM); if (r != NULL && r->log) - PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL, pd); + PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL); return (PF_DROP); bad: @@ -1057,7 +1172,7 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason, REASON_SET(reason, PFRES_FRAG); if (r != NULL && r->log) - PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL, pd); + PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL); return (PF_DROP); } @@ -1085,7 +1200,8 @@ pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif, r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr); while (r != NULL) { r->evaluations++; - if (pfi_kif_match(r->kif, kif) == r->ifnot) + if (r->kif != NULL && + (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != dir) r = r->skip[PF_SKIP_DIR].ptr; @@ -1096,23 +1212,19 @@ pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif, r = r->skip[PF_SKIP_PROTO].ptr; #endif else if (PF_MISMATCHAW(&r->src.addr, - (struct pf_addr *)&h->ip6_src, AF_INET6, - r->src.neg, kif)) + (struct pf_addr *)&h->ip6_src, AF_INET6, r->src.neg)) r = r->skip[PF_SKIP_SRC_ADDR].ptr; else if (PF_MISMATCHAW(&r->dst.addr, - (struct pf_addr *)&h->ip6_dst, AF_INET6, - r->dst.neg, NULL)) + (struct pf_addr *)&h->ip6_dst, AF_INET6, r->dst.neg)) r = r->skip[PF_SKIP_DST_ADDR].ptr; else break; } - if (r == NULL || r->action == PF_NOSCRUB) + if (r == NULL) return (PF_PASS); - else { - r->packets[dir == PF_OUT]++; - r->bytes[dir == PF_OUT] += pd->tot_len; - } + else + r->packets++; /* Check for illegal packets */ if (sizeof(struct ip6_hdr) + IPV6_MAXPACKET < m->m_pkthdr.len) @@ -1224,19 +1336,19 @@ pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif, shortpkt: REASON_SET(reason, PFRES_SHORT); if (r != NULL && r->log) - PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL, pd); + PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL); return (PF_DROP); drop: REASON_SET(reason, PFRES_NORM); if (r != NULL && r->log) - PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL, pd); + PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL); return (PF_DROP); badfrag: REASON_SET(reason, PFRES_FRAG); if (r != NULL && r->log) - PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL, pd); + PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL); return (PF_DROP); } #endif /* INET6 */ @@ -1255,7 +1367,8 @@ pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff, r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr); while (r != NULL) { r->evaluations++; - if (pfi_kif_match(r->kif, kif) == r->ifnot) + if (r->kif != NULL && + (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != dir) r = r->skip[PF_SKIP_DIR].ptr; @@ -1263,14 +1376,12 @@ pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff, r = r->skip[PF_SKIP_AF].ptr; else if (r->proto && r->proto != pd->proto) r = r->skip[PF_SKIP_PROTO].ptr; - else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, - r->src.neg, kif)) + else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg)) r = r->skip[PF_SKIP_SRC_ADDR].ptr; else if (r->src.port_op && !pf_match_port(r->src.port_op, r->src.port[0], r->src.port[1], th->th_sport)) r = r->skip[PF_SKIP_SRC_PORT].ptr; - else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, - r->dst.neg, NULL)) + else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg)) r = r->skip[PF_SKIP_DST_ADDR].ptr; else if (r->dst.port_op && !pf_match_port(r->dst.port_op, r->dst.port[0], r->dst.port[1], th->th_dport)) @@ -1287,10 +1398,8 @@ pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff, if (rm == NULL || rm->action == PF_NOSCRUB) return (PF_PASS); - else { - r->packets[dir == PF_OUT]++; - r->bytes[dir == PF_OUT] += pd->tot_len; - } + else + r->packets++; if (rm->rule_flag & PFRULE_REASSEMBLE_TCP) pd->flags |= PFDESC_TCP_NORM; @@ -1345,14 +1454,14 @@ pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff, /* copy back packet headers if we sanitized */ if (rewrite) - m_copyback(m, off, sizeof(*th), th); + m_copyback(m, off, sizeof(*th), (caddr_t)th); return (PF_PASS); tcp_drop: REASON_SET(&reason, PFRES_NORM); if (rm != NULL && r->log) - PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, r, NULL, NULL, pd); + PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, r, NULL, NULL); return (PF_DROP); } @@ -1364,7 +1473,12 @@ pf_normalize_tcp_init(struct mbuf *m, int off, struct pf_pdesc *pd, u_int8_t hdr[60]; u_int8_t *opt; +#ifdef __FreeBSD__ + KASSERT((src->scrub == NULL), + ("pf_normalize_tcp_init: src->scrub != NULL")); +#else KASSERT(src->scrub == NULL); +#endif src->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT); if (src->scrub == NULL) @@ -1463,7 +1577,12 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, int copyback = 0; int got_ts = 0; +#ifdef __FreeBSD__ + KASSERT((src->scrub || dst->scrub), + ("pf_normalize_tcp_statefull: src->scrub && dst->scrub!")); +#else KASSERT(src->scrub || dst->scrub); +#endif /* * Enforce the minimum TTL seen for this connection. Negate a common @@ -1687,6 +1806,19 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, /* Calculate max ticks since the last timestamp */ #define TS_MAXFREQ 1100 /* RFC max TS freq of 1Khz + 10% skew */ #define TS_MICROSECS 1000000 /* microseconds per second */ +#ifdef __FreeBSD__ +#ifndef timersub +#define timersub(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) +#endif +#endif timersub(&uptime, &src->scrub->pfss_last, &delta_ts); tsval_from_last = (delta_ts.tv_sec + ts_fudge) * TS_MAXFREQ; tsval_from_last += delta_ts.tv_usec / (TS_MICROSECS/TS_MAXFREQ); @@ -1711,6 +1843,18 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, tsval_from_last) ? '1' : ' ', SEQ_GT(tsecr, dst->scrub->pfss_tsval) ? '2' : ' ', SEQ_LT(tsecr, dst->scrub->pfss_tsval0)? '3' : ' ')); +#ifdef __FreeBSD__ + DPFPRINTF((" tsval: %u tsecr: %u +ticks: %u " + "idle: %jus %lums\n", + tsval, tsecr, tsval_from_last, + (uintmax_t)delta_ts.tv_sec, + delta_ts.tv_usec / 1000)); + DPFPRINTF((" src->tsval: %u tsecr: %u\n", + src->scrub->pfss_tsval, src->scrub->pfss_tsecr)); + DPFPRINTF((" dst->tsval: %u tsecr: %u tsval0: %u" + "\n", dst->scrub->pfss_tsval, + dst->scrub->pfss_tsecr, dst->scrub->pfss_tsval0)); +#else DPFPRINTF((" tsval: %lu tsecr: %lu +ticks: %lu " "idle: %lus %lums\n", tsval, tsecr, tsval_from_last, delta_ts.tv_sec, @@ -1720,6 +1864,7 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, DPFPRINTF((" dst->tsval: %lu tsecr: %lu tsval0: %lu" "\n", dst->scrub->pfss_tsval, dst->scrub->pfss_tsecr, dst->scrub->pfss_tsval0)); +#endif if (pf_status.debug >= PF_DEBUG_MISC) { pf_print_state(state); pf_print_flags(th->th_flags); @@ -1786,7 +1931,7 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, * timestamps. And require all data packets to contain a timestamp * if the first does. PAWS implicitly requires that all data packets be * timestamped. But I think there are middle-man devices that hijack - * TCP streams immediately after the 3whs and don't timestamp their + * TCP streams immedietly after the 3whs and don't timestamp their * packets (seen in a WWW accelerator or cache). */ if (pd->p_len > 0 && src->scrub && (src->scrub->pfss_flags & diff --git a/sys/contrib/pf/net/pf_osfp.c b/sys/contrib/pf/net/pf_osfp.c index 15dca8e..ce1efee 100644 --- a/sys/contrib/pf/net/pf_osfp.c +++ b/sys/contrib/pf/net/pf_osfp.c @@ -1,4 +1,5 @@ -/* $OpenBSD: pf_osfp.c,v 1.12 2006/12/13 18:14:10 itojun Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: pf_osfp.c,v 1.10 2004/04/09 19:30:41 frantzen Exp $ */ /* * Copyright (c) 2003 Mike Frantzen <frantzen@w4g.org> @@ -32,17 +33,19 @@ #include <net/if.h> #include <net/pfvar.h> +#ifdef INET6 #include <netinet/ip6.h> -#ifdef _KERNEL -#include <netinet6/in6_var.h> -#endif - +#endif /* INET6 */ #ifdef _KERNEL # define DPFPRINTF(format, x...) \ if (pf_status.debug >= PF_DEBUG_NOISY) \ printf(format , ##x) +#ifdef __FreeBSD__ +typedef uma_zone_t pool_t; +#else typedef struct pool pool_t; +#endif #else /* Userland equivalents so we can lend code to tcpdump et al. */ @@ -52,12 +55,15 @@ typedef struct pool pool_t; # include <stdio.h> # include <stdlib.h> # include <string.h> -# include <netdb.h> # define pool_t int # define pool_get(pool, flags) malloc(*(pool)) # define pool_put(pool, item) free(item) # define pool_init(pool, size, a, ao, f, m, p) (*(pool)) = (size) +# ifdef __FreeBSD__ +# define NTOHS(x) (x) = ntohs((u_int16_t)(x)) +# endif + # ifdef PFDEBUG # include <sys/stdarg.h> # define DPFPRINTF(format, x...) fprintf(stderr, format , ##x) @@ -89,96 +95,38 @@ pf_osfp_fingerprint(struct pf_pdesc *pd, struct mbuf *m, int off, const struct tcphdr *tcp) { struct ip *ip; - struct ip6_hdr *ip6; char hdr[60]; - if ((pd->af != PF_INET && pd->af != PF_INET6) || - pd->proto != IPPROTO_TCP || (tcp->th_off << 2) < sizeof(*tcp)) + /* XXX don't have a fingerprint database for IPv6 :-( */ + if (pd->af != PF_INET || pd->proto != IPPROTO_TCP || (tcp->th_off << 2) + < sizeof(*tcp)) return (NULL); - if (pd->af == PF_INET) { - ip = mtod(m, struct ip *); - ip6 = (struct ip6_hdr *)NULL; - } else { - ip = (struct ip *)NULL; - ip6 = mtod(m, struct ip6_hdr *); - } - if (!pf_pull_hdr(m, off, hdr, tcp->th_off << 2, NULL, NULL, - pd->af)) return (NULL); + ip = mtod(m, struct ip *); + if (!pf_pull_hdr(m, off, hdr, tcp->th_off << 2, NULL, NULL, pd->af)) + return (NULL); - return (pf_osfp_fingerprint_hdr(ip, ip6, (struct tcphdr *)hdr)); + return (pf_osfp_fingerprint_hdr(ip, (struct tcphdr *)hdr)); } #endif /* _KERNEL */ struct pf_osfp_enlist * -pf_osfp_fingerprint_hdr(const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcp) +pf_osfp_fingerprint_hdr(const struct ip *ip, const struct tcphdr *tcp) { struct pf_os_fingerprint fp, *fpresult; int cnt, optlen = 0; const u_int8_t *optp; -#ifdef _KERNEL - char srcname[128]; -#else - char srcname[NI_MAXHOST]; -#endif - if ((tcp->th_flags & (TH_SYN|TH_ACK)) != TH_SYN) + if ((tcp->th_flags & (TH_SYN|TH_ACK)) != TH_SYN || (ip->ip_off & + htons(IP_OFFMASK))) return (NULL); - if (ip) { - if ((ip->ip_off & htons(IP_OFFMASK)) != 0) - return (NULL); - } memset(&fp, 0, sizeof(fp)); - if (ip) { -#ifndef _KERNEL - struct sockaddr_in sin; -#endif - - fp.fp_psize = ntohs(ip->ip_len); - fp.fp_ttl = ip->ip_ttl; - if (ip->ip_off & htons(IP_DF)) - fp.fp_flags |= PF_OSFP_DF; -#ifdef _KERNEL - strlcpy(srcname, inet_ntoa(ip->ip_src), sizeof(srcname)); -#else - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_len = sizeof(struct sockaddr_in); - sin.sin_addr = ip->ip_src; - (void)getnameinfo((struct sockaddr *)&sin, - sizeof(struct sockaddr_in), srcname, sizeof(srcname), - NULL, 0, NI_NUMERICHOST); -#endif - } -#ifdef INET6 - else if (ip6) { -#ifndef _KERNEL - struct sockaddr_in6 sin6; -#endif - - /* jumbo payload? */ - fp.fp_psize = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen); - fp.fp_ttl = ip6->ip6_hlim; + fp.fp_psize = ntohs(ip->ip_len); + fp.fp_ttl = ip->ip_ttl; + if (ip->ip_off & htons(IP_DF)) fp.fp_flags |= PF_OSFP_DF; - fp.fp_flags |= PF_OSFP_INET6; -#ifdef _KERNEL - strlcpy(srcname, ip6_sprintf((struct in6_addr *)&ip6->ip6_src), - sizeof(srcname)); -#else - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_family = AF_INET6; - sin6.sin6_len = sizeof(struct sockaddr_in6); - sin6.sin6_addr = ip6->ip6_src; - (void)getnameinfo((struct sockaddr *)&sin6, - sizeof(struct sockaddr_in6), srcname, sizeof(srcname), - NULL, 0, NI_NUMERICHOST); -#endif - } -#endif - else - return (NULL); fp.fp_wsize = ntohs(tcp->th_win); @@ -241,7 +189,7 @@ pf_osfp_fingerprint_hdr(const struct ip *ip, const struct ip6_hdr *ip6, const st DPFPRINTF("fingerprinted %s:%d %d:%d:%d:%d:%llx (%d) " "(TS=%s,M=%s%d,W=%s%d)\n", - srcname, ntohs(tcp->th_sport), + inet_ntoa(ip->ip_src), ntohs(tcp->th_sport), fp.fp_wsize, fp.fp_ttl, (fp.fp_flags & PF_OSFP_DF) != 0, fp.fp_psize, (long long int)fp.fp_tcpopts, fp.fp_optcnt, (fp.fp_flags & PF_OSFP_TS0) ? "0" : "", @@ -289,16 +237,47 @@ pf_osfp_match(struct pf_osfp_enlist *list, pf_osfp_t os) } /* Initialize the OS fingerprint system */ +#ifdef __FreeBSD__ +int +#else void +#endif pf_osfp_initialize(void) { +#if defined(__FreeBSD__) && defined(_KERNEL) + int error = ENOMEM; + + do { + pf_osfp_entry_pl = pf_osfp_pl = NULL; + UMA_CREATE(pf_osfp_entry_pl, struct pf_osfp_entry, "pfospfen"); + UMA_CREATE(pf_osfp_pl, struct pf_os_fingerprint, "pfosfp"); + error = 0; + } while(0); +#else pool_init(&pf_osfp_entry_pl, sizeof(struct pf_osfp_entry), 0, 0, 0, "pfosfpen", &pool_allocator_nointr); pool_init(&pf_osfp_pl, sizeof(struct pf_os_fingerprint), 0, 0, 0, "pfosfp", &pool_allocator_nointr); +#endif SLIST_INIT(&pf_osfp_list); +#ifdef __FreeBSD__ +#ifdef _KERNEL + return (error); +#else + return (0); +#endif +#endif } +#if defined(__FreeBSD__) && (_KERNEL) +void +pf_osfp_cleanup(void) +{ + UMA_DESTROY(pf_osfp_entry_pl); + UMA_DESTROY(pf_osfp_pl); +} +#endif + /* Flush the fingerprint list */ void pf_osfp_flush(void) diff --git a/sys/contrib/pf/net/pf_subr.c b/sys/contrib/pf/net/pf_subr.c new file mode 100644 index 0000000..3de2924 --- /dev/null +++ b/sys/contrib/pf/net/pf_subr.c @@ -0,0 +1,127 @@ +/* $FreeBSD$ */ +/* from $OpenBSD: kern_subr.c,v 1.26 2003/10/31 11:10:41 markus Exp $ */ +/* $NetBSD: kern_subr.c,v 1.15 1996/04/09 17:21:56 ragge Exp $ */ + +/* + * Copyright (c) 1982, 1986, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)kern_subr.c 8.3 (Berkeley) 1/21/94 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/queue.h> +#include <sys/kernel.h> +#include <sys/resourcevar.h> + +#include <net/if.h> + +#include <netinet/in.h> +#include <netinet/in_var.h> + +#include <net/pfvar.h> + +/* + * This implements additional functions used by pf which can not be ported + * easyly. At this point it boils down to mostly the Net/OpenBSD hook + * implementation. + * + * BEWARE: this is not locked! Required locking is done by the caller. + */ + +void * +hook_establish(struct hook_desc_head *head, int tail, void (*fn)(void *), + void *arg) +{ + struct hook_desc *hdp; + + hdp = (struct hook_desc *)malloc(sizeof (*hdp), M_DEVBUF, M_NOWAIT); + if (hdp == NULL) + return (NULL); + + hdp->hd_fn = fn; + hdp->hd_arg = arg; + if (tail) + TAILQ_INSERT_TAIL(head, hdp, hd_list); + else + TAILQ_INSERT_HEAD(head, hdp, hd_list); + + return (hdp); +} + +void +hook_disestablish(struct hook_desc_head *head, void *vhook) +{ + struct hook_desc *hdp; + +#ifdef DIAGNOSTIC + for (hdp = TAILQ_FIRST(head); hdp != NULL; + hdp = TAILQ_NEXT(hdp, hd_list)) + if (hdp == vhook) + break; + if (hdp == NULL) + panic("hook_disestablish: hook not established"); +#endif + hdp = vhook; + TAILQ_REMOVE(head, hdp, hd_list); + free(hdp, M_DEVBUF); +} + +/* + * Run hooks. Startup hooks are invoked right after scheduler_start but + * before root is mounted. Shutdown hooks are invoked immediately before the + * system is halted or rebooted, i.e. after file systems unmounted, + * after crash dump done, etc. + */ +void +dohooks(struct hook_desc_head *head, int flags) +{ + struct hook_desc *hdp; + + if ((flags & HOOK_REMOVE) == 0) { + TAILQ_FOREACH(hdp, head, hd_list) { + (*hdp->hd_fn)(hdp->hd_arg); + } + } else { + while ((hdp = TAILQ_FIRST(head)) != NULL) { + TAILQ_REMOVE(head, hdp, hd_list); + (*hdp->hd_fn)(hdp->hd_arg); + if ((flags & HOOK_FREE) != 0) + free(hdp, M_DEVBUF); + } + } +} diff --git a/sys/contrib/pf/net/pf_table.c b/sys/contrib/pf/net/pf_table.c index a79ed37..033616e 100644 --- a/sys/contrib/pf/net/pf_table.c +++ b/sys/contrib/pf/net/pf_table.c @@ -1,4 +1,5 @@ -/* $OpenBSD: pf_table.c,v 1.68 2006/05/02 10:08:45 dhartmei Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: pf_table.c,v 1.62 2004/12/07 18:02:04 mcbride Exp $ */ /* * Copyright (c) 2002 Cedric Berger @@ -30,16 +31,27 @@ * */ +#ifdef __FreeBSD__ +#include "opt_inet.h" +#include "opt_inet6.h" +#endif + #include <sys/param.h> #include <sys/systm.h> #include <sys/socket.h> #include <sys/mbuf.h> #include <sys/kernel.h> +#ifdef __FreeBSD__ +#include <sys/malloc.h> +#endif #include <net/if.h> #include <net/route.h> #include <netinet/in.h> +#ifndef __FreeBSD__ #include <netinet/ip_ipsp.h> +#endif + #include <net/pfvar.h> #define ACCEPT_FLAGS(oklist) \ @@ -49,6 +61,43 @@ return (EINVAL); \ } while (0) +#ifdef __FreeBSD__ +static inline int +_copyin(const void *uaddr, void *kaddr, size_t len) +{ + int r; + + PF_UNLOCK(); + r = copyin(uaddr, kaddr, len); + PF_LOCK(); + + return (r); +} + +static inline int +_copyout(const void *uaddr, void *kaddr, size_t len) +{ + int r; + + PF_UNLOCK(); + r = copyout(uaddr, kaddr, len); + PF_LOCK(); + + return (r); +} + +#define COPYIN(from, to, size) \ + ((flags & PFR_FLAG_USERIOCTL) ? \ + _copyin((from), (to), (size)) : \ + (bcopy((from), (to), (size)), 0)) + +#define COPYOUT(from, to, size) \ + ((flags & PFR_FLAG_USERIOCTL) ? \ + _copyout((from), (to), (size)) : \ + (bcopy((from), (to), (size)), 0)) + +#else + #define COPYIN(from, to, size) \ ((flags & PFR_FLAG_USERIOCTL) ? \ copyin((from), (to), (size)) : \ @@ -59,6 +108,8 @@ copyout((from), (to), (size)) : \ (bcopy((from), (to), (size)), 0)) +#endif + #define FILLIN_SIN(sin, addr) \ do { \ (sin).sin_len = sizeof(sin); \ @@ -123,9 +174,15 @@ struct pfr_walktree { #define senderr(e) do { rv = (e); goto _bad; } while (0) +#ifdef __FreeBSD__ +uma_zone_t pfr_ktable_pl; +uma_zone_t pfr_kentry_pl; +uma_zone_t pfr_kentry_pl2; +#else struct pool pfr_ktable_pl; struct pool pfr_kentry_pl; struct pool pfr_kentry_pl2; +#endif struct sockaddr_in pfr_sin; struct sockaddr_in6 pfr_sin6; union sockaddr_union pfr_mask; @@ -188,12 +245,14 @@ int pfr_ktable_cnt; void pfr_initialize(void) { +#ifndef __FreeBSD__ pool_init(&pfr_ktable_pl, sizeof(struct pfr_ktable), 0, 0, 0, "pfrktable", &pool_allocator_oldnointr); pool_init(&pfr_kentry_pl, sizeof(struct pfr_kentry), 0, 0, 0, "pfrkentry", &pool_allocator_oldnointr); pool_init(&pfr_kentry_pl2, sizeof(struct pfr_kentry), 0, 0, 0, "pfrkentry2", NULL); +#endif pfr_sin.sin_len = sizeof(pfr_sin); pfr_sin.sin_family = AF_INET; @@ -221,6 +280,7 @@ pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags) pfr_enqueue_addrs(kt, &workq, ndel, 0); if (!(flags & PFR_FLAG_DUMMY)) { + s = 0; if (flags & PFR_FLAG_ATOMIC) s = splsoftnet(); pfr_remove_kentries(kt, &workq); @@ -243,7 +303,7 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfr_kentryworkq workq; struct pfr_kentry *p, *q; struct pfr_addr ad; - int i, rv, s, xadd = 0; + int i, rv, s = 0, xadd = 0; long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); @@ -287,9 +347,10 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, xadd++; } } - if (flags & PFR_FLAG_FEEDBACK) + if (flags & PFR_FLAG_FEEDBACK) { if (COPYOUT(&ad, addr+i, sizeof(ad))) senderr(EFAULT); + } } pfr_clean_node_mask(tmpkt, &workq); if (!(flags & PFR_FLAG_DUMMY)) { @@ -321,7 +382,7 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfr_kentryworkq workq; struct pfr_kentry *p; struct pfr_addr ad; - int i, rv, s, xdel = 0, log = 1; + int i, rv, s = 0, xdel = 0, log = 1; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) @@ -404,19 +465,17 @@ _bad: int pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, - int *size2, int *nadd, int *ndel, int *nchange, int flags, - u_int32_t ignore_pfrt_flags) + int *size2, int *nadd, int *ndel, int *nchange, int flags) { struct pfr_ktable *kt, *tmpkt; struct pfr_kentryworkq addq, delq, changeq; struct pfr_kentry *p, *q; struct pfr_addr ad; - int i, rv, s, xadd = 0, xdel = 0, xchange = 0; + int i, rv, s = 0, xadd = 0, xdel = 0, xchange = 0; long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); - if (pfr_validate_table(tbl, ignore_pfrt_flags, flags & - PFR_FLAG_USERIOCTL)) + if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) return (EINVAL); kt = pfr_lookup_table(tbl); if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) @@ -578,9 +637,18 @@ pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size, w.pfrw_addr = addr; w.pfrw_free = kt->pfrkt_cnt; w.pfrw_flags = flags; +#ifdef __FreeBSD__ + rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); +#else rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w); +#endif if (!rv) +#ifdef __FreeBSD__ + rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, + &w); +#else rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w); +#endif if (rv) return (rv); @@ -600,7 +668,7 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, struct pfr_ktable *kt; struct pfr_walktree w; struct pfr_kentryworkq workq; - int rv, s; + int rv, s = 0; long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC); /* XXX PFR_FLAG_CLSTATS disabled */ @@ -621,9 +689,18 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, w.pfrw_flags = flags; if (flags & PFR_FLAG_ATOMIC) s = splsoftnet(); +#ifdef __FreeBSD__ + rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); +#else rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w); +#endif if (!rv) +#ifdef __FreeBSD__ + rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, + &w); +#else rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w); +#endif if (!rv && (flags & PFR_FLAG_CLSTATS)) { pfr_enqueue_addrs(kt, &workq, NULL, 0); pfr_clstats_kentries(&workq, tzero, 0); @@ -650,7 +727,7 @@ pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfr_kentryworkq workq; struct pfr_kentry *p; struct pfr_addr ad; - int i, rv, s, xzero = 0; + int i, rv, s = 0, xzero = 0; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); if (pfr_validate_table(tbl, 0, 0)) @@ -738,10 +815,20 @@ pfr_enqueue_addrs(struct pfr_ktable *kt, struct pfr_kentryworkq *workq, w.pfrw_op = sweep ? PFRW_SWEEP : PFRW_ENQUEUE; w.pfrw_workq = workq; if (kt->pfrkt_ip4 != NULL) +#ifdef __FreeBSD__ + if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, + &w)) +#else if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w)) +#endif printf("pfr_enqueue_addrs: IPv4 walktree failed.\n"); if (kt->pfrkt_ip6 != NULL) +#ifdef __FreeBSD__ + if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, + &w)) +#else if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w)) +#endif printf("pfr_enqueue_addrs: IPv6 walktree failed.\n"); if (naddr != NULL) *naddr = w.pfrw_cnt; @@ -754,9 +841,17 @@ pfr_mark_addrs(struct pfr_ktable *kt) bzero(&w, sizeof(w)); w.pfrw_op = PFRW_MARK; +#ifdef __FreeBSD__ + if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w)) +#else if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w)) +#endif printf("pfr_mark_addrs: IPv4 walktree failed.\n"); +#ifdef __FreeBSD__ + if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w)) +#else if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w)) +#endif printf("pfr_mark_addrs: IPv6 walktree failed.\n"); } @@ -765,7 +860,7 @@ struct pfr_kentry * pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact) { union sockaddr_union sa, mask; - struct radix_node_head *head; + struct radix_node_head *head = NULL; /* make the compiler happy */ struct pfr_kentry *ke; int s; @@ -780,7 +875,13 @@ pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact) if (ADDR_NETWORK(ad)) { pfr_prepare_network(&mask, ad->pfra_af, ad->pfra_net); s = splsoftnet(); /* rn_lookup makes use of globals */ +#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100) + RADIX_NODE_HEAD_LOCK(head); +#endif ke = (struct pfr_kentry *)rn_lookup(&sa, &mask, head); +#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100) + RADIX_NODE_HEAD_UNLOCK(head); +#endif splx(s); if (ke && KENTRY_RNF_ROOT(ke)) ke = NULL; @@ -968,7 +1069,7 @@ pfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) { union sockaddr_union mask; struct radix_node *rn; - struct radix_node_head *head; + struct radix_node_head *head = NULL; /* make the compiler happy */ int s; bzero(ke->pfrke_node, sizeof(ke->pfrke_node)); @@ -978,11 +1079,17 @@ pfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) head = kt->pfrkt_ip6; s = splsoftnet(); +#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100) + RADIX_NODE_HEAD_LOCK(head); +#endif if (KENTRY_NETWORK(ke)) { pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net); rn = rn_addroute(&ke->pfrke_sa, &mask, head, ke->pfrke_node); } else rn = rn_addroute(&ke->pfrke_sa, NULL, head, ke->pfrke_node); +#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100) + RADIX_NODE_HEAD_UNLOCK(head); +#endif splx(s); return (rn == NULL ? -1 : 0); @@ -993,7 +1100,7 @@ pfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) { union sockaddr_union mask; struct radix_node *rn; - struct radix_node_head *head; + struct radix_node_head *head = NULL; /* make the compiler happy */ int s; if (ke->pfrke_af == AF_INET) @@ -1002,11 +1109,25 @@ pfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) head = kt->pfrkt_ip6; s = splsoftnet(); +#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100) + RADIX_NODE_HEAD_LOCK(head); +#endif if (KENTRY_NETWORK(ke)) { pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net); +#ifdef __FreeBSD__ + rn = rn_delete(&ke->pfrke_sa, &mask, head); +#else rn = rn_delete(&ke->pfrke_sa, &mask, head, NULL); +#endif } else +#ifdef __FreeBSD__ + rn = rn_delete(&ke->pfrke_sa, NULL, head); +#else rn = rn_delete(&ke->pfrke_sa, NULL, head, NULL); +#endif +#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100) + RADIX_NODE_HEAD_UNLOCK(head); +#endif splx(s); if (rn == NULL) { @@ -1115,7 +1236,7 @@ pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags) { struct pfr_ktableworkq workq; struct pfr_ktable *p; - int s, xdel = 0; + int s = 0, xdel = 0; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_ALLRSETS); if (pfr_fix_anchor(filter->pfrt_anchor)) @@ -1152,7 +1273,7 @@ pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) { struct pfr_ktableworkq addq, changeq; struct pfr_ktable *p, *q, *r, key; - int i, rv, s, xadd = 0; + int i, rv, s = 0, xadd = 0; long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); @@ -1232,7 +1353,7 @@ pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags) { struct pfr_ktableworkq workq; struct pfr_ktable *p, *q, key; - int i, s, xdel = 0; + int i, s = 0, xdel = 0; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); SLIST_INIT(&workq); @@ -1306,7 +1427,7 @@ pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, { struct pfr_ktable *p; struct pfr_ktableworkq workq; - int s, n, nn; + int s = 0, n, nn; long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC|PFR_FLAG_ALLRSETS); @@ -1331,7 +1452,8 @@ pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, if (!(flags & PFR_FLAG_ATOMIC)) s = splsoftnet(); if (COPYOUT(&p->pfrkt_ts, tbl++, sizeof(*tbl))) { - splx(s); + if (!(flags & PFR_FLAG_ATOMIC)) + splx(s); return (EFAULT); } if (!(flags & PFR_FLAG_ATOMIC)) @@ -1356,7 +1478,7 @@ pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) { struct pfr_ktableworkq workq; struct pfr_ktable *p, key; - int i, s, xzero = 0; + int i, s = 0, xzero = 0; long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_ADDRSTOO); @@ -1390,7 +1512,7 @@ pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag, { struct pfr_ktableworkq workq; struct pfr_ktable *p, *q, key; - int i, s, xchange = 0, xdel = 0; + int i, s = 0, xchange = 0, xdel = 0; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); if ((setflag & ~PFR_TFLAG_USRMASK) || @@ -1609,7 +1731,7 @@ pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd, struct pfr_ktable *p, *q; struct pfr_ktableworkq workq; struct pf_ruleset *rs; - int s, xadd = 0, xchange = 0; + int s = 0, xadd = 0, xchange = 0; long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); @@ -1927,10 +2049,21 @@ pfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr) pfr_clean_node_mask(kt, &addrq); pfr_destroy_kentries(&addrq); } +#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100) + if (kt->pfrkt_ip4 != NULL) { + RADIX_NODE_HEAD_DESTROY(kt->pfrkt_ip4); + free((caddr_t)kt->pfrkt_ip4, M_RTABLE); + } + if (kt->pfrkt_ip6 != NULL) { + RADIX_NODE_HEAD_DESTROY(kt->pfrkt_ip6); + free((caddr_t)kt->pfrkt_ip6, M_RTABLE); + } +#else if (kt->pfrkt_ip4 != NULL) free((caddr_t)kt->pfrkt_ip4, M_RTABLE); if (kt->pfrkt_ip6 != NULL) free((caddr_t)kt->pfrkt_ip6, M_RTABLE); +#endif if (kt->pfrkt_shadow != NULL) pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr); if (kt->pfrkt_rs != NULL) { @@ -2049,7 +2182,7 @@ pfr_attach_table(struct pf_ruleset *rs, char *name) bzero(&tbl, sizeof(tbl)); strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name)); if (ac != NULL) - strlcpy(tbl.pfrt_anchor, ac->path, sizeof(tbl.pfrt_anchor)); + strlcpy(tbl.pfrt_anchor, ac->name, sizeof(tbl.pfrt_anchor)); kt = pfr_lookup_table(&tbl); if (kt == NULL) { kt = pfr_create_ktable(&tbl, time_second, 1); @@ -2085,12 +2218,13 @@ pfr_detach_table(struct pfr_ktable *kt) pfr_setflags_ktable(kt, kt->pfrkt_flags&~PFR_TFLAG_REFERENCED); } + int pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter, struct pf_addr **raddr, struct pf_addr **rmask, sa_family_t af) { - struct pfr_kentry *ke, *ke2; - struct pf_addr *addr; + struct pfr_kentry *ke, *ke2 = NULL; + struct pf_addr *addr = NULL; union sockaddr_union mask; int idx = -1, use_counter = 0; @@ -2180,12 +2314,20 @@ pfr_kentry_byidx(struct pfr_ktable *kt, int idx, int af) switch (af) { #ifdef INET case AF_INET: +#ifdef __FreeBSD__ + kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); +#else rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w); +#endif return (w.pfrw_kentry); #endif /* INET */ #ifdef INET6 case AF_INET6: +#ifdef __FreeBSD__ + kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w); +#else rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w); +#endif return (w.pfrw_kentry); #endif /* INET6 */ default: @@ -2207,8 +2349,16 @@ pfr_dynaddr_update(struct pfr_ktable *kt, struct pfi_dynaddr *dyn) dyn->pfid_acnt4 = 0; dyn->pfid_acnt6 = 0; if (!dyn->pfid_af || dyn->pfid_af == AF_INET) +#ifdef __FreeBSD__ + kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); +#else rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w); +#endif if (!dyn->pfid_af || dyn->pfid_af == AF_INET6) +#ifdef __FreeBSD__ + kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w); +#else rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w); +#endif splx(s); } diff --git a/sys/contrib/pf/net/pfvar.h b/sys/contrib/pf/net/pfvar.h index d650f79..f741130 100644 --- a/sys/contrib/pf/net/pfvar.h +++ b/sys/contrib/pf/net/pfvar.h @@ -1,4 +1,5 @@ -/* $OpenBSD: pfvar.h,v 1.244 2007/02/23 21:31:51 deraadt Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: pfvar.h,v 1.213 2005/03/03 07:13:39 dhartmei Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -37,26 +38,30 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/rwlock.h> #include <net/radix.h> #include <net/route.h> +#ifdef __FreeBSD__ +#include <net/if_clone.h> +#include <vm/uma.h> +#else #include <netinet/ip_ipsp.h> +#endif + +#ifdef __FreeBSD__ +#include <netinet/in.h> +#endif + #include <netinet/tcp_fsm.h> struct ip; -struct ip6_hdr; +#ifdef __FreeBSD__ +struct inpcb; +#endif #define PF_TCPS_PROXY_SRC ((TCP_NSTATES)+0) #define PF_TCPS_PROXY_DST ((TCP_NSTATES)+1) -#define PF_MD5_DIGEST_LENGTH 16 -#ifdef MD5_DIGEST_LENGTH -#if PF_MD5_DIGEST_LENGTH != MD5_DIGEST_LENGTH -#error -#endif -#endif - enum { PF_INOUT, PF_IN, PF_OUT }; enum { PF_LAN_EXT, PF_EXT_GWY, PF_ID }; enum { PF_PASS, PF_DROP, PF_SCRUB, PF_NOSCRUB, PF_NAT, PF_NONAT, @@ -69,8 +74,6 @@ enum { PF_DEBUG_NONE, PF_DEBUG_URGENT, PF_DEBUG_MISC, PF_DEBUG_NOISY }; enum { PF_CHANGE_NONE, PF_CHANGE_ADD_HEAD, PF_CHANGE_ADD_TAIL, PF_CHANGE_ADD_BEFORE, PF_CHANGE_ADD_AFTER, PF_CHANGE_REMOVE, PF_CHANGE_GET_TICKET }; -enum { PF_GET_NONE, PF_GET_CLR_CNTR }; - /* * Note about PFTM_*: real indices into pf_rule.timeout[] come before * PFTM_MAX, special cases afterwards. See pf_state_expires(). @@ -82,8 +85,7 @@ enum { PFTM_TCP_FIRST_PACKET, PFTM_TCP_OPENING, PFTM_TCP_ESTABLISHED, PFTM_OTHER_FIRST_PACKET, PFTM_OTHER_SINGLE, PFTM_OTHER_MULTIPLE, PFTM_FRAG, PFTM_INTERVAL, PFTM_ADAPTIVE_START, PFTM_ADAPTIVE_END, PFTM_SRC_NODE, - PFTM_TS_DIFF, PFTM_MAX, PFTM_PURGE, PFTM_UNLINKED, - PFTM_UNTIL_PACKET }; + PFTM_TS_DIFF, PFTM_MAX, PFTM_PURGE, PFTM_UNTIL_PACKET }; /* PFTM default values */ #define PFTM_TCP_FIRST_PACKET_VAL 120 /* First TCP packet */ @@ -106,22 +108,17 @@ enum { PFTM_TCP_FIRST_PACKET, PFTM_TCP_OPENING, PFTM_TCP_ESTABLISHED, #define PFTM_TS_DIFF_VAL 30 /* Allowed TS diff */ enum { PF_NOPFROUTE, PF_FASTROUTE, PF_ROUTETO, PF_DUPTO, PF_REPLYTO }; -enum { PF_LIMIT_STATES, PF_LIMIT_SRC_NODES, PF_LIMIT_FRAGS, - PF_LIMIT_TABLES, PF_LIMIT_TABLE_ENTRIES, PF_LIMIT_MAX }; +enum { PF_LIMIT_STATES, PF_LIMIT_SRC_NODES, PF_LIMIT_FRAGS, PF_LIMIT_MAX }; #define PF_POOL_IDMASK 0x0f enum { PF_POOL_NONE, PF_POOL_BITMASK, PF_POOL_RANDOM, PF_POOL_SRCHASH, PF_POOL_ROUNDROBIN }; enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL, - PF_ADDR_TABLE, PF_ADDR_RTLABEL, PF_ADDR_URPFFAILED }; + PF_ADDR_TABLE, PF_ADDR_RTLABEL }; #define PF_POOL_TYPEMASK 0x0f #define PF_POOL_STICKYADDR 0x20 #define PF_WSCALE_FLAG 0x80 #define PF_WSCALE_MASK 0x0f -#define PF_LOG 0x01 -#define PF_LOG_ALL 0x02 -#define PF_LOG_SOCKET_LOOKUP 0x04 - struct pf_addr { union { struct in_addr v4; @@ -153,6 +150,9 @@ struct pf_addr_wrap { } a; char ifname[IFNAMSIZ]; char tblname[PF_TABLE_NAME_SIZE]; +#ifdef __FreeBSD__ +#define RTLABEL_LEN 32 +#endif char rtlabelname[RTLABEL_LEN]; u_int32_t rtlabel; } v; @@ -169,25 +169,100 @@ struct pf_addr_wrap { #ifdef _KERNEL struct pfi_dynaddr { - TAILQ_ENTRY(pfi_dynaddr) entry; - struct pf_addr pfid_addr4; - struct pf_addr pfid_mask4; - struct pf_addr pfid_addr6; - struct pf_addr pfid_mask6; - struct pfr_ktable *pfid_kt; - struct pfi_kif *pfid_kif; - void *pfid_hook_cookie; - int pfid_net; /* mask or 128 */ - int pfid_acnt4; /* address count IPv4 */ - int pfid_acnt6; /* address count IPv6 */ - sa_family_t pfid_af; /* rule af */ - u_int8_t pfid_iflags; /* PFI_AFLAG_* */ + struct pf_addr pfid_addr4; + struct pf_addr pfid_mask4; + struct pf_addr pfid_addr6; + struct pf_addr pfid_mask6; + struct pfr_ktable *pfid_kt; + struct pfi_kif *pfid_kif; + void *pfid_hook_cookie; + int pfid_net; /* optional mask, or 128 */ + int pfid_acnt4; /* address count, IPv4 */ + int pfid_acnt6; /* address count, IPv6 */ + sa_family_t pfid_af; /* rule address family */ + u_int8_t pfid_iflags; /* PFI_AFLAG_* */ }; /* * Address manipulation macros */ +#ifdef __FreeBSD__ +#define splsoftnet() splnet() + +#define HTONL(x) (x) = htonl((__uint32_t)(x)) +#define HTONS(x) (x) = htons((__uint16_t)(x)) +#define NTOHL(x) (x) = ntohl((__uint32_t)(x)) +#define NTOHS(x) (x) = ntohs((__uint16_t)(x)) + +#define PF_NAME "pf" + +#define PR_NOWAIT M_NOWAIT +#define pool_get(p, f) uma_zalloc(*(p), (f)) +#define pool_put(p, o) uma_zfree(*(p), (o)) + +#define UMA_CREATE(var, type, desc) \ + var = uma_zcreate(desc, sizeof(type), \ + NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); \ + if (var == NULL) break +#define UMA_DESTROY(var) \ + if(var) uma_zdestroy(var) + +extern struct mtx pf_task_mtx; + +#define PF_ASSERT(h) mtx_assert(&pf_task_mtx, (h)) + +#define PF_LOCK() do { \ + PF_ASSERT(MA_NOTOWNED); \ + mtx_lock(&pf_task_mtx); \ +} while(0) +#define PF_UNLOCK() do { \ + PF_ASSERT(MA_OWNED); \ + mtx_unlock(&pf_task_mtx); \ +} while(0) + +#define PF_COPYIN(uaddr, kaddr, len, r) do { \ + PF_UNLOCK(); \ + r = copyin((uaddr), (kaddr), (len)); \ + PF_LOCK(); \ +} while(0) + +#define PF_COPYOUT(kaddr, uaddr, len, r) do { \ + PF_UNLOCK(); \ + r = copyout((kaddr), (uaddr), (len)); \ + PF_LOCK(); \ +} while(0) + +extern void init_pf_mutex(void); +extern void destroy_pf_mutex(void); + +#define PF_MODVER 1 +#define PFLOG_MODVER 1 +#define PFSYNC_MODVER 1 + +#define PFLOG_MINVER 1 +#define PFLOG_PREFVER PFLOG_MODVER +#define PFLOG_MAXVER 1 +#define PFSYNC_MINVER 1 +#define PFSYNC_PREFVER PFSYNC_MODVER +#define PFSYNC_MAXVER 1 + +/* prototyped for pf_subr.c */ +struct hook_desc { + TAILQ_ENTRY(hook_desc) hd_list; + void (*hd_fn)(void *); + void *hd_arg; +}; +TAILQ_HEAD(hook_desc_head, hook_desc); + +void *hook_establish(struct hook_desc_head *, int, void (*)(void *), void *); +void hook_disestablish(struct hook_desc_head *, void *); +void dohooks(struct hook_desc_head *, int); + +#define HOOK_REMOVE 0x01 +#define HOOK_FREE 0x02 +#endif /* __FreeBSD__ */ + #ifdef INET #ifndef INET6 #define PF_INET_ONLY @@ -317,26 +392,23 @@ struct pfi_dynaddr { #endif /* PF_INET6_ONLY */ #endif /* PF_INET_INET6 */ -#define PF_MISMATCHAW(aw, x, af, neg, ifp) \ - ( \ - (((aw)->type == PF_ADDR_NOROUTE && \ - pf_routable((x), (af), NULL)) || \ - (((aw)->type == PF_ADDR_URPFFAILED && (ifp) != NULL && \ - pf_routable((x), (af), (ifp))) || \ - ((aw)->type == PF_ADDR_RTLABEL && \ - !pf_rtlabel_match((x), (af), (aw))) || \ - ((aw)->type == PF_ADDR_TABLE && \ - !pfr_match_addr((aw)->p.tbl, (x), (af))) || \ - ((aw)->type == PF_ADDR_DYNIFTL && \ - !pfi_match_addr((aw)->p.dyn, (x), (af))) || \ - ((aw)->type == PF_ADDR_ADDRMASK && \ - !PF_AZERO(&(aw)->v.a.mask, (af)) && \ - !PF_MATCHA(0, &(aw)->v.a.addr, \ - &(aw)->v.a.mask, (x), (af))))) != \ - (neg) \ +#define PF_MISMATCHAW(aw, x, af, neg) \ + ( \ + (((aw)->type == PF_ADDR_NOROUTE && \ + pf_routable((x), (af))) || \ + ((aw)->type == PF_ADDR_RTLABEL && \ + !pf_rtlabel_match((x), (af), (aw))) || \ + ((aw)->type == PF_ADDR_TABLE && \ + !pfr_match_addr((aw)->p.tbl, (x), (af))) || \ + ((aw)->type == PF_ADDR_DYNIFTL && \ + !pfi_match_addr((aw)->p.dyn, (x), (af))) || \ + ((aw)->type == PF_ADDR_ADDRMASK && \ + !PF_AZERO(&(aw)->v.a.mask, (af)) && \ + !PF_MATCHA(0, &(aw)->v.a.addr, \ + &(aw)->v.a.mask, (x), (af)))) != \ + (neg) \ ) - struct pf_rule_uid { uid_t uid[2]; u_int8_t op; @@ -454,7 +526,6 @@ struct pf_os_fingerprint { #define PF_OSFP_MSS_DC 0x0800 /* TCP MSS dont-care */ #define PF_OSFP_DF 0x1000 /* IPv4 don't fragment bit */ #define PF_OSFP_TS0 0x2000 /* Zero timestamp */ -#define PF_OSFP_INET6 0x4000 /* IPv6 */ u_int8_t fp_optcnt; /* TCP option count */ u_int8_t fp_wscale; /* TCP window scaling */ u_int8_t fp_ttl; /* IPv4 TTL */ @@ -510,11 +581,11 @@ struct pf_rule { union pf_rule_ptr skip[PF_SKIP_COUNT]; #define PF_RULE_LABEL_SIZE 64 char label[PF_RULE_LABEL_SIZE]; -#define PF_QNAME_SIZE 64 +#define PF_QNAME_SIZE 16 char ifname[IFNAMSIZ]; char qname[PF_QNAME_SIZE]; char pqname[PF_QNAME_SIZE]; -#define PF_TAG_NAME_SIZE 64 +#define PF_TAG_NAME_SIZE 16 char tagname[PF_TAG_NAME_SIZE]; char match_tagname[PF_TAG_NAME_SIZE]; @@ -524,8 +595,8 @@ struct pf_rule { struct pf_pool rpool; u_int64_t evaluations; - u_int64_t packets[2]; - u_int64_t bytes[2]; + u_int64_t packets; + u_int64_t bytes; struct pfi_kif *kif; struct pf_anchor *anchor; @@ -533,7 +604,6 @@ struct pf_rule { pf_osfp_t os_fingerprint; - int rtableid; u_int32_t timeout[PFTM_MAX]; u_int32_t states; u_int32_t max_states; @@ -550,8 +620,6 @@ struct pf_rule { u_int32_t rt_listid; u_int32_t nr; u_int32_t prob; - uid_t cuid; - pid_t cpid; u_int16_t return_icmp; u_int16_t return_icmp6; @@ -566,7 +634,6 @@ struct pf_rule { u_int8_t action; u_int8_t direction; u_int8_t log; - u_int8_t logif; u_int8_t quick; u_int8_t ifnot; u_int8_t match_tag_not; @@ -614,10 +681,9 @@ struct pf_rule { /* rule flags again */ #define PFRULE_IFBOUND 0x00010000 /* if-bound */ +#define PFRULE_GRBOUND 0x00020000 /* group-bound */ #define PFSTATE_HIWAT 10000 /* default state table size */ -#define PFSTATE_ADAPT_START 6000 /* default adaptive timeout start */ -#define PFSTATE_ADAPT_END 12000 /* default adaptive timeout end */ struct pf_threshold { @@ -635,8 +701,8 @@ struct pf_src_node { struct pf_addr raddr; union pf_rule_ptr rule; struct pfi_kif *kif; - u_int64_t bytes[2]; - u_int64_t packets[2]; + u_int32_t bytes; + u_int32_t packets; u_int32_t states; u_int32_t conn; struct pf_threshold conn_rate; @@ -678,53 +744,26 @@ struct pf_state_peer { u_int8_t state; /* active state level */ u_int8_t wscale; /* window scaling factor */ u_int16_t mss; /* Maximum segment size option */ - u_int8_t tcp_est; /* Did we reach TCPS_ESTABLISHED */ struct pf_state_scrub *scrub; /* state is scrubbed */ - u_int8_t pad[3]; }; TAILQ_HEAD(pf_state_queue, pf_state); -/* keep synced with struct pf_state, used in RB_FIND */ -struct pf_state_cmp { - u_int64_t id; - u_int32_t creatorid; - struct pf_state_host lan; - struct pf_state_host gwy; - struct pf_state_host ext; - sa_family_t af; - u_int8_t proto; - u_int8_t direction; - u_int8_t pad; -}; - struct pf_state { u_int64_t id; - u_int32_t creatorid; - struct pf_state_host lan; - struct pf_state_host gwy; - struct pf_state_host ext; - sa_family_t af; - u_int8_t proto; - u_int8_t direction; - u_int8_t pad; - u_int8_t log; - u_int8_t allow_opts; - u_int8_t timeout; - u_int8_t sync_flags; -#define PFSTATE_NOSYNC 0x01 -#define PFSTATE_FROMSYNC 0x02 -#define PFSTATE_STALE 0x04 union { struct { RB_ENTRY(pf_state) entry_lan_ext; RB_ENTRY(pf_state) entry_ext_gwy; RB_ENTRY(pf_state) entry_id; - TAILQ_ENTRY(pf_state) entry_list; + TAILQ_ENTRY(pf_state) entry_updates; struct pfi_kif *kif; } s; char ifname[IFNAMSIZ]; } u; + struct pf_state_host lan; + struct pf_state_host gwy; + struct pf_state_host ext; struct pf_state_peer src; struct pf_state_peer dst; union pf_rule_ptr rule; @@ -734,12 +773,30 @@ struct pf_state { struct pfi_kif *rt_kif; struct pf_src_node *src_node; struct pf_src_node *nat_src_node; - u_int64_t packets[2]; - u_int64_t bytes[2]; u_int32_t creation; u_int32_t expire; u_int32_t pfsync_time; + u_int32_t packets[2]; + u_int32_t bytes[2]; + u_int32_t creatorid; u_int16_t tag; + sa_family_t af; + u_int8_t proto; + u_int8_t direction; + u_int8_t log; + u_int8_t allow_opts; + u_int8_t timeout; + u_int8_t sync_flags; +#define PFSTATE_NOSYNC 0x01 +#define PFSTATE_FROMSYNC 0x02 +#define PFSTATE_STALE 0x04 +#ifdef __FreeBSD__ + u_int8_t local_flags; +#define PFSTATE_EXPIRING 0x01 +#define PFSTATE_SRC_CONN 0x02 +#else + u_int8_t pad; +#endif }; TAILQ_HEAD(pf_rulequeue, pf_rule); @@ -751,8 +808,6 @@ struct pf_ruleset { struct pf_rulequeue queues[2]; struct { struct pf_rulequeue *ptr; - struct pf_rule **ptr_array; - u_int32_t rcount; u_int32_t ticket; int open; } active, inactive; @@ -774,7 +829,6 @@ struct pf_anchor { char path[MAXPATHLEN]; struct pf_ruleset ruleset; int refcnt; /* anchor rules */ - int match; }; RB_PROTOTYPE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare); RB_PROTOTYPE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare); @@ -841,6 +895,15 @@ struct pfr_tstats { #define pfrts_name pfrts_t.pfrt_name #define pfrts_flags pfrts_t.pfrt_flags +#ifndef _SOCKADDR_UNION_DEFINED +#define _SOCKADDR_UNION_DEFINED +union sockaddr_union { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; +}; +#endif /* _SOCKADDR_UNION_DEFINED */ + SLIST_HEAD(pfr_kentryworkq, pfr_kentry); struct pfr_kentry { struct radix_node pfrke_node[2]; @@ -891,47 +954,56 @@ RB_HEAD(pf_state_tree_ext_gwy, pf_state); RB_PROTOTYPE(pf_state_tree_ext_gwy, pf_state, u.s.entry_ext_gwy, pf_state_compare_ext_gwy); -TAILQ_HEAD(pfi_statehead, pfi_kif); -RB_HEAD(pfi_ifhead, pfi_kif); - -/* keep synced with pfi_kif, used in RB_FIND */ -struct pfi_kif_cmp { - char pfik_name[IFNAMSIZ]; +struct pfi_if { + char pfif_name[IFNAMSIZ]; + u_int64_t pfif_packets[2][2][2]; + u_int64_t pfif_bytes[2][2][2]; + u_int64_t pfif_addcnt; + u_int64_t pfif_delcnt; + long pfif_tzero; + int pfif_states; + int pfif_rules; + int pfif_flags; }; +TAILQ_HEAD(pfi_grouphead, pfi_kif); +TAILQ_HEAD(pfi_statehead, pfi_kif); +RB_HEAD(pfi_ifhead, pfi_kif); struct pfi_kif { - char pfik_name[IFNAMSIZ]; + struct pfi_if pfik_if; RB_ENTRY(pfi_kif) pfik_tree; - u_int64_t pfik_packets[2][2][2]; - u_int64_t pfik_bytes[2][2][2]; - u_int32_t pfik_tzero; - int pfik_flags; struct pf_state_tree_lan_ext pfik_lan_ext; struct pf_state_tree_ext_gwy pfik_ext_gwy; + struct pfi_grouphead pfik_grouphead; + TAILQ_ENTRY(pfi_kif) pfik_instances; TAILQ_ENTRY(pfi_kif) pfik_w_states; + struct hook_desc_head *pfik_ah_head; void *pfik_ah_cookie; + struct pfi_kif *pfik_parent; struct ifnet *pfik_ifp; - struct ifg_group *pfik_group; int pfik_states; int pfik_rules; - TAILQ_HEAD(, pfi_dynaddr) pfik_dynaddrs; }; - -enum pfi_kif_refs { - PFI_KIF_REF_NONE, - PFI_KIF_REF_STATE, - PFI_KIF_REF_RULE -}; - +#define pfik_name pfik_if.pfif_name +#define pfik_packets pfik_if.pfif_packets +#define pfik_bytes pfik_if.pfif_bytes +#define pfik_tzero pfik_if.pfif_tzero +#define pfik_flags pfik_if.pfif_flags +#define pfik_addcnt pfik_if.pfif_addcnt +#define pfik_delcnt pfik_if.pfif_delcnt +#define pfik_states pfik_if.pfif_states +#define pfik_rules pfik_if.pfif_rules + +#define PFI_IFLAG_GROUP 0x0001 /* group of interfaces */ +#define PFI_IFLAG_INSTANCE 0x0002 /* single instance */ +#define PFI_IFLAG_CLONABLE 0x0010 /* clonable group */ +#define PFI_IFLAG_DYNAMIC 0x0020 /* dynamic group */ +#define PFI_IFLAG_ATTACHED 0x0040 /* interface attached */ #define PFI_IFLAG_SKIP 0x0100 /* skip filtering on interface */ +#define PFI_IFLAG_SETABLE_MASK 0x0100 /* setable via DIOC{SET,CLR}IFFLAG */ +#define PFI_IFLAG_PLACEHOLDER 0x8000 /* placeholder group/interface */ struct pf_pdesc { - struct { - int done; - uid_t uid; - gid_t gid; - pid_t pid; - } lookup; u_int64_t tot_len; /* Make Mickey money */ union { struct tcphdr *tcp; @@ -949,7 +1021,6 @@ struct pf_pdesc { struct pf_addr *dst; struct ether_header *eh; - struct pf_mtag *pf_mtag; u_int16_t *ip_sum; u_int32_t p_len; /* total length of payload */ u_int16_t flags; /* Let SCRUB trigger behavior in @@ -1090,7 +1161,6 @@ struct pf_status { u_int32_t debug; u_int32_t hostid; char ifname[IFNAMSIZ]; - u_int8_t pf_chksum[PF_MD5_DIGEST_LENGTH]; }; struct cbq_opts { @@ -1153,20 +1223,6 @@ struct pf_altq { u_int32_t qid; /* return value */ }; -#define PF_TAG_GENERATED 0x01 -#define PF_TAG_FRAGCACHE 0x02 -#define PF_TAG_TRANSLATE_LOCALHOST 0x04 - -struct pf_mtag { - void *hdr; /* saved hdr pos in mbuf, for ECN */ - u_int rtableid; /* alternate routing table id */ - u_int32_t qid; /* queue id */ - u_int16_t tag; /* tag id */ - u_int8_t flags; - u_int8_t routed; - sa_family_t af; /* for ECN */ -}; - struct pf_tag { u_int16_t tag; /* tag id */ }; @@ -1183,10 +1239,6 @@ struct pf_tagname { #define PFFRAG_FRCENT_HIWAT 50000 /* Number of fragment cache entries */ #define PFFRAG_FRCACHE_HIWAT 10000 /* Number of fragment descriptors */ -#define PFR_KTABLE_HIWAT 1000 /* Number of tables */ -#define PFR_KENTRY_HIWAT 200000 /* Number of table entries */ -#define PFR_KENTRY_HIWAT_SMALL 100000 /* Number of table entries (tiny hosts) */ - /* * ioctl parameter structures */ @@ -1232,13 +1284,6 @@ struct pfioc_state { struct pf_state state; }; -struct pfioc_src_node_kill { - /* XXX returns the number of src nodes killed in psnk_af */ - sa_family_t psnk_af; - struct pf_rule_addr psnk_src; - struct pf_rule_addr psnk_dst; -}; - struct pfioc_state_kill { /* XXX returns the number of states killed in psk_af */ sa_family_t psk_af; @@ -1346,6 +1391,11 @@ struct pfioc_table { #define pfrio_setflag pfrio_size2 #define pfrio_clrflag pfrio_nadd + +#define PFI_FLAG_GROUP 0x0001 /* gets groups of interfaces */ +#define PFI_FLAG_INSTANCE 0x0002 /* gets single interfaces */ +#define PFI_FLAG_ALLMASK 0x0003 + struct pfioc_iface { char pfiio_name[IFNAMSIZ]; void *pfiio_buffer; @@ -1424,9 +1474,16 @@ struct pfioc_iface { #define DIOCCLRSRCNODES _IO('D', 85) #define DIOCSETHOSTID _IOWR('D', 86, u_int32_t) #define DIOCIGETIFACES _IOWR('D', 87, struct pfioc_iface) +#define DIOCICLRISTATS _IOWR('D', 88, struct pfioc_iface) #define DIOCSETIFFLAG _IOWR('D', 89, struct pfioc_iface) #define DIOCCLRIFFLAG _IOWR('D', 90, struct pfioc_iface) -#define DIOCKILLSRCNODES _IOWR('D', 91, struct pfioc_src_node_kill) +#ifdef __FreeBSD__ +struct pf_ifspeed { + char ifname[IFNAMSIZ]; + u_int32_t baudrate; +}; +#define DIOCGIFSPEED _IOWR('D', 91, struct pf_ifspeed) +#endif #ifdef _KERNEL RB_HEAD(pf_src_tree, pf_src_node); @@ -1437,13 +1494,16 @@ RB_HEAD(pf_state_tree_id, pf_state); RB_PROTOTYPE(pf_state_tree_id, pf_state, entry_id, pf_state_compare_id); extern struct pf_state_tree_id tree_id; -extern struct pf_state_queue state_list; +extern struct pf_state_queue state_updates; +extern struct pf_anchor_global pf_anchors; +extern struct pf_ruleset pf_main_ruleset; TAILQ_HEAD(pf_poolqueue, pf_pool); extern struct pf_poolqueue pf_pools[2]; TAILQ_HEAD(pf_altqqueue, pf_altq); extern struct pf_altqqueue pf_altqs[2]; extern struct pf_palist pf_pabuf; +extern struct pfi_kif **pfi_index2kif; extern u_int32_t ticket_altqs_active; extern u_int32_t ticket_altqs_inactive; @@ -1458,25 +1518,38 @@ extern int pf_tbladdr_setup(struct pf_ruleset *, extern void pf_tbladdr_remove(struct pf_addr_wrap *); extern void pf_tbladdr_copyout(struct pf_addr_wrap *); extern void pf_calc_skip_steps(struct pf_rulequeue *); +#ifdef __FreeBSD__ +extern uma_zone_t pf_src_tree_pl, pf_rule_pl; +extern uma_zone_t pf_state_pl, pf_altq_pl, pf_pooladdr_pl; +extern uma_zone_t pfr_ktable_pl, pfr_kentry_pl, pfr_kentry_pl2; +extern uma_zone_t pf_cache_pl, pf_cent_pl; +extern uma_zone_t pf_state_scrub_pl; +extern uma_zone_t pfi_addr_pl; +#else extern struct pool pf_src_tree_pl, pf_rule_pl; extern struct pool pf_state_pl, pf_altq_pl, pf_pooladdr_pl; extern struct pool pf_state_scrub_pl; -extern void pf_purge_thread(void *); -extern void pf_purge_expired_src_nodes(int); -extern void pf_purge_expired_states(u_int32_t); -extern void pf_unlink_state(struct pf_state *); -extern void pf_free_state(struct pf_state *); +#endif +extern void pf_purge_timeout(void *); +extern void pf_purge_expired_src_nodes(void); +extern void pf_purge_expired_states(void); +extern void pf_purge_expired_state(struct pf_state *); extern int pf_insert_state(struct pfi_kif *, struct pf_state *); extern int pf_insert_src_node(struct pf_src_node **, struct pf_rule *, struct pf_addr *, sa_family_t); void pf_src_tree_remove_state(struct pf_state *); -extern struct pf_state *pf_find_state_byid(struct pf_state_cmp *); -extern struct pf_state *pf_find_state_all(struct pf_state_cmp *key, +extern struct pf_state *pf_find_state_byid(struct pf_state *); +extern struct pf_state *pf_find_state_all(struct pf_state *key, u_int8_t tree, int *more); extern void pf_print_state(struct pf_state *); extern void pf_print_flags(u_int8_t); +extern struct pf_anchor *pf_find_anchor(const char *); +extern struct pf_ruleset *pf_find_ruleset(const char *); +extern struct pf_ruleset *pf_find_or_create_ruleset(const char *); +extern void pf_remove_if_empty_ruleset( + struct pf_ruleset *); extern u_int16_t pf_cksum_fixup(u_int16_t, u_int16_t, u_int16_t, u_int8_t); @@ -1488,11 +1561,21 @@ void pf_rm_rule(struct pf_rulequeue *, struct pf_rule *); #ifdef INET +#ifdef __FreeBSD__ +int pf_test(int, struct ifnet *, struct mbuf **, struct ether_header *, + struct inpcb *); +#else int pf_test(int, struct ifnet *, struct mbuf **, struct ether_header *); +#endif #endif /* INET */ #ifdef INET6 +#ifdef __FreeBSD__ +int pf_test6(int, struct ifnet *, struct mbuf **, struct ether_header *, + struct inpcb *); +#else int pf_test6(int, struct ifnet *, struct mbuf **, struct ether_header *); +#endif void pf_poolmask(struct pf_addr *, struct pf_addr*, struct pf_addr *, struct pf_addr *, u_int8_t); void pf_addr_inc(struct pf_addr *, sa_family_t); @@ -1502,8 +1585,7 @@ void *pf_pull_hdr(struct mbuf *, int, void *, int, u_short *, u_short *, sa_family_t); void pf_change_a(void *, u_int16_t *, u_int32_t, u_int8_t); int pflog_packet(struct pfi_kif *, struct mbuf *, sa_family_t, u_int8_t, - u_int8_t, struct pf_rule *, struct pf_rule *, struct pf_ruleset *, - struct pf_pdesc *); + u_int8_t, struct pf_rule *, struct pf_rule *, struct pf_ruleset *); int pf_match_addr(u_int8_t, struct pf_addr *, struct pf_addr *, struct pf_addr *, sa_family_t); int pf_match(u_int8_t, u_int32_t, u_int32_t, u_int32_t); @@ -1527,9 +1609,8 @@ int pf_normalize_tcp_stateful(struct mbuf *, int, struct pf_pdesc *, u_int32_t pf_state_expires(const struct pf_state *); void pf_purge_expired_fragments(void); -int pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *); +int pf_routable(struct pf_addr *addr, sa_family_t af); int pf_rtlabel_match(struct pf_addr *, sa_family_t, struct pf_addr_wrap *); -int pf_socket_lookup(int, struct pf_pdesc *); void pfr_initialize(void); int pfr_match_addr(struct pfr_ktable *, struct pf_addr *, sa_family_t); void pfr_update_stats(struct pfr_ktable *, struct pf_addr *, sa_family_t, @@ -1554,7 +1635,7 @@ int pfr_add_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int pfr_del_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int); int pfr_set_addrs(struct pfr_table *, struct pfr_addr *, int, int *, - int *, int *, int *, int, u_int32_t); + int *, int *, int *, int); int pfr_get_addrs(struct pfr_table *, struct pfr_addr *, int *, int); int pfr_get_astats(struct pfr_table *, struct pfr_astats *, int *, int); int pfr_clr_astats(struct pfr_table *, struct pfr_addr *, int, int *, @@ -1567,44 +1648,49 @@ int pfr_ina_commit(struct pfr_table *, u_int32_t, int *, int *, int); int pfr_ina_define(struct pfr_table *, struct pfr_addr *, int, int *, int *, u_int32_t, int); -extern struct pfi_statehead pfi_statehead; -extern struct pfi_kif *pfi_all; - void pfi_initialize(void); -struct pfi_kif *pfi_kif_get(const char *); -void pfi_kif_ref(struct pfi_kif *, enum pfi_kif_refs); -void pfi_kif_unref(struct pfi_kif *, enum pfi_kif_refs); -int pfi_kif_match(struct pfi_kif *, struct pfi_kif *); +#ifdef __FreeBSD__ +void pfi_cleanup(void); +#endif +void pfi_attach_clone(struct if_clone *); void pfi_attach_ifnet(struct ifnet *); void pfi_detach_ifnet(struct ifnet *); -void pfi_attach_ifgroup(struct ifg_group *); -void pfi_detach_ifgroup(struct ifg_group *); -void pfi_group_change(const char *); -int pfi_match_addr(struct pfi_dynaddr *, struct pf_addr *, - sa_family_t); +struct pfi_kif *pfi_lookup_create(const char *); +struct pfi_kif *pfi_lookup_if(const char *); +int pfi_maybe_destroy(struct pfi_kif *); +struct pfi_kif *pfi_attach_rule(const char *); +void pfi_detach_rule(struct pfi_kif *); +void pfi_attach_state(struct pfi_kif *); +void pfi_detach_state(struct pfi_kif *); int pfi_dynaddr_setup(struct pf_addr_wrap *, sa_family_t); -void pfi_dynaddr_remove(struct pf_addr_wrap *); void pfi_dynaddr_copyout(struct pf_addr_wrap *); +void pfi_dynaddr_remove(struct pf_addr_wrap *); void pfi_fill_oldstatus(struct pf_status *); -int pfi_clr_istats(const char *); -int pfi_get_ifaces(const char *, struct pfi_kif *, int *); +int pfi_clr_istats(const char *, int *, int); +int pfi_get_ifaces(const char *, struct pfi_if *, int *, int); int pfi_set_flags(const char *, int); int pfi_clear_flags(const char *, int); +int pfi_match_addr(struct pfi_dynaddr *, struct pf_addr *, + sa_family_t); -u_int16_t pf_tagname2tag(char *); -void pf_tag2tagname(u_int16_t, char *); -void pf_tag_ref(u_int16_t); -void pf_tag_unref(u_int16_t); -int pf_tag_packet(struct mbuf *, struct pf_mtag *, int, int); -u_int32_t pf_qname2qid(char *); -void pf_qid2qname(u_int32_t, char *); -void pf_qid_unref(u_int32_t); -struct pf_mtag *pf_find_mtag(struct mbuf *); -struct pf_mtag *pf_get_mtag(struct mbuf *); +extern struct pfi_statehead pfi_statehead; + +u_int16_t pf_tagname2tag(char *); +void pf_tag2tagname(u_int16_t, char *); +void pf_tag_ref(u_int16_t); +void pf_tag_unref(u_int16_t); +int pf_tag_packet(struct mbuf *, struct pf_tag *, int); +u_int32_t pf_qname2qid(char *); +void pf_qid2qname(u_int32_t, char *); +void pf_qid_unref(u_int32_t); extern struct pf_status pf_status; + +#ifdef __FreeBSD__ +extern uma_zone_t pf_frent_pl, pf_frag_pl; +#else extern struct pool pf_frent_pl, pf_frag_pl; -extern struct rwlock pf_consistency_lock; +#endif struct pf_pool_limit { void *pp; @@ -1612,30 +1698,37 @@ struct pf_pool_limit { }; extern struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX]; -#endif /* _KERNEL */ +#ifdef __FreeBSD__ +struct pf_frent { + LIST_ENTRY(pf_frent) fr_next; + struct ip *fr_ip; + struct mbuf *fr_m; +}; -extern struct pf_anchor_global pf_anchors; -extern struct pf_anchor pf_main_anchor; -#define pf_main_ruleset pf_main_anchor.ruleset - -/* these ruleset functions can be linked into userland programs (pfctl) */ -int pf_get_ruleset_number(u_int8_t); -void pf_init_ruleset(struct pf_ruleset *); -int pf_anchor_setup(struct pf_rule *, - const struct pf_ruleset *, const char *); -int pf_anchor_copyout(const struct pf_ruleset *, - const struct pf_rule *, struct pfioc_rule *); -void pf_anchor_remove(struct pf_rule *); -void pf_remove_if_empty_ruleset(struct pf_ruleset *); -struct pf_anchor *pf_find_anchor(const char *); -struct pf_ruleset *pf_find_ruleset(const char *); -struct pf_ruleset *pf_find_or_create_ruleset(const char *); -void pf_rs_initialize(void); +struct pf_frcache { + LIST_ENTRY(pf_frcache) fr_next; + uint16_t fr_off; + uint16_t fr_end; +}; -#ifdef _KERNEL -int pf_anchor_copyout(const struct pf_ruleset *, - const struct pf_rule *, struct pfioc_rule *); -void pf_anchor_remove(struct pf_rule *); +struct pf_fragment { + RB_ENTRY(pf_fragment) fr_entry; + TAILQ_ENTRY(pf_fragment) frag_next; + struct in_addr fr_src; + struct in_addr fr_dst; + u_int8_t fr_p; /* protocol of this fragment */ + u_int8_t fr_flags; /* status flags */ + u_int16_t fr_id; /* fragment id for reassemble */ + u_int16_t fr_max; /* fragment data max */ + u_int32_t fr_timeout; +#define fr_queue fr_u.fru_queue +#define fr_cache fr_u.fru_cache + union { + LIST_HEAD(pf_fragq, pf_frent) fru_queue; /* buffering */ + LIST_HEAD(pf_cacheq, pf_frcache) fru_cache; /* non-buf */ + } fr_u; +}; +#endif /* (__FreeBSD__) */ #endif /* _KERNEL */ @@ -1647,11 +1740,15 @@ struct pf_osfp_enlist * const struct tcphdr *); #endif /* _KERNEL */ struct pf_osfp_enlist * - pf_osfp_fingerprint_hdr(const struct ip *, const struct ip6_hdr *, - const struct tcphdr *); + pf_osfp_fingerprint_hdr(const struct ip *, const struct tcphdr *); void pf_osfp_flush(void); int pf_osfp_get(struct pf_osfp_ioctl *); +#ifdef __FreeBSD__ +int pf_osfp_initialize(void); +void pf_osfp_cleanup(void); +#else void pf_osfp_initialize(void); +#endif int pf_osfp_match(struct pf_osfp_enlist *, pf_osfp_t); struct pf_os_fingerprint * pf_osfp_validate(void); diff --git a/sys/contrib/pf/netinet/in4_cksum.c b/sys/contrib/pf/netinet/in4_cksum.c index 1c40f2e..24a04d0 100644 --- a/sys/contrib/pf/netinet/in4_cksum.c +++ b/sys/contrib/pf/netinet/in4_cksum.c @@ -1,3 +1,4 @@ +/* $FreeBSD$ */ /* $OpenBSD: in4_cksum.c,v 1.7 2003/06/02 23:28:13 millert Exp $ */ /* $KAME: in4_cksum.c,v 1.10 2001/11/30 10:06:15 itojun Exp $ */ /* $NetBSD: in_cksum.c,v 1.13 1996/10/13 02:03:03 christos Exp $ */ @@ -63,52 +64,37 @@ */ #include <sys/param.h> -#include <sys/mbuf.h> #include <sys/systm.h> -#include <sys/socket.h> -#include <net/route.h> +#include <sys/mbuf.h> + #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/ip_var.h> -/* - * Checksum routine for Internet Protocol family headers (Portable Version). - * This is only for IPv4 pseudo header checksum. - * No need to clear non-pseudo-header fields in IPv4 header. - * len is for actual payload size, and does not include IPv4 header and - * skipped header chain (off + len should be equal to the whole packet). - * - * This routine is very heavily used in the network - * code and should be modified for each CPU to be as fast as possible. - */ +#include <machine/in_cksum.h> #define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);} +int in4_cksum(struct mbuf *, u_int8_t, int, int); + int -in4_cksum(m, nxt, off, len) - struct mbuf *m; - u_int8_t nxt; - int off, len; +in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len) { - u_int16_t *w; - int sum = 0; - int mlen = 0; - int byte_swapped = 0; union { struct ipovly ipov; u_int16_t w[10]; } u; union { - u_int8_t c[2]; - u_int16_t s; - } s_util; - union { u_int16_t s[2]; u_int32_t l; } l_util; + u_int16_t *w; + int psum; + int sum = 0; + if (nxt != 0) { /* pseudo header */ if (off < sizeof(struct ipovly)) @@ -126,94 +112,9 @@ in4_cksum(m, nxt, off, len) sum += w[5]; sum += w[6]; sum += w[7]; sum += w[8]; sum += w[9]; } - /* skip unnecessary part */ - while (m && off > 0) { - if (m->m_len > off) - break; - off -= m->m_len; - m = m->m_next; - } - - for (;m && len; m = m->m_next) { - if (m->m_len == 0) - continue; - w = (u_int16_t *)(mtod(m, caddr_t) + off); - if (mlen == -1) { - /* - * The first byte of this mbuf is the continuation - * of a word spanning between this mbuf and the - * last mbuf. - * - * s_util.c[0] is already saved when scanning previous - * mbuf. - */ - s_util.c[1] = *(u_int8_t *)w; - sum += s_util.s; - w = (u_int16_t *)((u_int8_t *)w + 1); - mlen = m->m_len - off - 1; - len--; - } else - mlen = m->m_len - off; - off = 0; - if (len < mlen) - mlen = len; - len -= mlen; - /* - * Force to even boundary. - */ - if ((1 & (long) w) && (mlen > 0)) { - REDUCE; - sum <<= 8; - s_util.c[0] = *(u_int8_t *)w; - w = (u_int16_t *)((int8_t *)w + 1); - mlen--; - byte_swapped = 1; - } - /* - * Unroll the loop to make overhead from - * branches &c small. - */ - while ((mlen -= 32) >= 0) { - sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; - sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; - sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; - sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; - w += 16; - } - mlen += 32; - while ((mlen -= 8) >= 0) { - sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; - w += 4; - } - mlen += 8; - if (mlen == 0 && byte_swapped == 0) - continue; - REDUCE; - while ((mlen -= 2) >= 0) { - sum += *w++; - } - if (byte_swapped) { - REDUCE; - sum <<= 8; - byte_swapped = 0; - if (mlen == -1) { - s_util.c[1] = *(u_int8_t *)w; - sum += s_util.s; - mlen = 0; - } else - mlen = -1; - } else if (mlen == -1) - s_util.c[0] = *(u_int8_t *)w; - } - if (len) - printf("cksum4: out of data\n"); - if (mlen == -1) { - /* The last mbuf has odd # of bytes. Follow the - standard (the odd byte may be shifted left by 8 bits - or not as determined by endian-ness of the machine) */ - s_util.c[1] = 0; - sum += s_util.s; - } + psum = in_cksum_skip(m, len + off, off); + psum = ~psum & 0xffff; + sum += psum; REDUCE; return (~sum & 0xffff); } |