diff options
Diffstat (limited to 'sys/contrib/pf')
-rw-r--r-- | sys/contrib/pf/net/if_pflog.c | 169 | ||||
-rw-r--r-- | sys/contrib/pf/net/if_pflog.h | 8 | ||||
-rw-r--r-- | sys/contrib/pf/net/if_pfsync.c | 1225 | ||||
-rw-r--r-- | sys/contrib/pf/net/if_pfsync.h | 242 | ||||
-rw-r--r-- | sys/contrib/pf/net/pf.c | 3091 | ||||
-rw-r--r-- | sys/contrib/pf/net/pf_ioctl.c | 2134 | ||||
-rw-r--r-- | sys/contrib/pf/net/pf_norm.c | 252 | ||||
-rw-r--r-- | sys/contrib/pf/net/pf_osfp.c | 46 | ||||
-rw-r--r-- | sys/contrib/pf/net/pf_table.c | 552 | ||||
-rw-r--r-- | sys/contrib/pf/net/pfvar.h | 467 | ||||
-rw-r--r-- | sys/contrib/pf/netinet/in4_cksum.c | 168 |
11 files changed, 4488 insertions, 3866 deletions
diff --git a/sys/contrib/pf/net/if_pflog.c b/sys/contrib/pf/net/if_pflog.c index 3b93226..13f6a6c 100644 --- a/sys/contrib/pf/net/if_pflog.c +++ b/sys/contrib/pf/net/if_pflog.c @@ -1,4 +1,5 @@ -/* $OpenBSD: if_pflog.c,v 1.11 2003/12/31 11:18:25 cedric Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: if_pflog.c,v 1.9 2003/05/14 08:42:00 canacar Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), * Angelos D. Keromytis (kermit@csd.uch.gr) and @@ -33,14 +34,33 @@ * 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" +#define NBPFILTER DEV_BPF +#define NPFLOG DEV_PFLOG +#endif #include <sys/param.h> #include <sys/systm.h> #include <sys/mbuf.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> #include <net/if_types.h> @@ -54,6 +74,10 @@ #include <netinet/ip.h> #endif +#ifdef __FreeBSD__ +#include <machine/in_cksum.h> +#endif + #ifdef INET6 #ifndef INET #include <netinet/in.h> @@ -64,6 +88,10 @@ #include <net/pfvar.h> #include <net/if_pflog.h> +#ifdef __FreeBSD__ +#define PFLOGNAME "pflog" +#endif + #define PFLOGMTU (32768 + MHLEN + MLEN) #ifdef PFLOGDEBUG @@ -72,17 +100,87 @@ #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); +#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 *); +#ifndef __FreeBSD__ extern int ifqmaxlen; +#endif + +#ifdef __FreeBSD__ +static MALLOC_DEFINE(M_PFLOG, PFLOGNAME, "Packet Filter Logging Interface"); +static LIST_HEAD(pflog_list, pflog_softc) pflog_list; +struct if_clone pflog_cloner = IF_CLONE_INITIALIZER(PFLOGNAME, + pflog_clone_create, pflog_clone_destroy, 1, IF_MAXUNIT); + +static void +pflog_clone_destroy(struct ifnet *ifp) +{ + struct pflog_softc *sc; + + sc = ifp->if_softc; + + /* + * Does we really need this? + */ + IF_DRAIN(&ifp->if_snd); + + bpfdetach(ifp); + if_detach(ifp); + LIST_REMOVE(sc, sc_next); + free(sc, M_PFLOG); +} + +static int +pflog_clone_create(struct if_clone *ifc, int unit) +{ + struct pflog_softc *sc; + + MALLOC(sc, struct pflog_softc *, sizeof(*sc), M_PFLOG, M_WAITOK|M_ZERO); + +#if (__FreeBSD_version < 501113) + sc->sc_if.if_name = PFLOGNAME; + sc->sc_if.if_unit = unit; +#else + if_initname(&sc->sc_if, ifc->ifc_name, unit); +#endif + sc->sc_if.if_mtu = PFLOGMTU; + sc->sc_if.if_ioctl = pflogioctl; + sc->sc_if.if_output = pflogoutput; + sc->sc_if.if_start = pflogstart; + sc->sc_if.if_type = IFT_PFLOG; + sc->sc_if.if_snd.ifq_maxlen = ifqmaxlen; + sc->sc_if.if_hdrlen = PFLOG_HDRLEN; + sc->sc_if.if_softc = sc; + /* + * We would get a message like + * "in6_ifattach: pflog0 is not multicast capable, IPv6 not enabled". + * We need a patch to in6_ifattach() to exclude interface type + * IFT_PFLOG. + */ + if_attach(&sc->sc_if); + + LIST_INSERT_HEAD(&pflog_list, sc, sc_next); +#if NBPFILTER > 0 + bpfattach(&sc->sc_if, DLT_PFLOG, PFLOG_HDRLEN); +#endif + return (0); +} +#else /* !__FreeBSD__ */ void pflogattach(int npflog) { @@ -111,6 +209,7 @@ pflogattach(int npflog) #endif } } +#endif /* __FreeBSD__ */ /* * Start output on the pflog interface. @@ -123,10 +222,16 @@ pflogstart(struct ifnet *ifp) for (;;) { s = splimp(); +#ifdef __FreeBSD__ + IF_LOCK(&ifp->if_snd); + _IF_DROP(&ifp->if_snd); + _IF_DEQUEUE(&ifp->if_snd, m); + IF_UNLOCK(&ifp->if_snd); +#else IF_DROP(&ifp->if_snd); IF_DEQUEUE(&ifp->if_snd, m); +#endif splx(s); - if (m == NULL) return; else @@ -172,7 +277,7 @@ 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, +pflog_packet(struct ifnet *ifp, 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) { @@ -181,23 +286,29 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir, struct pfloghdr hdr; struct mbuf m1; - if (kif == NULL || m == NULL || rm == NULL) + if (ifp == NULL || m == NULL || rm == NULL) return (-1); - bzero(&hdr, sizeof(hdr)); hdr.length = PFLOG_REAL_HDRLEN; hdr.af = af; hdr.action = rm->action; hdr.reason = reason; - memcpy(hdr.ifname, kif->pfik_name, sizeof(hdr.ifname)); +#if defined(__FreeBSD__) && (__FreeBSD_version < 501113) + snprintf(hdr.ifname, IFNAMSIZ, "%s%d", ifp->if_name, ifp->if_unit); +#else + memcpy(hdr.ifname, ifp->if_xname, sizeof(hdr.ifname)); +#endif if (am == NULL) { hdr.rulenr = htonl(rm->nr); hdr.subrulenr = -1; + bzero(hdr.ruleset, sizeof(hdr.ruleset)); } else { hdr.rulenr = htonl(am->nr); hdr.subrulenr = htonl(rm->nr); - if (ruleset != NULL) + if (ruleset == NULL) + bzero(hdr.ruleset, sizeof(hdr.ruleset)); + else memcpy(hdr.ruleset, ruleset->name, sizeof(hdr.ruleset)); @@ -219,7 +330,12 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir, m1.m_len = PFLOG_HDRLEN; m1.m_data = (char *) &hdr; +#ifdef __FreeBSD__ + KASSERT((!LIST_EMPTY(&pflog_list)), ("pflog: no interface")); + ifn = &LIST_FIRST(&pflog_list)->sc_if; +#else ifn = &(pflogif[0].sc_if); +#endif if (ifn->if_bpf) bpf_mtap(ifn->if_bpf, &m1); @@ -227,3 +343,42 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir, 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); + break; + + case MOD_UNLOAD: + if_clone_detach(&pflog_cloner); + while (!LIST_EMPTY(&pflog_list)) + pflog_clone_destroy( + &LIST_FIRST(&pflog_list)->sc_if); + 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_PSEUDO, SI_ORDER_ANY); +MODULE_VERSION(pflog, PFLOG_MODVER); +#endif /* __FreeBSD__ */ diff --git a/sys/contrib/pf/net/if_pflog.h b/sys/contrib/pf/net/if_pflog.h index e4e603e..e598239 100644 --- a/sys/contrib/pf/net/if_pflog.h +++ b/sys/contrib/pf/net/if_pflog.h @@ -1,4 +1,5 @@ -/* $OpenBSD: if_pflog.h,v 1.10 2004/03/19 04:52:04 frantzen Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: if_pflog.h,v 1.9 2003/07/15 20:27:27 dhartmei Exp $ */ /* * Copyright 2001 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -29,6 +30,9 @@ struct pflog_softc { struct ifnet sc_if; /* the interface */ +#ifdef __FreeBSD__ + LIST_ENTRY(pflog_softc) sc_next; +#endif }; /* XXX keep in sync with pfvar.h */ @@ -51,7 +55,7 @@ struct pfloghdr { #define PFLOG_HDRLEN sizeof(struct pfloghdr) /* minus pad, also used as a signature */ -#define PFLOG_REAL_HDRLEN offsetof(struct pfloghdr, pad) +#define PFLOG_REAL_HDRLEN offsetof(struct pfloghdr, pad); /* XXX remove later when old format logs are no longer needed */ struct old_pfloghdr { diff --git a/sys/contrib/pf/net/if_pfsync.c b/sys/contrib/pf/net/if_pfsync.c index e4840ff..06eb4b0 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.26 2004/03/28 18:14:20 mcbride Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: if_pfsync.c,v 1.6 2003/06/21 09:07:01 djm Exp $ */ /* * Copyright (c) 2002 Michael Shalayeff @@ -26,17 +27,35 @@ * 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" +#define NBPFILTER DEV_BPF +#define NPFSYNC DEV_PFSYNC +#endif #include <sys/param.h> -#include <sys/proc.h> #include <sys/systm.h> #include <sys/time.h> #include <sys/mbuf.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> #include <sys/timeout.h> +#endif #include <net/if.h> #include <net/if_types.h> @@ -45,10 +64,7 @@ #ifdef INET #include <netinet/in.h> -#include <netinet/in_systm.h> #include <netinet/in_var.h> -#include <netinet/ip.h> -#include <netinet/ip_var.h> #endif #ifdef INET6 @@ -61,6 +77,10 @@ #include <net/pfvar.h> #include <net/if_pfsync.h> +#ifdef __FreeBSD__ +#define PFSYNCNAME "pfsync" +#endif + #define PFSYNC_MINMTU \ (sizeof(struct pfsync_header) + sizeof(struct pf_state)) @@ -71,46 +91,105 @@ int pfsyncdebug; #define DPRINTF(x) #endif -struct pfsync_softc pfsyncif; -int pfsync_sync_ok; -struct pfsyncstats pfsyncstats; +#ifndef __FreeBSD__ +struct pfsync_softc pfsyncif; +#endif +#ifdef __FreeBSD__ +static void pfsync_clone_destroy(struct ifnet *); +static int pfsync_clone_create(struct if_clone *, int); +#else void pfsyncattach(int); -void pfsync_setmtu(struct pfsync_softc *, int); -int pfsync_insert_net_state(struct pfsync_state *); +#endif +void pfsync_setmtu(struct pfsync_softc *sc, int); int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *, - struct rtentry *); + struct rtentry *); int pfsyncioctl(struct ifnet *, u_long, caddr_t); 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 *); -void pfsync_timeout(void *); -void pfsync_send_bus(struct pfsync_softc *, u_int8_t); -void pfsync_bulk_update(void *); -void pfsync_bulkfail(void *); +struct mbuf *pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action); +int pfsync_sendout(struct pfsync_softc *sc); +void pfsync_timeout(void *v); +#ifndef __FreeBSD__ extern int ifqmaxlen; -extern struct timeval time; -extern struct timeval mono_time; -extern int hz; +#endif + +#ifdef __FreeBSD__ +static MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface"); +static LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list; +struct if_clone pfsync_cloner = IF_CLONE_INITIALIZER(PFSYNCNAME, + pfsync_clone_create, pfsync_clone_destroy, 1, IF_MAXUNIT); + +static void +pfsync_clone_destroy(struct ifnet *ifp) +{ + struct pfsync_softc *sc; + + sc = ifp->if_softc; + callout_stop(&sc->sc_tmo); + + /* + * Does we really need this? + */ + IF_DRAIN(&ifp->if_snd); + +#if NBPFILTER > 0 + bpfdetach(ifp); +#endif + if_detach(ifp); + LIST_REMOVE(sc, sc_next); + free(sc, M_PFSYNC); +} + +static int +pfsync_clone_create(struct if_clone *ifc, int unit) +{ + struct pfsync_softc *sc; + + MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC, + M_WAITOK|M_ZERO); + sc->sc_count = 8; +#if (__FreeBSD_version < 501113) + sc->sc_if.if_name = PFSYNCNAME; + sc->sc_if.if_unit = unit; +#else + if_initname(&sc->sc_if, ifc->ifc_name, unit); +#endif + sc->sc_if.if_ioctl = pfsyncioctl; + sc->sc_if.if_output = pfsyncoutput; + sc->sc_if.if_start = pfsyncstart; + sc->sc_if.if_type = IFT_PFSYNC; + sc->sc_if.if_snd.ifq_maxlen = ifqmaxlen; + sc->sc_if.if_hdrlen = PFSYNC_HDRLEN; + sc->sc_if.if_baudrate = IF_Mbps(100); + sc->sc_if.if_softc = sc; + pfsync_setmtu(sc, MCLBYTES); + /* + * XXX + * The 2nd arg. 0 to callout_init(9) shoule be set to CALLOUT_MPSAFE + * if Gaint lock is removed from the network stack. + */ + callout_init(&sc->sc_tmo, 0); + if_attach(&sc->sc_if); + + LIST_INSERT_HEAD(&pfsync_list, sc, sc_next); +#if NBPFILTER > 0 + bpfattach(&sc->sc_if, DLT_PFSYNC, PFSYNC_HDRLEN); +#endif + + return (0); +} +#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_sendaddr.s_addr = INADDR_PFSYNC_GROUP; - pfsyncif.sc_ureq_received = 0; - pfsyncif.sc_ureq_sent = 0; + pfsyncif.sc_ptr = NULL; + pfsyncif.sc_count = 8; ifp = &pfsyncif.sc_if; strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname); ifp->if_softc = &pfsyncif; @@ -120,10 +199,9 @@ pfsyncattach(int npfsync) ifp->if_type = IFT_PFSYNC; ifp->if_snd.ifq_maxlen = ifqmaxlen; ifp->if_hdrlen = PFSYNC_HDRLEN; + ifp->if_baudrate = IF_Mbps(100); 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); @@ -131,6 +209,7 @@ pfsyncattach(int npfsync) bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN); #endif } +#endif /* * Start output on the pfsync interface. @@ -143,8 +222,15 @@ pfsyncstart(struct ifnet *ifp) for (;;) { s = splimp(); +#ifdef __FreeBSD__ + IF_LOCK(&ifp->if_snd); + _IF_DROP(&ifp->if_snd); + _IF_DEQUEUE(&ifp->if_snd, m); + IF_UNLOCK(&ifp->if_snd); +#else IF_DROP(&ifp->if_snd); IF_DEQUEUE(&ifp->if_snd, m); +#endif splx(s); if (m == NULL) @@ -155,451 +241,6 @@ pfsyncstart(struct ifnet *ifp) } int -pfsync_insert_net_state(struct pfsync_state *sp) -{ - struct pf_state *st = NULL; - struct pf_rule *r = NULL; - struct pfi_kif *kif; - - 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_lookup_create(sp->ifname); - if (kif == NULL) { - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync_insert_net_state: " - "unknown interface: %s\n", sp->ifname); - /* skip this state */ - return (0); - } - - /* - * Just use the default rule until we have infrastructure to find the - * best matching 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_maybe_destroy(kif); - return (ENOMEM); - } - bzero(st, sizeof(*st)); - - st->rule.ptr = r; - /* XXX get pointers to nat_rule and anchor */ - - /* fill in the rest of the state entry */ - pf_state_host_ntoh(&sp->lan, &st->lan); - pf_state_host_ntoh(&sp->gwy, &st->gwy); - pf_state_host_ntoh(&sp->ext, &st->ext); - - pf_state_peer_ntoh(&sp->src, &st->src); - pf_state_peer_ntoh(&sp->dst, &st->dst); - - bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr)); - st->creation = ntohl(sp->creation) + time.tv_sec; - st->expire = ntohl(sp->expire) + time.tv_sec; - - st->af = sp->af; - st->proto = sp->proto; - st->direction = sp->direction; - st->log = sp->log; - st->timeout = sp->timeout; - st->allow_opts = sp->allow_opts; - - bcopy(sp->id, &st->id, sizeof(st->id)); - st->creatorid = sp->creatorid; - st->sync_flags = sp->sync_flags | PFSTATE_FROMSYNC; - - - if (pf_insert_state(kif, st)) { - pfi_maybe_destroy(kif); - pool_put(&pf_state_pl, st); - return (EINVAL); - } - - return (0); -} - -void -pfsync_input(struct mbuf *m, ...) -{ - struct ip *ip = mtod(m, struct ip *); - struct pfsync_header *ph; - struct pfsync_softc *sc = &pfsyncif; - 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 in_addr src; - struct mbuf *mp; - int iplen, action, error, i, s, count, offp; - - pfsyncstats.pfsyncs_ipackets++; - - /* verify that we have a sync interface configured */ - if (!sc->sc_sync_ifp || !pf_status.running) - goto done; - - /* verify that the packet came in on the right interface */ - if (sc->sc_sync_ifp != m->m_pkthdr.rcvif) { - pfsyncstats.pfsyncs_badif++; - goto done; - } - - /* verify that the IP TTL is 255. */ - if (ip->ip_ttl != PFSYNC_DFLTTL) { - pfsyncstats.pfsyncs_badttl++; - goto done; - } - - iplen = ip->ip_hl << 2; - - if (m->m_pkthdr.len < iplen + sizeof(*ph)) { - pfsyncstats.pfsyncs_hdrops++; - goto done; - } - - if (iplen + sizeof(*ph) > m->m_len) { - if ((m = m_pullup(m, iplen + sizeof(*ph))) == NULL) { - pfsyncstats.pfsyncs_hdrops++; - goto done; - } - ip = mtod(m, struct ip *); - } - ph = (struct pfsync_header *)((char *)ip + iplen); - - /* verify the version */ - if (ph->version != PFSYNC_VERSION) { - pfsyncstats.pfsyncs_badver++; - goto done; - } - - action = ph->action; - count = ph->count; - - /* make sure it's a valid action code */ - if (action >= PFSYNC_ACT_MAX) { - pfsyncstats.pfsyncs_badact++; - goto done; - } - - /* Cheaper to grab this now than having to mess with mbufs later */ - src = ip->ip_src; - - switch (action) { - case PFSYNC_ACT_CLR: { - struct pfi_kif *kif; - u_int32_t creatorid; - if ((mp = m_pulldown(m, iplen + sizeof(*ph), - sizeof(*cp), &offp)) == NULL) { - pfsyncstats.pfsyncs_badlen++; - return; - } - cp = (struct pfsync_state_clr *)(mp->m_data + offp); - creatorid = cp->creatorid; - - s = splsoftnet(); - if (cp->ifname[0] == '\0') { - RB_FOREACH(st, pf_state_tree_id, &tree_id) { - if (st->creatorid == creatorid) - st->timeout = PFTM_PURGE; - } - } else { - 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); - goto done; - } - RB_FOREACH(st, pf_state_tree_lan_ext, - &kif->pfik_lan_ext) { - if (st->creatorid == creatorid) - st->timeout = PFTM_PURGE; - } - } - pf_purge_expired_states(); - splx(s); - - break; - } - case PFSYNC_ACT_INS: - if ((mp = m_pulldown(m, iplen + sizeof(*ph), - count * sizeof(*sp), &offp)) == NULL) { - pfsyncstats.pfsyncs_badlen++; - return; - } - - s = splsoftnet(); - for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); - i < count; i++, sp++) { - /* check for invalid values */ - if (sp->timeout >= PFTM_MAX || - sp->src.state > PF_TCPS_PROXY_DST || - sp->dst.state > PF_TCPS_PROXY_DST || - sp->direction > PF_OUT || - (sp->af != AF_INET && sp->af != AF_INET6)) { - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync_insert: PFSYNC_ACT_INS: " - "invalid value\n"); - pfsyncstats.pfsyncs_badstate++; - continue; - } - - if ((error = pfsync_insert_net_state(sp))) { - if (error == ENOMEM) { - splx(s); - goto done; - } - continue; - } - } - splx(s); - break; - case PFSYNC_ACT_UPD: - if ((mp = m_pulldown(m, iplen + sizeof(*ph), - count * sizeof(*sp), &offp)) == NULL) { - pfsyncstats.pfsyncs_badlen++; - return; - } - - s = splsoftnet(); - for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); - i < count; i++, sp++) { - /* check for invalid values */ - if (sp->timeout >= PFTM_MAX || - sp->src.state > PF_TCPS_PROXY_DST || - sp->dst.state > PF_TCPS_PROXY_DST) { - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync_insert: PFSYNC_ACT_UPD: " - "invalid value\n"); - pfsyncstats.pfsyncs_badstate++; - continue; - } - - bcopy(sp->id, &key.id, sizeof(key.id)); - key.creatorid = sp->creatorid; - - st = pf_find_state_byid(&key); - if (st == NULL) { - /* insert the update */ - if (pfsync_insert_net_state(sp)) - pfsyncstats.pfsyncs_badstate++; - continue; - } - pf_state_peer_ntoh(&sp->src, &st->src); - pf_state_peer_ntoh(&sp->dst, &st->dst); - st->expire = ntohl(sp->expire) + time.tv_sec; - st->timeout = sp->timeout; - - } - splx(s); - break; - /* - * It's not strictly necessary for us to support the "uncompressed" - * delete action, but it's relatively simple and maintains consistency. - */ - case PFSYNC_ACT_DEL: - if ((mp = m_pulldown(m, iplen + sizeof(*ph), - count * sizeof(*sp), &offp)) == NULL) { - pfsyncstats.pfsyncs_badlen++; - return; - } - - s = splsoftnet(); - for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); - i < count; i++, sp++) { - bcopy(sp->id, &key.id, sizeof(key.id)); - key.creatorid = sp->creatorid; - - st = pf_find_state_byid(&key); - if (st == NULL) { - pfsyncstats.pfsyncs_badstate++; - continue; - } - /* - * XXX - * pf_purge_expired_states() is expensive, - * we really want to purge the state directly. - */ - st->timeout = PFTM_PURGE; - st->sync_flags |= PFSTATE_FROMSYNC; - } - pf_purge_expired_states(); - splx(s); - break; - case PFSYNC_ACT_UPD_C: { - int update_requested = 0; - - if ((mp = m_pulldown(m, iplen + sizeof(*ph), - count * sizeof(*up), &offp)) == NULL) { - pfsyncstats.pfsyncs_badlen++; - return; - } - - s = splsoftnet(); - for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp); - i < count; i++, up++) { - /* check for invalid values */ - if (up->timeout >= PFTM_MAX || - up->src.state > PF_TCPS_PROXY_DST || - up->dst.state > PF_TCPS_PROXY_DST) { - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync_insert: " - "PFSYNC_ACT_UPD_C: " - "invalid value\n"); - pfsyncstats.pfsyncs_badstate++; - continue; - } - - bcopy(up->id, &key.id, sizeof(key.id)); - key.creatorid = up->creatorid; - - st = pf_find_state_byid(&key); - if (st == NULL) { - /* We don't have this state. Ask for it. */ - pfsync_request_update(up, &src); - update_requested = 1; - pfsyncstats.pfsyncs_badstate++; - continue; - } - pf_state_peer_ntoh(&up->src, &st->src); - pf_state_peer_ntoh(&up->dst, &st->dst); - st->expire = ntohl(up->expire) + time.tv_sec; - st->timeout = up->timeout; - } - if (update_requested) - pfsync_sendout(sc); - splx(s); - break; - } - case PFSYNC_ACT_DEL_C: - if ((mp = m_pulldown(m, iplen + sizeof(*ph), - count * sizeof(*dp), &offp)) == NULL) { - pfsyncstats.pfsyncs_badlen++; - return; - } - - s = splsoftnet(); - for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp); - i < count; i++, dp++) { - bcopy(dp->id, &key.id, sizeof(key.id)); - key.creatorid = dp->creatorid; - - st = pf_find_state_byid(&key); - if (st == NULL) { - pfsyncstats.pfsyncs_badstate++; - continue; - } - /* - * XXX - * pf_purge_expired_states() is expensive, - * we really want to purge the state directly. - */ - st->timeout = PFTM_PURGE; - st->sync_flags |= PFSTATE_FROMSYNC; - } - pf_purge_expired_states(); - splx(s); - break; - case PFSYNC_ACT_INS_F: - case PFSYNC_ACT_DEL_F: - /* not implemented */ - break; - case PFSYNC_ACT_UREQ: - if ((mp = m_pulldown(m, iplen + sizeof(*ph), - count * sizeof(*rup), &offp)) == NULL) { - pfsyncstats.pfsyncs_badlen++; - return; - } - - s = splsoftnet(); - /* XXX send existing. pfsync_pack_state should handle this. */ - if (sc->sc_mbuf != NULL) - pfsync_sendout(sc); - for (i = 0, - rup = (struct pfsync_state_upd_req *)(mp->m_data + offp); - i < count; i++, rup++) { - bcopy(rup->id, &key.id, sizeof(key.id)); - key.creatorid = rup->creatorid; - - if (key.id == 0 && key.creatorid == 0) { - sc->sc_ureq_received = mono_time.tv_sec; - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync: received " - "bulk update request\n"); - pfsync_send_bus(sc, PFSYNC_BUS_START); - timeout_add(&sc->sc_bulk_tmo, 1 * hz); - } else { - st = pf_find_state_byid(&key); - if (st == NULL) { - pfsyncstats.pfsyncs_badstate++; - continue; - } - pfsync_pack_state(PFSYNC_ACT_UPD, st, 0); - } - } - if (sc->sc_mbuf != NULL) - pfsync_sendout(sc); - splx(s); - break; - case PFSYNC_ACT_BUS: - /* If we're not waiting for a bulk update, who cares. */ - if (sc->sc_ureq_sent == 0) - break; - - if ((mp = m_pulldown(m, iplen + sizeof(*ph), - sizeof(*bus), &offp)) == NULL) { - pfsyncstats.pfsyncs_badlen++; - return; - } - bus = (struct pfsync_state_bus *)(mp->m_data + offp); - switch (bus->status) { - case PFSYNC_BUS_START: - timeout_add(&sc->sc_bulkfail_tmo, - pf_pool_limits[PF_LIMIT_STATES].limit / - (PFSYNC_BULKPACKETS * sc->sc_maxcount)); - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync: received bulk " - "update start\n"); - break; - case PFSYNC_BUS_END: - if (mono_time.tv_sec - ntohl(bus->endtime) >= - sc->sc_ureq_sent) { - /* that's it, we're happy */ - sc->sc_ureq_sent = 0; - sc->sc_bulk_tries = 0; - timeout_del(&sc->sc_bulkfail_tmo); - pfsync_sync_ok = 1; - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync: received valid " - "bulk update end\n"); - } else { - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync: received invalid " - "bulk update end: bad timestamp\n"); - } - break; - } - break; - } - -done: - if (m) - m_freem(m); -} - -int pfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt) { @@ -611,13 +252,9 @@ pfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, int pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct proc *p = curproc; struct pfsync_softc *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *)data; - struct ip_moptions *imo = &sc->sc_imo; - struct pfsyncreq pfsyncr; - struct ifnet *sifp; - int s, error; + int s; switch (cmd) { case SIOCSIFADDR: @@ -640,84 +277,6 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) pfsync_setmtu(sc, ifr->ifr_mtu); splx(s); break; - case SIOCGETPFSYNC: - bzero(&pfsyncr, sizeof(pfsyncr)); - if (sc->sc_sync_ifp) - strlcpy(pfsyncr.pfsyncr_syncif, - sc->sc_sync_ifp->if_xname, IFNAMSIZ); - pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates; - if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr)))) - return (error); - break; - case SIOCSETPFSYNC: - if ((error = suser(p, p->p_acflag)) != 0) - return (error); - if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr)))) - return (error); - - if (pfsyncr.pfsyncr_maxupdates > 255) - return (EINVAL); - sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates; - - if (pfsyncr.pfsyncr_syncif[0] == 0) { - sc->sc_sync_ifp = NULL; - if (sc->sc_mbuf_net != NULL) { - /* Don't keep stale pfsync packets around. */ - s = splnet(); - m_freem(sc->sc_mbuf_net); - sc->sc_mbuf_net = NULL; - sc->sc_statep_net.s = NULL; - splx(s); - } - break; - } - if ((sifp = ifunit(pfsyncr.pfsyncr_syncif)) == NULL) - return (EINVAL); - else if (sifp == sc->sc_sync_ifp) - break; - - s = splnet(); - if (sifp->if_mtu < sc->sc_if.if_mtu || - (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; - - pfsync_setmtu(sc, sc->sc_if.if_mtu); - - if (imo->imo_num_memberships > 0) { - in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); - imo->imo_multicast_ifp = NULL; - } - - if (sc->sc_sync_ifp) { - struct in_addr addr; - - addr.s_addr = INADDR_PFSYNC_GROUP; - if ((imo->imo_membership[0] = - in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) { - splx(s); - return (ENOBUFS); - } - imo->imo_num_memberships++; - imo->imo_multicast_ifp = sc->sc_sync_ifp; - imo->imo_multicast_ttl = PFSYNC_DFLTTL; - imo->imo_multicast_loop = 0; - - /* Request a full state table update. */ - sc->sc_ureq_sent = mono_time.tv_sec; - pfsync_sync_ok = 0; - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync: requesting bulk update\n"); - timeout_add(&sc->sc_bulkfail_tmo, 5 * hz); - pfsync_request_update(NULL, NULL); - pfsync_sendout(sc); - } - splx(s); - - break; - default: return (ENOTTY); } @@ -726,26 +285,24 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } void -pfsync_setmtu(struct pfsync_softc *sc, int mtu_req) -{ +pfsync_setmtu(sc, mtu) + struct pfsync_softc *sc; int mtu; - - if (sc->sc_sync_ifp && sc->sc_sync_ifp->if_mtu < mtu_req) - mtu = sc->sc_sync_ifp->if_mtu; - else - mtu = mtu_req; - - sc->sc_maxcount = (mtu - sizeof(struct pfsync_header)) / - sizeof(struct pfsync_state); - if (sc->sc_maxcount > 254) - sc->sc_maxcount = 254; +{ + sc->sc_count = (mtu - sizeof(struct pfsync_header)) / + sizeof(struct pf_state); sc->sc_if.if_mtu = sizeof(struct pfsync_header) + - sc->sc_maxcount * sizeof(struct pfsync_state); + sc->sc_count * sizeof(struct pf_state); } struct mbuf * -pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp) +pfsync_get_mbuf(sc, action) + struct pfsync_softc *sc; + u_int8_t action; { +#ifndef __FreeBSD__ + extern int hz; +#endif struct pfsync_header *h; struct mbuf *m; int len; @@ -756,33 +313,7 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp) return (NULL); } - switch (action) { - case PFSYNC_ACT_CLR: - len = sizeof(struct pfsync_header) + - sizeof(struct pfsync_state_clr); - break; - case PFSYNC_ACT_UPD_C: - len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd)) + - sizeof(struct pfsync_header); - break; - case PFSYNC_ACT_DEL_C: - len = (sc->sc_maxcount * sizeof(struct pfsync_state_del)) + - sizeof(struct pfsync_header); - break; - case PFSYNC_ACT_UREQ: - len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd_req)) + - sizeof(struct pfsync_header); - break; - case PFSYNC_ACT_BUS: - len = sizeof(struct pfsync_header) + - sizeof(struct pfsync_state_bus); - break; - default: - len = (sc->sc_maxcount * sizeof(struct pfsync_state)) + - sizeof(struct pfsync_header); - break; - } - + len = sc->sc_if.if_mtu; if (len > MHLEN) { MCLGET(m, M_DONTWAIT); if ((m->m_flags & M_EXT) == 0) { @@ -790,286 +321,146 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp) sc->sc_if.if_oerrors++; return (NULL); } - m->m_data += (MCLBYTES - len) &~ (sizeof(long) - 1); - } else - MH_ALIGN(m, len); - + } m->m_pkthdr.rcvif = NULL; - m->m_pkthdr.len = m->m_len = sizeof(struct pfsync_header); + m->m_pkthdr.len = m->m_len = len; + h = mtod(m, struct pfsync_header *); h->version = PFSYNC_VERSION; h->af = 0; h->count = 0; h->action = action; - *sp = (void *)((char *)h + PFSYNC_HDRLEN); + sc->sc_mbuf = m; + sc->sc_ptr = (struct pf_state *)((char *)h + PFSYNC_HDRLEN); +#ifdef __FreeBSD__ + callout_reset(&sc->sc_tmo, hz, pfsync_timeout, + LIST_FIRST(&pfsync_list)); +#else timeout_add(&sc->sc_tmo, hz); +#endif + return (m); } +/* + * XXX: This function should be called with PF_LOCK held as it references + * pf_state. + */ int -pfsync_pack_state(u_int8_t action, struct pf_state *st, int compress) +pfsync_pack_state(action, st) + u_int8_t action; + struct pf_state *st; { +#ifdef __FreeBSD__ + struct pfsync_softc *sc = LIST_FIRST(&pfsync_list); +#else + extern struct timeval time; struct ifnet *ifp = &pfsyncif.sc_if; struct pfsync_softc *sc = ifp->if_softc; - struct pfsync_header *h, *h_net; - struct pfsync_state *sp = NULL; - struct pfsync_state_upd *up = NULL; - struct pfsync_state_del *dp = NULL; - struct pf_rule *r; +#endif + struct pfsync_header *h; + struct pf_state *sp; + struct pf_rule *r = st->rule.ptr; + struct mbuf *m; u_long secs; - int s, ret = 0; - u_int8_t i = 255, newaction = 0; - - /* - * 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) { - /* Don't leave any stale pfsync packets hanging around. */ - if (sc->sc_mbuf != NULL) { - m_freem(sc->sc_mbuf); - sc->sc_mbuf = NULL; - sc->sc_statep.s = NULL; - } - return (0); - } + int s, ret; if (action >= PFSYNC_ACT_MAX) return (EINVAL); +#ifdef __FreeBSD__ + /* + * XXX + * If we need to check mutex owned, PF_LOCK should be + * declared in pflog.ko. + * + * PF_LOCK_ASSERT(); + */ + KASSERT((!LIST_EMPTY(&pfsync_list)), ("pfsync: no interface")); +#endif s = splnet(); - if (sc->sc_mbuf == NULL) { - if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action, - (void *)&sc->sc_statep.s)) == NULL) { + m = sc->sc_mbuf; + if (m == NULL) { + if ((m = pfsync_get_mbuf(sc, action)) == NULL) { splx(s); return (ENOMEM); } - h = mtod(sc->sc_mbuf, struct pfsync_header *); + h = mtod(m, struct pfsync_header *); } else { - h = mtod(sc->sc_mbuf, struct pfsync_header *); + h = mtod(m, struct pfsync_header *); if (h->action != action) { pfsync_sendout(sc); - if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action, - (void *)&sc->sc_statep.s)) == NULL) { + if ((m = pfsync_get_mbuf(sc, action)) == NULL) { splx(s); return (ENOMEM); } - h = mtod(sc->sc_mbuf, struct pfsync_header *); - } else { - /* - * If it's an update, look in the packet to see if - * we already have an update for the state. - */ - if (action == PFSYNC_ACT_UPD && sc->sc_maxupdates) { - struct pfsync_state *usp = - (void *)((char *)h + PFSYNC_HDRLEN); - - for (i = 0; i < h->count; i++) { - if (!memcmp(usp->id, &st->id, - PFSYNC_ID_LEN) && - usp->creatorid == st->creatorid) { - sp = usp; - sp->updates++; - break; - } - usp++; - } - } + h = mtod(m, struct pfsync_header *); } } - secs = time.tv_sec; + sp = sc->sc_ptr++; + h->count++; + bzero(sp, sizeof(*sp)); - st->pfsync_time = mono_time.tv_sec; - 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 */ - i = 255; - sp = sc->sc_statep.s++; - sc->sc_mbuf->m_pkthdr.len = - sc->sc_mbuf->m_len += sizeof(struct pfsync_state); - h->count++; - bzero(sp, sizeof(*sp)); - - bcopy(&st->id, sp->id, sizeof(sp->id)); - sp->creatorid = st->creatorid; - - strlcpy(sp->ifname, st->u.s.kif->pfik_name, sizeof(sp->ifname)); - pf_state_host_hton(&st->lan, &sp->lan); - pf_state_host_hton(&st->gwy, &sp->gwy); - pf_state_host_hton(&st->ext, &sp->ext); - - bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); - - sp->creation = htonl(secs - st->creation); - 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 - sp->rule = htonl(r->nr); - if ((r = st->anchor.ptr) == NULL) - sp->anchor = htonl(-1); - else - sp->anchor = htonl(r->nr); - sp->af = st->af; - sp->proto = st->proto; - sp->direction = st->direction; - sp->log = st->log; - sp->allow_opts = st->allow_opts; - sp->timeout = st->timeout; - - sp->sync_flags = st->sync_flags & PFSTATE_NOSYNC; - } + bcopy(&st->lan, &sp->lan, sizeof(sp->lan)); + bcopy(&st->gwy, &sp->gwy, sizeof(sp->gwy)); + bcopy(&st->ext, &sp->ext, sizeof(sp->ext)); pf_state_peer_hton(&st->src, &sp->src); pf_state_peer_hton(&st->dst, &sp->dst); + bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); +#ifdef __FreeBSD__ + secs = time_second; +#else + secs = time.tv_sec; +#endif + sp->creation = htonl(secs - st->creation); if (st->expire <= secs) sp->expire = htonl(0); else sp->expire = htonl(st->expire - secs); - - /* do we need to build "compressed" actions for network transfer? */ - if (sc->sc_sync_ifp && compress) { - switch (action) { - case PFSYNC_ACT_UPD: - newaction = PFSYNC_ACT_UPD_C; - break; - case PFSYNC_ACT_DEL: - newaction = PFSYNC_ACT_DEL_C; - break; - default: - /* by default we just send the uncompressed states */ - break; - } - } - - if (newaction) { - if (sc->sc_mbuf_net == NULL) { - if ((sc->sc_mbuf_net = pfsync_get_mbuf(sc, newaction, - (void *)&sc->sc_statep_net.s)) == NULL) { - splx(s); - return (ENOMEM); - } - } - h_net = mtod(sc->sc_mbuf_net, struct pfsync_header *); - - switch (newaction) { - case PFSYNC_ACT_UPD_C: - if (i != 255) { - up = (void *)((char *)h_net + - PFSYNC_HDRLEN + (i * sizeof(*up))); - up->updates++; - } else { - h_net->count++; - sc->sc_mbuf_net->m_pkthdr.len = - sc->sc_mbuf_net->m_len += sizeof(*up); - up = sc->sc_statep_net.u++; - - bzero(up, sizeof(*up)); - bcopy(&st->id, up->id, sizeof(up->id)); - up->creatorid = st->creatorid; - } - up->timeout = st->timeout; - up->expire = sp->expire; - up->src = sp->src; - up->dst = sp->dst; - break; - case PFSYNC_ACT_DEL_C: - sc->sc_mbuf_net->m_pkthdr.len = - sc->sc_mbuf_net->m_len += sizeof(*dp); - dp = sc->sc_statep_net.d++; - h_net->count++; - - bzero(dp, sizeof(*dp)); - bcopy(&st->id, dp->id, sizeof(dp->id)); - dp->creatorid = st->creatorid; - break; - } - } - - if (h->count == sc->sc_maxcount || - (sc->sc_maxupdates && (sp->updates >= sc->sc_maxupdates))) + 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 == NULL) + sp->rule.nr = htonl(-1); + else + sp->rule.nr = htonl(r->nr); + sp->af = st->af; + sp->proto = st->proto; + sp->direction = st->direction; + sp->log = st->log; + sp->allow_opts = st->allow_opts; + + ret = 0; + if (h->count == sc->sc_count) ret = pfsync_sendout(sc); splx(s); - return (ret); -} - -/* This must be called in splnet() */ -int -pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src) -{ - struct ifnet *ifp = &pfsyncif.sc_if; - struct pfsync_header *h; - struct pfsync_softc *sc = ifp->if_softc; - struct pfsync_state_upd_req *rup; - int s, ret; - - if (sc->sc_mbuf == NULL) { - if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ, - (void *)&sc->sc_statep.s)) == NULL) { - splx(s); - return (ENOMEM); - } - h = mtod(sc->sc_mbuf, struct pfsync_header *); - } else { - h = mtod(sc->sc_mbuf, struct pfsync_header *); - if (h->action != PFSYNC_ACT_UREQ) { - pfsync_sendout(sc); - if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ, - (void *)&sc->sc_statep.s)) == NULL) { - splx(s); - return (ENOMEM); - } - h = mtod(sc->sc_mbuf, struct pfsync_header *); - } - } - - if (src != NULL) - sc->sc_sendaddr = *src; - sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*rup); - h->count++; - rup = sc->sc_statep.r++; - bzero(rup, sizeof(*rup)); - if (up != NULL) { - bcopy(up->id, rup->id, sizeof(rup->id)); - rup->creatorid = up->creatorid; - } - - if (h->count == sc->sc_maxcount) - ret = pfsync_sendout(sc); - - return (ret); + return (0); } int -pfsync_clear_states(u_int32_t creatorid, char *ifname) +pfsync_clear_state(st) + struct pf_state *st; { +#ifdef __FreeBSD__ + struct pfsync_softc *sc = LIST_FIRST(&pfsync_list); +#else struct ifnet *ifp = &pfsyncif.sc_if; struct pfsync_softc *sc = ifp->if_softc; - struct pfsync_state_clr *cp; +#endif + struct mbuf *m = sc->sc_mbuf; int s, ret; s = splnet(); - if (sc->sc_mbuf != NULL) - pfsync_sendout(sc); - if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR, - (void *)&sc->sc_statep.c)) == NULL) { + if (m == NULL && (m = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR)) == NULL) { splx(s); return (ENOMEM); } - sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*cp); - cp = sc->sc_statep.c; - cp->creatorid = creatorid; - if (ifname != NULL) - strlcpy(cp->ifname, ifname, IFNAMSIZ); ret = (pfsync_sendout(sc)); splx(s); @@ -1082,162 +473,76 @@ pfsync_timeout(void *v) struct pfsync_softc *sc = v; int s; + /* We don't need PF_LOCK/PF_UNLOCK here! */ s = splnet(); pfsync_sendout(sc); splx(s); } -void -pfsync_send_bus(struct pfsync_softc *sc, u_int8_t status) -{ - struct pfsync_state_bus *bus; - - if (sc->sc_mbuf != NULL) - pfsync_sendout(sc); - - if (pfsync_sync_ok && - (sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_BUS, - (void *)&sc->sc_statep.b)) != NULL) { - sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*bus); - bus = sc->sc_statep.b; - bus->creatorid = pf_status.hostid; - bus->status = status; - bus->endtime = htonl(mono_time.tv_sec - sc->sc_ureq_received); - pfsync_sendout(sc); - } -} - -void -pfsync_bulk_update(void *v) -{ - struct pfsync_softc *sc = v; - int s, i = 0; - struct pf_state *state; - - s = splnet(); - if (sc->sc_mbuf != NULL) - pfsync_sendout(sc); - - /* - * Grab at most PFSYNC_BULKPACKETS worth of states which have not - * been sent since the latest request was made. - */ - 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; - timeout_del(&sc->sc_bulk_tmo); - 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); - state->pfsync_time = mono_time.tv_sec; - 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 */ - timeout_add(&sc->sc_bulk_tmo, 1); - } - } - if (sc->sc_mbuf != NULL) - pfsync_sendout(sc); - splx(s); -} - -void -pfsync_bulkfail(void *v) -{ - struct pfsync_softc *sc = v; - - if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) { - /* Try again in a bit */ - timeout_add(&sc->sc_bulkfail_tmo, 5 * hz); - pfsync_request_update(NULL, NULL); - pfsync_sendout(sc); - } else { - /* Pretend like the transfer was ok */ - sc->sc_ureq_sent = 0; - sc->sc_bulk_tries = 0; - pfsync_sync_ok = 1; - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync: failed to receive " - "bulk update status\n"); - timeout_del(&sc->sc_bulkfail_tmo); - } -} - int pfsync_sendout(sc) struct pfsync_softc *sc; { struct ifnet *ifp = &sc->sc_if; - struct mbuf *m; + struct mbuf *m = sc->sc_mbuf; +#ifdef __FreeBSD__ + callout_stop(&sc->sc_tmo); +#else timeout_del(&sc->sc_tmo); - - if (sc->sc_mbuf == NULL) - return (0); - m = sc->sc_mbuf; +#endif sc->sc_mbuf = NULL; - sc->sc_statep.s = NULL; + sc->sc_ptr = NULL; +#ifdef __FreeBSD__ + KASSERT(m != NULL, ("pfsync_sendout: null mbuf")); +#endif #if NBPFILTER > 0 if (ifp->if_bpf) bpf_mtap(ifp->if_bpf, m); #endif - if (sc->sc_mbuf_net) { - m_freem(m); - m = sc->sc_mbuf_net; - sc->sc_mbuf_net = NULL; - sc->sc_statep_net.s = NULL; - } + m_freem(m); + + return (0); +} - if (sc->sc_sync_ifp) { - struct ip *ip; - struct ifaddr *ifa; - struct sockaddr sa; - M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); - if (m == NULL) { - pfsyncstats.pfsyncs_onomem++; - return (0); - } - ip = mtod(m, struct ip *); - ip->ip_v = IPVERSION; - ip->ip_hl = sizeof(*ip) >> 2; - ip->ip_tos = IPTOS_LOWDELAY; - ip->ip_len = htons(m->m_pkthdr.len); - ip->ip_id = htons(ip_randomid()); - ip->ip_off = htons(IP_DF); - ip->ip_ttl = PFSYNC_DFLTTL; - ip->ip_p = IPPROTO_PFSYNC; - ip->ip_sum = 0; - - bzero(&sa, sizeof(sa)); - sa.sa_family = AF_INET; - ifa = ifaof_ifpforaddr(&sa, sc->sc_sync_ifp); - if (ifa == NULL) - return (0); - ip->ip_src.s_addr = ifatoia(ifa)->ia_addr.sin_addr.s_addr; - - if (sc->sc_sendaddr.s_addr == INADDR_PFSYNC_GROUP) - m->m_flags |= M_MCAST; - ip->ip_dst = sc->sc_sendaddr; - sc->sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP; - - pfsyncstats.pfsyncs_opackets++; - - if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)) - pfsyncstats.pfsyncs_oerrors++; - } else - m_freem(m); +#ifdef __FreeBSD__ +static int +pfsync_modevent(module_t mod, int type, void *data) +{ + int error = 0; - return (0); + switch (type) { + case MOD_LOAD: + LIST_INIT(&pfsync_list); + if_clone_attach(&pfsync_cloner); + break; + + case MOD_UNLOAD: + if_clone_detach(&pfsync_cloner); + while (!LIST_EMPTY(&pfsync_list)) + pfsync_clone_destroy( + &LIST_FIRST(&pfsync_list)->sc_if); + break; + + default: + error = EINVAL; + break; + } + + return error; } + +static moduledata_t pfsync_mod = { + "pfsync", + pfsync_modevent, + 0 +}; + +#define PFSYNC_MODVER 1 + +DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PSEUDO, 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 b3705c8..23539ba 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.13 2004/03/22 04:54:17 mcbride Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: if_pfsync.h,v 1.2 2002/12/11 18:31:26 mickey Exp $ */ /* * Copyright (c) 2001 Michael Shalayeff @@ -29,208 +30,47 @@ #ifndef _NET_IF_PFSYNC_H_ #define _NET_IF_PFSYNC_H_ - -#define PFSYNC_ID_LEN sizeof(u_int64_t) - -struct pfsync_state_scrub { - u_int16_t pfss_flags; - u_int8_t pfss_ttl; /* stashed TTL */ - u_int8_t scrub_flag; - u_int32_t pfss_ts_mod; /* timestamp modulation */ -} __packed; - -struct pfsync_state_host { - struct pf_addr addr; - u_int16_t port; - u_int16_t pad[3]; -} __packed; - -struct pfsync_state_peer { - struct pfsync_state_scrub scrub; /* state is scrubbed */ - u_int32_t seqlo; /* Max sequence number sent */ - u_int32_t seqhi; /* Max the other end ACKd + win */ - u_int32_t seqdiff; /* Sequence number modulator */ - u_int16_t max_win; /* largest window (pre scaling) */ - 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 scrub_flag; - u_int8_t pad[5]; -} __packed; - -struct pfsync_state { - u_int32_t id[2]; - char ifname[IFNAMSIZ]; - struct pfsync_state_host lan; - struct pfsync_state_host gwy; - struct pfsync_state_host ext; - struct pfsync_state_peer src; - struct pfsync_state_peer dst; - struct pf_addr rt_addr; - u_int32_t rule; - u_int32_t anchor; - u_int32_t nat_rule; - u_int32_t creation; - u_int32_t expire; - u_int32_t packets[2]; - u_int32_t bytes[2]; - u_int32_t creatorid; - 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; - u_int8_t updates; -} __packed; - -struct pfsync_state_upd { - u_int32_t id[2]; - struct pfsync_state_peer src; - struct pfsync_state_peer dst; - u_int32_t creatorid; - u_int32_t expire; - u_int8_t timeout; - u_int8_t updates; - u_int8_t pad[6]; -} __packed; - -struct pfsync_state_del { - u_int32_t id[2]; - u_int32_t creatorid; - struct { - u_int8_t state; - } src; - struct { - u_int8_t state; - } dst; - u_int8_t pad[2]; -} __packed; - -struct pfsync_state_upd_req { - u_int32_t id[2]; - u_int32_t creatorid; - u_int32_t pad; -} __packed; - -struct pfsync_state_clr { - char ifname[IFNAMSIZ]; - u_int32_t creatorid; - u_int32_t pad; -} __packed; - -struct pfsync_state_bus { - u_int32_t creatorid; - u_int32_t endtime; - u_int8_t status; -#define PFSYNC_BUS_START 1 -#define PFSYNC_BUS_END 2 - u_int8_t pad[7]; -} __packed; - #ifdef _KERNEL - -union sc_statep { - struct pfsync_state *s; - struct pfsync_state_upd *u; - struct pfsync_state_del *d; - struct pfsync_state_clr *c; - struct pfsync_state_bus *b; - struct pfsync_state_upd_req *r; -}; - -extern int pfsync_sync_ok; - struct pfsync_softc { - struct ifnet sc_if; - struct ifnet *sc_sync_ifp; + struct ifnet sc_if; - struct ip_moptions sc_imo; - struct timeout sc_tmo; - struct timeout sc_bulk_tmo; - struct timeout sc_bulkfail_tmo; - struct in_addr sc_sendaddr; - struct mbuf *sc_mbuf; /* current cummulative mbuf */ - struct mbuf *sc_mbuf_net; /* current cummulative mbuf */ - union sc_statep sc_statep; - union sc_statep sc_statep_net; - u_int32_t sc_ureq_received; - u_int32_t sc_ureq_sent; - int sc_bulk_tries; - int sc_maxcount; /* number of states in mtu */ - int sc_maxupdates; /* number of updates/state */ +#ifdef __FreeBSD__ + struct callout sc_tmo; +#else + struct timeout sc_tmo; +#endif + struct mbuf *sc_mbuf; /* current cummulative mbuf */ + struct pf_state *sc_ptr; /* current ongoing state */ + int sc_count; /* number of states in one mtu */ +#ifdef __FreeBSD__ + LIST_ENTRY(pfsync_softc) sc_next; +#endif }; #endif - struct pfsync_header { u_int8_t version; -#define PFSYNC_VERSION 2 +#define PFSYNC_VERSION 1 u_int8_t af; u_int8_t action; -#define PFSYNC_ACT_CLR 0 /* clear all states */ -#define PFSYNC_ACT_INS 1 /* insert state */ -#define PFSYNC_ACT_UPD 2 /* update state */ -#define PFSYNC_ACT_DEL 3 /* delete state */ -#define PFSYNC_ACT_UPD_C 4 /* "compressed" state update */ -#define PFSYNC_ACT_DEL_C 5 /* "compressed" state delete */ -#define PFSYNC_ACT_INS_F 6 /* insert fragment */ -#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_MAX 10 +#define PFSYNC_ACT_CLR 0 +#define PFSYNC_ACT_INS 1 +#define PFSYNC_ACT_UPD 2 +#define PFSYNC_ACT_DEL 3 +#define PFSYNC_ACT_MAX 4 u_int8_t count; -} __packed; +}; -#define PFSYNC_BULKPACKETS 1 /* # of packets per timeout */ -#define PFSYNC_MAX_BULKTRIES 12 #define PFSYNC_HDRLEN sizeof(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" - -#define PFSYNC_DFLTTL 255 - -struct pfsyncstats { - u_long pfsyncs_ipackets; /* total input packets, IPv4 */ - u_long pfsyncs_ipackets6; /* total input packets, IPv6 */ - u_long pfsyncs_badif; /* not the right interface */ - u_long pfsyncs_badttl; /* TTL is not PFSYNC_DFLTTL */ - u_long pfsyncs_hdrops; /* packets shorter than header */ - u_long pfsyncs_badver; /* bad (incl unsupp) version */ - u_long pfsyncs_badact; /* bad action */ - u_long pfsyncs_badlen; /* data length does not match */ - u_long pfsyncs_badauth; /* bad authentication */ - u_long pfsyncs_badstate; /* insert/lookup failed */ - - u_long pfsyncs_opackets; /* total output packets, IPv4 */ - u_long pfsyncs_opackets6; /* total output packets, IPv6 */ - u_long pfsyncs_onomem; /* no memory for an mbuf for a send */ - u_long pfsyncs_oerrors; /* ip output error */ -}; - -/* - * Configuration structure for SIOCSETPFSYNC SIOCGETPFSYNC - */ -struct pfsyncreq { - char pfsyncr_syncif[IFNAMSIZ]; - int pfsyncr_maxupdates; - int pfsyncr_authlevel; -}; -#define SIOCSETPFSYNC _IOW('i', 247, struct ifreq) -#define SIOCGETPFSYNC _IOWR('i', 248, struct ifreq) - + "CLR ST", "INS ST", "UPD ST", "DEL ST" #define pf_state_peer_hton(s,d) do { \ (d)->seqlo = htonl((s)->seqlo); \ (d)->seqhi = htonl((s)->seqhi); \ (d)->seqdiff = htonl((s)->seqdiff); \ (d)->max_win = htons((s)->max_win); \ - (d)->mss = htons((s)->mss); \ (d)->state = (s)->state; \ - (d)->wscale = (s)->wscale; \ } while (0) #define pf_state_peer_ntoh(s,d) do { \ @@ -238,43 +78,15 @@ struct pfsyncreq { (d)->seqhi = ntohl((s)->seqhi); \ (d)->seqdiff = ntohl((s)->seqdiff); \ (d)->max_win = ntohs((s)->max_win); \ - (d)->mss = ntohs((s)->mss); \ (d)->state = (s)->state; \ - (d)->wscale = (s)->wscale; \ -} while (0) - -#define pf_state_host_hton(s,d) do { \ - bcopy(&(s)->addr, &(d)->addr, sizeof((d)->addr)); \ - (d)->port = (s)->port; \ -} while (0) - -#define pf_state_host_ntoh(s,d) do { \ - bcopy(&(s)->addr, &(d)->addr, sizeof((d)->addr)); \ - (d)->port = (s)->port; \ } while (0) #ifdef _KERNEL -void pfsync_input(struct mbuf *, ...); -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 { \ - if ((st->rule.ptr->rule_flag & PFRULE_NOSYNC) || \ - (st->proto == IPPROTO_PFSYNC)) \ - st->sync_flags |= PFSTATE_NOSYNC; \ - else if (!st->sync_flags) \ - pfsync_pack_state(PFSYNC_ACT_INS, (st), 1); \ - st->sync_flags &= ~PFSTATE_FROMSYNC; \ -} while (0) -#define pfsync_update_state(st) do { \ - if (!st->sync_flags) \ - pfsync_pack_state(PFSYNC_ACT_UPD, (st), 1); \ - st->sync_flags &= ~PFSTATE_FROMSYNC; \ -} while (0) -#define pfsync_delete_state(st) do { \ - if (!st->sync_flags) \ - pfsync_pack_state(PFSYNC_ACT_DEL, (st), 1); \ - st->sync_flags &= ~PFSTATE_FROMSYNC; \ -} while (0) +int pfsync_clear_state(struct pf_state *); +int pfsync_pack_state(u_int8_t, struct pf_state *); +#define pfsync_insert_state(st) pfsync_pack_state(PFSYNC_ACT_INS, (st)) +#define pfsync_update_state(st) pfsync_pack_state(PFSYNC_ACT_UPD, (st)) +#define pfsync_delete_state(st) pfsync_pack_state(PFSYNC_ACT_DEL, (st)) #endif #endif /* _NET_IF_PFSYNC_H_ */ diff --git a/sys/contrib/pf/net/pf.c b/sys/contrib/pf/net/pf.c index 82113ec..46f45c8 100644 --- a/sys/contrib/pf/net/pf.c +++ b/sys/contrib/pf/net/pf.c @@ -1,8 +1,8 @@ -/* $OpenBSD: pf.c,v 1.433 2004/03/26 22:20:57 dhartmei Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: pf.c,v 1.389.2.4 2004/04/30 23:27:57 brad Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier - * Copyright (c) 2002,2003 Henning Brauer * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,9 +35,22 @@ * */ +#ifdef __FreeBSD__ +#include "opt_inet.h" +#include "opt_inet6.h" +#endif + +#ifdef __FreeBSD__ +#include "opt_bpf.h" +#include "opt_pf.h" +#define NBPFILTER DEV_BPF +#define NPFLOG DEV_PFLOG +#define NPFSYNC DEV_PFSYNC +#else #include "bpfilter.h" #include "pflog.h" #include "pfsync.h" +#endif #include <sys/param.h> #include <sys/systm.h> @@ -47,7 +60,11 @@ #include <sys/socketvar.h> #include <sys/kernel.h> #include <sys/time.h> +#ifdef __FreeBSD__ +#include <sys/sysctl.h> +#else #include <sys/pool.h> +#endif #include <net/if.h> #include <net/if_types.h> @@ -69,23 +86,48 @@ #include <netinet/udp_var.h> #include <netinet/icmp_var.h> +#ifndef __FreeBSD__ #include <dev/rndvar.h> +#endif #include <net/pfvar.h> #include <net/if_pflog.h> - -#if NPFSYNC > 0 #include <net/if_pfsync.h> -#endif /* NPFSYNC > 0 */ #ifdef INET6 #include <netinet/ip6.h> #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 ALTQ +#include <altq/if_altq.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/in_cksum.h> +#if (__FreeBSD_version >= 500112) +#include <sys/limits.h> +#else +#include <machine/limits.h> +#endif +#include <sys/ucred.h> +#endif + +#ifdef __FreeBSD__ +extern int ip_optcopy(struct ip *, struct ip *); +#if (__FreeBSD_version < 501105) +int ip_fragment(struct ip *ip, struct mbuf **m_frag, int mtu, + u_long if_hwassist_flags, int sw_csum); +#endif +#endif #define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x +struct pf_state_tree; /* * Global variables @@ -98,17 +140,31 @@ struct pf_palist pf_pabuf; struct pf_altqqueue *pf_altqs_active; struct pf_altqqueue *pf_altqs_inactive; struct pf_status pf_status; +struct ifnet *status_ifp; u_int32_t ticket_altqs_active; 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 pool pf_src_tree_pl, pf_rule_pl; +#ifdef __FreeBSD__ +uma_zone_t pf_tree_pl, pf_rule_pl, pf_addr_pl; +uma_zone_t pf_state_pl, pf_altq_pl, pf_pooladdr_pl; +#else +struct pool pf_tree_pl, pf_rule_pl, pf_addr_pl; struct pool pf_state_pl, pf_altq_pl, pf_pooladdr_pl; +#endif +void pf_dynaddr_update(void *); +#ifdef __FreeBSD__ +void pf_dynaddr_update_event(void *arg, struct ifnet *ifp); +#endif void pf_print_host(struct pf_addr *, u_int16_t, u_int8_t); void pf_print_state(struct pf_state *); void pf_print_flags(u_int8_t); @@ -133,62 +189,62 @@ void pf_send_tcp(const struct pf_rule *, sa_family_t, 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 *, - int, int, struct pfi_kif *, + int, int, struct ifnet *, struct pf_addr *, u_int16_t, struct pf_addr *, u_int16_t, int); struct pf_rule *pf_get_translation(struct pf_pdesc *, struct mbuf *, - int, int, struct pfi_kif *, struct pf_src_node **, + int, int, struct ifnet *, struct pf_addr *, u_int16_t, struct pf_addr *, u_int16_t, struct pf_addr *, u_int16_t *); int pf_test_tcp(struct pf_rule **, struct pf_state **, - int, struct pfi_kif *, struct mbuf *, int, + int, struct ifnet *, struct mbuf *, int, int, void *, struct pf_pdesc *, struct pf_rule **, struct pf_ruleset **); int pf_test_udp(struct pf_rule **, struct pf_state **, - int, struct pfi_kif *, struct mbuf *, int, + int, struct ifnet *, struct mbuf *, int, int, void *, struct pf_pdesc *, struct pf_rule **, struct pf_ruleset **); int pf_test_icmp(struct pf_rule **, struct pf_state **, - int, struct pfi_kif *, struct mbuf *, int, + int, struct ifnet *, struct mbuf *, int, int, void *, struct pf_pdesc *, struct pf_rule **, struct pf_ruleset **); int pf_test_other(struct pf_rule **, struct pf_state **, - int, struct pfi_kif *, struct mbuf *, int, void *, + int, struct ifnet *, struct mbuf *, int, void *, struct pf_pdesc *, struct pf_rule **, struct pf_ruleset **); int pf_test_fragment(struct pf_rule **, int, - struct pfi_kif *, struct mbuf *, void *, + struct ifnet *, struct mbuf *, void *, struct pf_pdesc *, struct pf_rule **, struct pf_ruleset **); int pf_test_state_tcp(struct pf_state **, int, - struct pfi_kif *, struct mbuf *, int, + struct ifnet *, struct mbuf *, int, int, void *, struct pf_pdesc *, u_short *); int pf_test_state_udp(struct pf_state **, int, - struct pfi_kif *, struct mbuf *, int, + struct ifnet *, struct mbuf *, int, int, void *, struct pf_pdesc *); int pf_test_state_icmp(struct pf_state **, int, - struct pfi_kif *, struct mbuf *, int, + struct ifnet *, struct mbuf *, int, int, void *, struct pf_pdesc *); int pf_test_state_other(struct pf_state **, int, - struct pfi_kif *, struct pf_pdesc *); + struct ifnet *, struct pf_pdesc *); struct pf_tag *pf_get_tag(struct mbuf *); int pf_match_tag(struct mbuf *, struct pf_rule *, - struct pf_rule *, struct pf_tag *, int *); + struct pf_rule *, struct pf_rule *, + 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 *, +int pf_map_addr(u_int8_t, struct pf_pool *, struct pf_addr *, struct pf_addr *, - struct pf_addr *, struct pf_src_node **); -int pf_get_sport(sa_family_t, u_int8_t, struct pf_rule *, + struct pf_addr *); +int pf_get_sport(sa_family_t, u_int8_t, struct pf_pool *, struct pf_addr *, struct pf_addr *, u_int16_t, - struct pf_addr *, u_int16_t*, u_int16_t, u_int16_t, - struct pf_src_node **); + struct pf_addr *, u_int16_t*, u_int16_t, u_int16_t); void pf_route(struct mbuf **, struct pf_rule *, int, struct ifnet *, struct pf_state *); void pf_route6(struct mbuf **, struct pf_rule *, int, struct ifnet *, struct pf_state *); -int pf_socket_lookup(uid_t *, gid_t *, +int pf_socket_lookup(uid_t *, gid_t *, int, sa_family_t, int, struct pf_pdesc *); u_int8_t pf_get_wscale(struct mbuf *, int, u_int16_t, sa_family_t); @@ -202,24 +258,22 @@ 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 *, u_int8_t); -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 } -}; +#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_frent_pl, PFFRAG_FRENT_HIWAT } }; +#endif #define STATE_LOOKUP() \ do { \ if (direction == PF_IN) \ - *state = pf_find_state_recurse( \ - kif, &key, PF_EXT_GWY); \ + *state = pf_find_state(&tree_ext_gwy, &key); \ else \ - *state = pf_find_state_recurse( \ - kif, &key, PF_LAN_EXT); \ + *state = pf_find_state(&tree_lan_ext, &key); \ if (*state == NULL) \ return (PF_DROP); \ if (direction == PF_OUT && \ @@ -227,8 +281,8 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = { (*state)->rule.ptr->direction == PF_OUT) || \ ((*state)->rule.ptr->rt == PF_REPLYTO && \ (*state)->rule.ptr->direction == PF_IN)) && \ - (*state)->rt_kif != NULL && \ - (*state)->rt_kif != kif) \ + (*state)->rt_ifp != NULL && \ + (*state)->rt_ifp != ifp) \ return (PF_PASS); \ } while (0) @@ -240,145 +294,18 @@ 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) : \ - ((r)->rule_flag & PFRULE_GRBOUND) ? (k)->pfik_parent : \ - (k)->pfik_parent->pfik_parent) - -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 *); -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 *); - -struct pf_src_tree tree_src_tracking; - -struct pf_state_tree_id tree_id; -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, - u.s.entry_lan_ext, pf_state_compare_lan_ext); -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); - -static __inline int -pf_src_compare(struct pf_src_node *a, struct pf_src_node *b) -{ - int diff; - - if (a->rule.ptr > b->rule.ptr) - return (1); - if (a->rule.ptr < b->rule.ptr) - return (-1); - if ((diff = a->af - b->af) != 0) - return (diff); - switch (a->af) { -#ifdef INET - case AF_INET: - if (a->addr.addr32[0] > b->addr.addr32[0]) - return (1); - if (a->addr.addr32[0] < b->addr.addr32[0]) - return (-1); - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - if (a->addr.addr32[3] > b->addr.addr32[3]) - return (1); - if (a->addr.addr32[3] < b->addr.addr32[3]) - return (-1); - if (a->addr.addr32[2] > b->addr.addr32[2]) - return (1); - if (a->addr.addr32[2] < b->addr.addr32[2]) - return (-1); - if (a->addr.addr32[1] > b->addr.addr32[1]) - return (1); - if (a->addr.addr32[1] < b->addr.addr32[1]) - return (-1); - if (a->addr.addr32[0] > b->addr.addr32[0]) - return (1); - if (a->addr.addr32[0] < b->addr.addr32[0]) - return (-1); - break; -#endif /* INET6 */ - } - return (0); -} +static __inline int pf_state_compare(struct pf_tree_node *, + struct pf_tree_node *); -static __inline int -pf_state_compare_lan_ext(struct pf_state *a, struct pf_state *b) -{ - int diff; - - if ((diff = a->proto - b->proto) != 0) - return (diff); - if ((diff = a->af - b->af) != 0) - return (diff); - switch (a->af) { -#ifdef INET - case AF_INET: - if (a->lan.addr.addr32[0] > b->lan.addr.addr32[0]) - return (1); - if (a->lan.addr.addr32[0] < b->lan.addr.addr32[0]) - return (-1); - if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0]) - return (1); - if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0]) - return (-1); - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - if (a->lan.addr.addr32[3] > b->lan.addr.addr32[3]) - return (1); - if (a->lan.addr.addr32[3] < b->lan.addr.addr32[3]) - return (-1); - if (a->ext.addr.addr32[3] > b->ext.addr.addr32[3]) - return (1); - if (a->ext.addr.addr32[3] < b->ext.addr.addr32[3]) - return (-1); - if (a->lan.addr.addr32[2] > b->lan.addr.addr32[2]) - return (1); - if (a->lan.addr.addr32[2] < b->lan.addr.addr32[2]) - return (-1); - if (a->ext.addr.addr32[2] > b->ext.addr.addr32[2]) - return (1); - if (a->ext.addr.addr32[2] < b->ext.addr.addr32[2]) - return (-1); - if (a->lan.addr.addr32[1] > b->lan.addr.addr32[1]) - return (1); - if (a->lan.addr.addr32[1] < b->lan.addr.addr32[1]) - return (-1); - if (a->ext.addr.addr32[1] > b->ext.addr.addr32[1]) - return (1); - if (a->ext.addr.addr32[1] < b->ext.addr.addr32[1]) - return (-1); - if (a->lan.addr.addr32[0] > b->lan.addr.addr32[0]) - return (1); - if (a->lan.addr.addr32[0] < b->lan.addr.addr32[0]) - return (-1); - if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0]) - return (1); - if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0]) - return (-1); - break; -#endif /* INET6 */ - } - - if ((diff = a->lan.port - b->lan.port) != 0) - return (diff); - if ((diff = a->ext.port - b->ext.port) != 0) - return (diff); - - return (0); -} +struct pf_state_tree tree_lan_ext, tree_ext_gwy; +RB_GENERATE(pf_state_tree, pf_tree_node, entry, pf_state_compare); +#ifdef __FreeBSD__ +static int +#else static __inline int -pf_state_compare_ext_gwy(struct pf_state *a, struct pf_state *b) +#endif +pf_state_compare(struct pf_tree_node *a, struct pf_tree_node *b) { int diff; @@ -389,77 +316,62 @@ pf_state_compare_ext_gwy(struct pf_state *a, struct pf_state *b) switch (a->af) { #ifdef INET case AF_INET: - if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0]) + if (a->addr[0].addr32[0] > b->addr[0].addr32[0]) return (1); - if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0]) + if (a->addr[0].addr32[0] < b->addr[0].addr32[0]) return (-1); - if (a->gwy.addr.addr32[0] > b->gwy.addr.addr32[0]) + if (a->addr[1].addr32[0] > b->addr[1].addr32[0]) return (1); - if (a->gwy.addr.addr32[0] < b->gwy.addr.addr32[0]) + if (a->addr[1].addr32[0] < b->addr[1].addr32[0]) return (-1); break; #endif /* INET */ #ifdef INET6 case AF_INET6: - if (a->ext.addr.addr32[3] > b->ext.addr.addr32[3]) + if (a->addr[0].addr32[3] > b->addr[0].addr32[3]) return (1); - if (a->ext.addr.addr32[3] < b->ext.addr.addr32[3]) + if (a->addr[0].addr32[3] < b->addr[0].addr32[3]) return (-1); - if (a->gwy.addr.addr32[3] > b->gwy.addr.addr32[3]) + if (a->addr[1].addr32[3] > b->addr[1].addr32[3]) return (1); - if (a->gwy.addr.addr32[3] < b->gwy.addr.addr32[3]) + if (a->addr[1].addr32[3] < b->addr[1].addr32[3]) return (-1); - if (a->ext.addr.addr32[2] > b->ext.addr.addr32[2]) + if (a->addr[0].addr32[2] > b->addr[0].addr32[2]) return (1); - if (a->ext.addr.addr32[2] < b->ext.addr.addr32[2]) + if (a->addr[0].addr32[2] < b->addr[0].addr32[2]) return (-1); - if (a->gwy.addr.addr32[2] > b->gwy.addr.addr32[2]) + if (a->addr[1].addr32[2] > b->addr[1].addr32[2]) return (1); - if (a->gwy.addr.addr32[2] < b->gwy.addr.addr32[2]) + if (a->addr[1].addr32[2] < b->addr[1].addr32[2]) return (-1); - if (a->ext.addr.addr32[1] > b->ext.addr.addr32[1]) + if (a->addr[0].addr32[1] > b->addr[0].addr32[1]) return (1); - if (a->ext.addr.addr32[1] < b->ext.addr.addr32[1]) + if (a->addr[0].addr32[1] < b->addr[0].addr32[1]) return (-1); - if (a->gwy.addr.addr32[1] > b->gwy.addr.addr32[1]) + if (a->addr[1].addr32[1] > b->addr[1].addr32[1]) return (1); - if (a->gwy.addr.addr32[1] < b->gwy.addr.addr32[1]) + if (a->addr[1].addr32[1] < b->addr[1].addr32[1]) return (-1); - if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0]) + if (a->addr[0].addr32[0] > b->addr[0].addr32[0]) return (1); - if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0]) + if (a->addr[0].addr32[0] < b->addr[0].addr32[0]) return (-1); - if (a->gwy.addr.addr32[0] > b->gwy.addr.addr32[0]) + if (a->addr[1].addr32[0] > b->addr[1].addr32[0]) return (1); - if (a->gwy.addr.addr32[0] < b->gwy.addr.addr32[0]) + if (a->addr[1].addr32[0] < b->addr[1].addr32[0]) return (-1); break; #endif /* INET6 */ } - if ((diff = a->ext.port - b->ext.port) != 0) + if ((diff = a->port[0] - b->port[0]) != 0) return (diff); - if ((diff = a->gwy.port - b->gwy.port) != 0) + if ((diff = a->port[1] - b->port[1]) != 0) return (diff); return (0); } -static __inline int -pf_state_compare_id(struct pf_state *a, struct pf_state *b) -{ - if (a->id > b->id) - return (1); - if (a->id < b->id) - return (-1); - if (a->creatorid > b->creatorid) - return (1); - if (a->creatorid < b->creatorid) - return (-1); - - return (0); -} - #ifdef INET6 void pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af) @@ -481,140 +393,36 @@ pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af) #endif struct pf_state * -pf_find_state_byid(struct pf_state *key) +pf_find_state(struct pf_state_tree *tree, struct pf_tree_node *key) { - pf_status.fcounters[FCNT_STATE_SEARCH]++; - return (RB_FIND(pf_state_tree_id, &tree_id, key)); -} - -struct pf_state * -pf_find_state_recurse(struct pfi_kif *kif, struct pf_state *key, u_int8_t tree) -{ - struct pf_state *s; + struct pf_tree_node *k; pf_status.fcounters[FCNT_STATE_SEARCH]++; - - switch (tree) { - case PF_LAN_EXT: - 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: - 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); - } + k = RB_FIND(pf_state_tree, tree, key); + if (k) + return (k->state); + else return (NULL); - default: - panic("pf_find_state_recurse"); - } -} - -struct pf_state * -pf_find_state_all(struct pf_state *key, u_int8_t tree, int *more) -{ - struct pf_state *s, *ss = NULL; - struct pfi_kif *kif; - - pf_status.fcounters[FCNT_STATE_SEARCH]++; - - switch (tree) { - case PF_LAN_EXT: - TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) { - s = RB_FIND(pf_state_tree_lan_ext, - &kif->pfik_lan_ext, key); - if (s == NULL) - continue; - if (more == NULL) - return (s); - ss = s; - (*more)++; - } - return (ss); - case PF_EXT_GWY: - TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) { - s = RB_FIND(pf_state_tree_ext_gwy, - &kif->pfik_ext_gwy, key); - if (s == NULL) - continue; - if (more == NULL) - return (s); - ss = s; - (*more)++; - } - return (ss); - default: - panic("pf_find_state_all"); - } } int -pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule, - struct pf_addr *src, sa_family_t af) +pf_insert_state(struct pf_state *state) { - struct pf_src_node k; - - if (*sn == NULL) { - k.af = af; - PF_ACPY(&k.addr, src, af); - if (rule->rule_flag & PFRULE_RULESRCTRACK || - rule->rpool.opts & PF_POOL_STICKYADDR) - k.rule.ptr = rule; - else - k.rule.ptr = NULL; - pf_status.scounters[SCNT_SRC_NODE_SEARCH]++; - *sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k); - } - if (*sn == NULL) { - if (!rule->max_src_nodes || - rule->src_nodes < rule->max_src_nodes) - (*sn) = pool_get(&pf_src_tree_pl, PR_NOWAIT); - if ((*sn) == NULL) - return (-1); - bzero(*sn, sizeof(struct pf_src_node)); - (*sn)->af = af; - if (rule->rule_flag & PFRULE_RULESRCTRACK || - rule->rpool.opts & PF_POOL_STICKYADDR) - (*sn)->rule.ptr = rule; - else - (*sn)->rule.ptr = NULL; - PF_ACPY(&(*sn)->addr, src, af); - if (RB_INSERT(pf_src_tree, - &tree_src_tracking, *sn) != NULL) { - if (pf_status.debug >= PF_DEBUG_MISC) { - printf("pf: src_tree insert failed: "); - pf_print_host(&(*sn)->addr, 0, af); - printf("\n"); - } - pool_put(&pf_src_tree_pl, *sn); - return (-1); - } - (*sn)->creation = time.tv_sec; - (*sn)->ruletype = rule->action; - if ((*sn)->rule.ptr != NULL) - (*sn)->rule.ptr->src_nodes++; - pf_status.scounters[SCNT_SRC_NODE_INSERT]++; - pf_status.src_nodes++; - } else { - if (rule->max_src_states && - (*sn)->states >= rule->max_src_states) - return (-1); - } - return (0); -} + struct pf_tree_node *keya, *keyb; + + keya = pool_get(&pf_tree_pl, PR_NOWAIT); + if (keya == NULL) + return (-1); + keya->state = state; + keya->proto = state->proto; + keya->af = state->af; + PF_ACPY(&keya->addr[0], &state->lan.addr, state->af); + keya->port[0] = state->lan.port; + PF_ACPY(&keya->addr[1], &state->ext.addr, state->af); + keya->port[1] = state->ext.port; -int -pf_insert_state(struct pfi_kif *kif, struct pf_state *state) -{ /* Thou MUST NOT insert multiple duplicate keys */ - state->u.s.kif = kif; - if (RB_INSERT(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state)) { + if (RB_INSERT(pf_state_tree, &tree_lan_ext, keya) != NULL) { if (pf_status.debug >= PF_DEBUG_MISC) { printf("pf: state insert failed: tree_lan_ext"); printf(" lan: "); @@ -626,14 +434,28 @@ pf_insert_state(struct pfi_kif *kif, struct pf_state *state) printf(" ext: "); pf_print_host(&state->ext.addr, state->ext.port, state->af); - if (state->sync_flags & PFSTATE_FROMSYNC) - printf(" (from sync)"); printf("\n"); } + pool_put(&pf_tree_pl, keya); + return (-1); + } + + keyb = pool_get(&pf_tree_pl, PR_NOWAIT); + if (keyb == NULL) { + /* Need to pull out the other state */ + RB_REMOVE(pf_state_tree, &tree_lan_ext, keya); + pool_put(&pf_tree_pl, keya); return (-1); } + keyb->state = state; + keyb->proto = state->proto; + keyb->af = state->af; + PF_ACPY(&keyb->addr[0], &state->ext.addr, state->af); + keyb->port[0] = state->ext.port; + PF_ACPY(&keyb->addr[1], &state->gwy.addr, state->af); + keyb->port[1] = state->gwy.port; - if (RB_INSERT(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state)) { + if (RB_INSERT(pf_state_tree, &tree_ext_gwy, keyb) != NULL) { if (pf_status.debug >= PF_DEBUG_MISC) { printf("pf: state insert failed: tree_ext_gwy"); printf(" lan: "); @@ -645,36 +467,16 @@ pf_insert_state(struct pfi_kif *kif, struct pf_state *state) printf(" ext: "); pf_print_host(&state->ext.addr, state->ext.port, state->af); - if (state->sync_flags & PFSTATE_FROMSYNC) - printf(" (from sync)"); printf("\n"); } - RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state); + RB_REMOVE(pf_state_tree, &tree_lan_ext, keya); + pool_put(&pf_tree_pl, keya); + pool_put(&pf_tree_pl, keyb); return (-1); } - if (state->id == 0 && state->creatorid == 0) { - state->id = htobe64(pf_status.stateid++); - state->creatorid = pf_status.hostid; - } - if (RB_INSERT(pf_state_tree_id, &tree_id, state) != NULL) { - if (pf_status.debug >= PF_DEBUG_MISC) { - printf("pf: state insert failed: " - "id: %016llx creatorid: %08x", - betoh64(state->id), ntohl(state->creatorid)); - if (state->sync_flags & PFSTATE_FROMSYNC) - printf(" (from sync)"); - printf("\n"); - } - RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state); - RB_REMOVE(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state); - return (-1); - } - TAILQ_INSERT_HEAD(&state_updates, state, u.s.entry_updates); - pf_status.fcounters[FCNT_STATE_INSERT]++; pf_status.states++; - pfi_attach_state(kif); #if NPFSYNC pfsync_insert_state(state); #endif @@ -684,16 +486,30 @@ pf_insert_state(struct pfi_kif *kif, struct pf_state *state) void pf_purge_timeout(void *arg) { +#ifdef __FreeBSD__ + struct callout *to = arg; +#else struct timeout *to = arg; +#endif int s; +#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 +#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 @@ -706,10 +522,19 @@ pf_state_expires(const struct pf_state *state) /* handle all PFTM_* > PFTM_MAX here */ if (state->timeout == PFTM_PURGE) +#ifdef __FreeBSD__ + return (time_second); +#else return (time.tv_sec); +#endif if (state->timeout == PFTM_UNTIL_PACKET) return (0); +#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]; @@ -727,99 +552,81 @@ pf_state_expires(const struct pf_state *state) return (state->expire + timeout * (end - states) / (end - start)); else +#ifdef __FreeBSD__ + return (time_second); +#else return (time.tv_sec); +#endif } return (state->expire + timeout); } void -pf_purge_expired_src_nodes(void) +pf_purge_expired_states(void) { - struct pf_src_node *cur, *next; - - 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.tv_sec) { - if (cur->rule.ptr != NULL) { - cur->rule.ptr->src_nodes--; - if (cur->rule.ptr->states <= 0 && - cur->rule.ptr->max_src_nodes <= 0) - pf_rm_rule(NULL, cur->rule.ptr); - } - RB_REMOVE(pf_src_tree, &tree_src_tracking, cur); - pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; - pf_status.src_nodes--; - pool_put(&pf_src_tree_pl, cur); - } - } -} + struct pf_tree_node *cur, *peer, *next; + struct pf_tree_node key; -void -pf_src_tree_remove_state(struct pf_state *s) -{ - u_int32_t timeout; - - if (s->src_node != NULL) { - if (--s->src_node->states <= 0) { - timeout = s->rule.ptr->timeout[PFTM_SRC_NODE]; - if (!timeout) - timeout = - pf_default_rule.timeout[PFTM_SRC_NODE]; - s->src_node->expire = time.tv_sec + timeout; - } - } - if (s->nat_src_node != s->src_node && s->nat_src_node != NULL) { - if (--s->nat_src_node->states <= 0) { - timeout = s->rule.ptr->timeout[PFTM_SRC_NODE]; - if (!timeout) - timeout = - pf_default_rule.timeout[PFTM_SRC_NODE]; - s->nat_src_node->expire = time.tv_sec + timeout; - } - } - s->src_node = s->nat_src_node = NULL; -} + for (cur = RB_MIN(pf_state_tree, &tree_ext_gwy); cur; cur = next) { + next = RB_NEXT(pf_state_tree, &tree_ext_gwy, cur); -void -pf_purge_expired_states(void) -{ - struct pf_state *cur, *next; - - 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.tv_sec) { - if (cur->src.state == PF_TCPS_PROXY_DST) - pf_send_tcp(cur->rule.ptr, cur->af, - &cur->ext.addr, &cur->lan.addr, - cur->ext.port, cur->lan.port, - cur->src.seqhi, cur->src.seqlo + 1, 0, +#ifdef __FreeBSD__ + if (pf_state_expires(cur->state) <= (u_int32_t)time_second) { +#else + if (pf_state_expires(cur->state) <= time.tv_sec) { +#endif + if (cur->state->src.state == PF_TCPS_PROXY_DST) + pf_send_tcp(cur->state->rule.ptr, + cur->state->af, + &cur->state->ext.addr, + &cur->state->lan.addr, + cur->state->ext.port, + cur->state->lan.port, + cur->state->src.seqhi, + cur->state->src.seqlo + 1, + 0, TH_RST|TH_ACK, 0, 0); - 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); + RB_REMOVE(pf_state_tree, &tree_ext_gwy, cur); + + /* Need this key's peer (in the other tree) */ + key.state = cur->state; + key.proto = cur->state->proto; + key.af = cur->state->af; + PF_ACPY(&key.addr[0], &cur->state->lan.addr, + cur->state->af); + key.port[0] = cur->state->lan.port; + PF_ACPY(&key.addr[1], &cur->state->ext.addr, + cur->state->af); + key.port[1] = cur->state->ext.port; + + peer = RB_FIND(pf_state_tree, &tree_lan_ext, &key); +#ifdef __FreeBSD__ + KASSERT((peer), ("peer null :%s", __FUNCTION__)); + KASSERT((peer->state == cur->state), + ("peer->state != cur->state: %s", __FUNCTION__)); +#else + KASSERT(peer); + KASSERT(peer->state == cur->state); +#endif + RB_REMOVE(pf_state_tree, &tree_lan_ext, peer); + #if NPFSYNC - pfsync_delete_state(cur); + pfsync_delete_state(cur->state); #endif - pf_src_tree_remove_state(cur); - if (--cur->rule.ptr->states <= 0 && - cur->rule.ptr->src_nodes <= 0) - pf_rm_rule(NULL, cur->rule.ptr); - if (cur->nat_rule.ptr != NULL) - if (--cur->nat_rule.ptr->states <= 0 && - cur->nat_rule.ptr->src_nodes <= 0) - pf_rm_rule(NULL, cur->nat_rule.ptr); - if (cur->anchor.ptr != NULL) - if (--cur->anchor.ptr->states <= 0) - pf_rm_rule(NULL, cur->anchor.ptr); - pf_normalize_tcp_cleanup(cur); - pfi_detach_state(cur->u.s.kif); - TAILQ_REMOVE(&state_updates, cur, u.s.entry_updates); - pool_put(&pf_state_pl, cur); + if (--cur->state->rule.ptr->states <= 0) + pf_rm_rule(NULL, cur->state->rule.ptr); + if (cur->state->nat_rule.ptr != NULL) + if (--cur->state->nat_rule.ptr->states <= 0) + pf_rm_rule(NULL, + cur->state->nat_rule.ptr); + if (cur->state->anchor.ptr != NULL) + if (--cur->state->anchor.ptr->states <= 0) + pf_rm_rule(NULL, + cur->state->anchor.ptr); + pf_normalize_tcp_cleanup(cur->state); + pool_put(&pf_state_pl, cur->state); + pool_put(&pf_tree_pl, cur); + pool_put(&pf_tree_pl, peer); pf_status.fcounters[FCNT_STATE_REMOVALS]++; pf_status.states--; } @@ -859,6 +666,129 @@ pf_tbladdr_copyout(struct pf_addr_wrap *aw) kt->pfrkt_cnt : -1; } +int +pf_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af) +{ + if (aw->type != PF_ADDR_DYNIFTL) + return (0); + aw->p.dyn = pool_get(&pf_addr_pl, PR_NOWAIT); + if (aw->p.dyn == NULL) + return (1); + bcopy(aw->v.ifname, aw->p.dyn->ifname, sizeof(aw->p.dyn->ifname)); + aw->p.dyn->ifp = ifunit(aw->p.dyn->ifname); + if (aw->p.dyn->ifp == NULL) { + pool_put(&pf_addr_pl, aw->p.dyn); + aw->p.dyn = NULL; + return (1); + } + aw->p.dyn->addr = &aw->v.a.addr; + aw->p.dyn->af = af; + aw->p.dyn->undefined = 1; +#ifndef __FreeBSD__ + aw->p.dyn->hook_cookie = hook_establish( + aw->p.dyn->ifp->if_addrhooks, 1, + pf_dynaddr_update, aw->p.dyn); + if (aw->p.dyn->hook_cookie == NULL) { + pool_put(&pf_addr_pl, aw->p.dyn); + aw->p.dyn = NULL; + return (1); + } +#else + PF_UNLOCK(); + aw->p.dyn->hook_cookie = EVENTHANDLER_REGISTER(ifaddr_event, + pf_dynaddr_update_event, aw->p.dyn, EVENTHANDLER_PRI_ANY); + PF_LOCK(); + if (aw->p.dyn->hook_cookie == NULL) { + pool_put(&pf_addr_pl, aw->p.dyn); + aw->p.dyn = NULL; + return (1); + } +#endif + pf_dynaddr_update(aw->p.dyn); + return (0); +} + +#ifdef __FreeBSD__ +void +pf_dynaddr_update_event(void *arg, struct ifnet *ifp) +{ + PF_LOCK(); + pf_dynaddr_update(arg); + PF_UNLOCK(); +} +#endif + +void +pf_dynaddr_update(void *p) +{ + struct pf_addr_dyn *ad = (struct pf_addr_dyn *)p; + struct ifaddr *ia; + int s, changed = 0; + + if (ad == NULL || ad->ifp == NULL) + panic("pf_dynaddr_update"); + s = splsoftnet(); + TAILQ_FOREACH(ia, &ad->ifp->if_addrlist, ifa_list) + if (ia->ifa_addr != NULL && + ia->ifa_addr->sa_family == ad->af) { + if (ad->af == AF_INET) { + struct in_addr *a, *b; + + a = &ad->addr->v4; + b = &((struct sockaddr_in *)ia->ifa_addr) + ->sin_addr; + if (ad->undefined || + memcmp(a, b, sizeof(*a))) { + bcopy(b, a, sizeof(*a)); + changed = 1; + } + } else if (ad->af == AF_INET6) { + struct in6_addr *a, *b; + + a = &ad->addr->v6; + b = &((struct sockaddr_in6 *)ia->ifa_addr) + ->sin6_addr; + if (ad->undefined || + memcmp(a, b, sizeof(*a))) { + bcopy(b, a, sizeof(*a)); + changed = 1; + } + } + if (changed) + ad->undefined = 0; + break; + } + if (ia == NULL) + ad->undefined = 1; + splx(s); +} + +void +pf_dynaddr_remove(struct pf_addr_wrap *aw) +{ + if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL) + return; +#ifndef __FreeBSD__ + hook_disestablish(aw->p.dyn->ifp->if_addrhooks, + aw->p.dyn->hook_cookie); +#else + PF_UNLOCK(); + EVENTHANDLER_DEREGISTER(ifaddr_event, aw->p.dyn->hook_cookie); + PF_LOCK(); +#endif + pool_put(&pf_addr_pl, aw->p.dyn); + aw->p.dyn = NULL; +} + +void +pf_dynaddr_copyout(struct pf_addr_wrap *aw) +{ + if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL) + return; + bcopy(aw->p.dyn->ifname, aw->v.ifname, sizeof(aw->v.ifname)); + aw->p.dyn = (struct pf_addr_dyn *)1; +} + void pf_print_host(struct pf_addr *addr, u_int16_t p, sa_family_t af) { @@ -1004,7 +934,7 @@ pf_calc_skip_steps(struct pf_rulequeue *rules) head[i] = cur; while (cur != NULL) { - if (cur->kif != prev->kif || cur->ifnot != prev->ifnot) + if (cur->ifp != prev->ifp || cur->ifnot != prev->ifnot) PF_SET_SKIP_STEPS(PF_SKIP_IFP); if (cur->direction != prev->direction) PF_SET_SKIP_STEPS(PF_SKIP_DIR); @@ -1047,7 +977,11 @@ pf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2) return (1); return (0); case PF_ADDR_DYNIFTL: - return (aw1->p.dyn->pfid_kt != aw2->p.dyn->pfid_kt); + if (aw1->p.dyn->ifp != aw2->p.dyn->ifp) + return (1); + if (PF_ANEQ(&aw1->v.a.mask, &aw2->v.a.mask, 0)) + return (1); + return (0); case PF_ADDR_NOROUTE: return (0); case PF_ADDR_TABLE: @@ -1059,6 +993,33 @@ pf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2) } void +pf_rule_set_qid(struct pf_rulequeue *rules) +{ + struct pf_rule *rule; + + TAILQ_FOREACH(rule, rules, entries) + if (rule->qname[0] != 0) { + rule->qid = pf_qname_to_qid(rule->qname); + if (rule->pqname[0] != 0) + rule->pqid = pf_qname_to_qid(rule->pqname); + else + rule->pqid = rule->qid; + } +} + +u_int32_t +pf_qname_to_qid(char *qname) +{ + struct pf_altq *altq; + + TAILQ_FOREACH(altq, pf_altqs_active, entries) + if (!strcmp(altq->qname, qname)) + return (altq->qid); + + return (0); +} + +void pf_update_anchor_rules() { struct pf_rule *rule; @@ -1181,7 +1142,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; @@ -1261,14 +1222,20 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, { struct mbuf *m; struct m_tag *mtag; - 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; + struct tcphdr *th = NULL; /* make the compiler happy */ +#ifdef __FreeBSD__ + struct ip *ip; +#if (__FreeBSD_version < 501114) + struct route ro; +#endif +#endif char *opt; /* maximum segment size tcp option */ @@ -1374,12 +1341,44 @@ 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 = htons(path_mtu_discovery ? IP_DF : 0); +#else h->ip_off = htons(ip_mtudisc ? IP_DF : 0); +#endif + h->ip_len = htons(len); h->ip_ttl = ttl ? ttl : ip_defttl; h->ip_sum = 0; +#ifdef __FreeBSD__ + ip = mtod(m, struct ip *); + /* + * XXX + * OpenBSD changed ip_len/ip_off byte ordering! + * Because FreeBSD assumes host byte ordering we need to + * change here. + */ + NTOHS(ip->ip_len); + NTOHS(ip->ip_off); +#if (__FreeBSD_version < 501114) + bzero(&ro, sizeof(ro)); + ip_rtaddr(ip->ip_dst, &ro); + PF_UNLOCK(); + ip_output(m, (void *)NULL, &ro, 0, (void *)NULL, + (void *)NULL); + PF_LOCK(); + if(ro.ro_rt) { + RTFREE(ro.ro_rt); + } +#else /* __FreeBSD_version >= 501114 */ + PF_UNLOCK(); + ip_output(m, (void *)NULL, (void *)NULL, 0, (void *)NULL, + (void *)NULL); + PF_LOCK(); +#endif +#else /* ! __FreeBSD__ */ ip_output(m, (void *)NULL, (void *)NULL, 0, (void *)NULL, (void *)NULL); +#endif break; #endif /* INET */ #ifdef INET6 @@ -1391,7 +1390,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 */ } @@ -1403,11 +1408,18 @@ pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af, { struct m_tag *mtag; struct mbuf *m0; +#ifdef __FreeBSD__ + struct ip *ip; +#endif mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT); if (mtag == NULL) return; +#ifdef __FreeBSD__ + m0 = m_copypacket(m, M_DONTWAIT); +#else m0 = m_copy(m, 0, M_COPYALL); +#endif if (m0 == NULL) { m_tag_free(mtag); return; @@ -1433,12 +1445,28 @@ pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af, switch (af) { #ifdef INET case AF_INET: - icmp_error(m0, type, code, 0, (void *)NULL); +#ifdef __FreeBSD__ + /* icmp_error() expects host byte ordering */ + ip = mtod(m0, struct ip *); + NTOHS(ip->ip_len); + NTOHS(ip->ip_off); + PF_UNLOCK(); +#endif + icmp_error(m0, type, code, 0, NULL); +#ifdef __FreeBSD__ + PF_LOCK(); +#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 */ } @@ -1553,8 +1581,8 @@ pf_get_tag(struct mbuf *m) } int -pf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_rule *nat_rule, - struct pf_tag *pftag, int *tag) +pf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_rule *nat, + struct pf_rule *rdr, struct pf_tag *pftag, int *tag) { if (*tag == -1) { /* find mbuf tag */ pftag = pf_get_tag(m); @@ -1562,8 +1590,10 @@ pf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_rule *nat_rule, *tag = pftag->tag; else *tag = 0; - if (nat_rule != NULL && nat_rule->tag) - *tag = nat_rule->tag; + if (nat != NULL && nat->tag) + *tag = nat->tag; + if (rdr != NULL && rdr->tag) + *tag = rdr->tag; } return ((!r->match_tag_not && r->match_tag == *tag) || @@ -1647,7 +1677,7 @@ pf_poolmask(struct pf_addr *naddr, struct pf_addr *raddr, } void -pf_addr_inc(struct pf_addr *addr, sa_family_t af) +pf_addr_inc(struct pf_addr *addr, u_int8_t af) { switch (af) { #ifdef INET @@ -1736,59 +1766,20 @@ pf_hash(struct pf_addr *inaddr, struct pf_addr *hash, } int -pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, - struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sn) +pf_map_addr(u_int8_t af, struct pf_pool *rpool, struct pf_addr *saddr, + struct pf_addr *naddr, struct pf_addr *init_addr) { unsigned char hash[16]; - struct pf_pool *rpool = &r->rpool; - struct pf_addr *raddr = &rpool->cur->addr.v.a.addr; - struct pf_addr *rmask = &rpool->cur->addr.v.a.mask; + struct pf_addr *raddr; + struct pf_addr *rmask; struct pf_pooladdr *acur = rpool->cur; - struct pf_src_node k; - - if (*sn == NULL && r->rpool.opts & PF_POOL_STICKYADDR && - (r->rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) { - k.af = af; - PF_ACPY(&k.addr, saddr, af); - if (r->rule_flag & PFRULE_RULESRCTRACK || - r->rpool.opts & PF_POOL_STICKYADDR) - k.rule.ptr = r; - else - k.rule.ptr = NULL; - pf_status.scounters[SCNT_SRC_NODE_SEARCH]++; - *sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k); - if (*sn != NULL && !PF_AZERO(&(*sn)->raddr, af)) { - PF_ACPY(naddr, &(*sn)->raddr, af); - if (pf_status.debug >= PF_DEBUG_MISC) { - printf("pf_map_addr: src tracking maps "); - pf_print_host(&k.addr, 0, af); - printf(" to "); - pf_print_host(naddr, 0, af); - printf("\n"); - } - return (0); - } - } if (rpool->cur->addr.type == PF_ADDR_NOROUTE) return (1); - if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) { - if (af == AF_INET) { - if (rpool->cur->addr.p.dyn->pfid_acnt4 < 1 && - (rpool->opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN) - return (1); - raddr = &rpool->cur->addr.p.dyn->pfid_addr4; - rmask = &rpool->cur->addr.p.dyn->pfid_mask4; - } else { - if (rpool->cur->addr.p.dyn->pfid_acnt6 < 1 && - (rpool->opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN) - return (1); - raddr = &rpool->cur->addr.p.dyn->pfid_addr6; - rmask = &rpool->cur->addr.p.dyn->pfid_mask6; - } - } else if (rpool->cur->addr.type == PF_ADDR_TABLE) { + if (rpool->cur->addr.type == PF_ADDR_DYNIFTL && + rpool->cur->addr.p.dyn->undefined) + return (1); + if (rpool->cur->addr.type == PF_ADDR_TABLE) { if ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN) return (1); /* unsupported */ } else { @@ -1848,11 +1839,6 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, &rpool->tblidx, &rpool->counter, &raddr, &rmask, af)) goto get_addr; - } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) { - if (!pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt, - &rpool->tblidx, &rpool->counter, - &raddr, &rmask, af)) - goto get_addr; } else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af)) goto get_addr; @@ -1864,17 +1850,7 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, if (pfr_pool_get(rpool->cur->addr.p.tbl, &rpool->tblidx, &rpool->counter, &raddr, &rmask, af)) { - /* table contains no address of type 'af' */ - if (rpool->cur != acur) - goto try_next; - return (1); - } - } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) { - rpool->tblidx = -1; - if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt, - &rpool->tblidx, &rpool->counter, - &raddr, &rmask, af)) { - /* table contains no address of type 'af' */ + /* table contain no address of type 'af' */ if (rpool->cur != acur) goto try_next; return (1); @@ -1890,12 +1866,10 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, PF_AINC(&rpool->counter, af); break; } - if (*sn != NULL) - PF_ACPY(&(*sn)->raddr, naddr, af); if (pf_status.debug >= PF_DEBUG_MISC && (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) { - printf("pf_map_addr: selected address "); + printf("pf_map_addr: selected address: "); pf_print_host(naddr, 0, af); printf("\n"); } @@ -1904,41 +1878,41 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, } int -pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, +pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_pool *rpool, struct pf_addr *saddr, struct pf_addr *daddr, u_int16_t dport, - struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high, - struct pf_src_node **sn) + struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high) { - struct pf_state key; + struct pf_tree_node key; struct pf_addr init_addr; u_int16_t cut; bzero(&init_addr, sizeof(init_addr)); - if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn)) + if (pf_map_addr(af, rpool, saddr, naddr, &init_addr)) return (1); do { key.af = af; key.proto = proto; - PF_ACPY(&key.ext.addr, daddr, key.af); - PF_ACPY(&key.gwy.addr, naddr, key.af); - key.ext.port = dport; + PF_ACPY(&key.addr[0], daddr, key.af); + PF_ACPY(&key.addr[1], naddr, key.af); + key.port[0] = dport; /* * port search; start random, step; * similar 2 portloop in in_pcbbind */ if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP)) { - key.gwy.port = 0; - if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL) + key.port[1] = 0; + if (pf_find_state(&tree_ext_gwy, &key) == NULL) return (0); } else if (low == 0 && high == 0) { - key.gwy.port = *nport; - if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL) + key.port[1] = *nport; + if (pf_find_state(&tree_ext_gwy, &key) == NULL) { return (0); + } } else if (low == high) { - key.gwy.port = htons(low); - if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL) { + key.port[1] = htons(low); + if (pf_find_state(&tree_ext_gwy, &key) == NULL) { *nport = htons(low); return (0); } @@ -1954,16 +1928,16 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, cut = arc4random() % (1 + high - low) + low; /* low <= cut <= high */ for (tmp = cut; tmp <= high; ++(tmp)) { - key.gwy.port = htons(tmp); - if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == + key.port[1] = htons(tmp); + if (pf_find_state(&tree_ext_gwy, &key) == NULL) { *nport = htons(tmp); return (0); } } for (tmp = cut - 1; tmp >= low; --(tmp)) { - key.gwy.port = htons(tmp); - if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == + key.port[1] = htons(tmp); + if (pf_find_state(&tree_ext_gwy, &key) == NULL) { *nport = htons(tmp); return (0); @@ -1971,10 +1945,10 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, } } - switch (r->rpool.opts & PF_POOL_TYPEMASK) { + switch (rpool->opts & PF_POOL_TYPEMASK) { case PF_POOL_RANDOM: case PF_POOL_ROUNDROBIN: - if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn)) + if (pf_map_addr(af, rpool, saddr, naddr, &init_addr)) return (1); break; case PF_POOL_NONE: @@ -1982,6 +1956,7 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, case PF_POOL_BITMASK: default: return (1); + break; } } while (! PF_AEQ(&init_addr, naddr, af) ); @@ -1990,7 +1965,7 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, struct pf_rule * pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off, - int direction, struct pfi_kif *kif, struct pf_addr *saddr, u_int16_t sport, + int direction, struct ifnet *ifp, struct pf_addr *saddr, u_int16_t sport, struct pf_addr *daddr, u_int16_t dport, int rs_num) { struct pf_rule *r, *rm = NULL, *anchorrule = NULL; @@ -2011,8 +1986,8 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off, } r->evaluations++; - if (r->kif != NULL && - (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) + if (r->ifp != NULL && ((r->ifp != ifp && !r->ifnot) || + (r->ifp == ifp && r->ifnot))) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR].ptr; @@ -2058,7 +2033,7 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off, struct pf_rule * pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, - struct pfi_kif *kif, struct pf_src_node **sn, + struct ifnet *ifp, struct pf_addr *saddr, u_int16_t sport, struct pf_addr *daddr, u_int16_t dport, struct pf_addr *naddr, u_int16_t *nport) @@ -2066,16 +2041,16 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, struct pf_rule *r = NULL; if (direction == PF_OUT) { - r = pf_match_translation(pd, m, off, direction, kif, saddr, + r = pf_match_translation(pd, m, off, direction, ifp, saddr, sport, daddr, dport, PF_RULESET_BINAT); if (r == NULL) - r = pf_match_translation(pd, m, off, direction, kif, + r = pf_match_translation(pd, m, off, direction, ifp, saddr, sport, daddr, dport, PF_RULESET_NAT); } else { - r = pf_match_translation(pd, m, off, direction, kif, saddr, + r = pf_match_translation(pd, m, off, direction, ifp, saddr, sport, daddr, dport, PF_RULESET_RDR); if (r == NULL) - r = pf_match_translation(pd, m, off, direction, kif, + r = pf_match_translation(pd, m, off, direction, ifp, saddr, sport, daddr, dport, PF_RULESET_BINAT); } @@ -2085,10 +2060,11 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, case PF_NOBINAT: case PF_NORDR: return (NULL); + break; case PF_NAT: - if (pf_get_sport(pd->af, pd->proto, r, saddr, + if (pf_get_sport(pd->af, pd->proto, &r->rpool, saddr, daddr, dport, naddr, nport, r->rpool.proxy_port[0], - r->rpool.proxy_port[1], sn)) { + r->rpool.proxy_port[1])) { DPFPRINTF(PF_DEBUG_MISC, ("pf: NAT proxy port allocation " "(%u-%u) failed\n", @@ -2100,58 +2076,21 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, case PF_BINAT: switch (direction) { case PF_OUT: - if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){ - if (pd->af == AF_INET) { - if (r->rpool.cur->addr.p.dyn-> - pfid_acnt4 < 1) - return (NULL); - PF_POOLMASK(naddr, - &r->rpool.cur->addr.p.dyn-> - pfid_addr4, - &r->rpool.cur->addr.p.dyn-> - pfid_mask4, - saddr, AF_INET); - } else { - if (r->rpool.cur->addr.p.dyn-> - pfid_acnt6 < 1) - return (NULL); - PF_POOLMASK(naddr, - &r->rpool.cur->addr.p.dyn-> - pfid_addr6, - &r->rpool.cur->addr.p.dyn-> - pfid_mask6, - saddr, AF_INET6); - } - } else + if (r->rpool.cur->addr.type == + PF_ADDR_DYNIFTL && + r->rpool.cur->addr.p.dyn->undefined) + return (NULL); + else PF_POOLMASK(naddr, &r->rpool.cur->addr.v.a.addr, &r->rpool.cur->addr.v.a.mask, saddr, pd->af); break; case PF_IN: - if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){ - if (pd->af == AF_INET) { - if (r->src.addr.p.dyn-> - pfid_acnt4 < 1) - return (NULL); - PF_POOLMASK(naddr, - &r->src.addr.p.dyn-> - pfid_addr4, - &r->src.addr.p.dyn-> - pfid_mask4, - daddr, AF_INET); - } else { - if (r->src.addr.p.dyn-> - pfid_acnt6 < 1) - return (NULL); - PF_POOLMASK(naddr, - &r->src.addr.p.dyn-> - pfid_addr6, - &r->src.addr.p.dyn-> - pfid_mask6, - daddr, AF_INET6); - } - } else + if (r->src.addr.type == PF_ADDR_DYNIFTL && + r->src.addr.p.dyn->undefined) + return (NULL); + else PF_POOLMASK(naddr, &r->src.addr.v.a.addr, &r->src.addr.v.a.mask, daddr, @@ -2160,7 +2099,7 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, } break; case PF_RDR: { - if (pf_map_addr(r->af, r, saddr, naddr, NULL, sn)) + if (pf_map_addr(r->af, &r->rpool, saddr, naddr, NULL)) return (NULL); if (r->rpool.proxy_port[1]) { @@ -2182,6 +2121,7 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, } default: return (NULL); + break; } } @@ -2189,25 +2129,38 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, } int -pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd) +pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, sa_family_t af, + int proto, struct pf_pdesc *pd) { struct pf_addr *saddr, *daddr; u_int16_t sport, dport; +#ifdef __FreeBSD__ + struct inpcbinfo *pi; +#else struct inpcbtable *tb; +#endif struct inpcb *inp; *uid = UID_MAX; *gid = GID_MAX; - switch (pd->proto) { + switch (proto) { case IPPROTO_TCP: sport = pd->hdr.tcp->th_sport; dport = pd->hdr.tcp->th_dport; +#ifdef __FreeBSD__ + pi = &tcbinfo; +#else tb = &tcbtable; +#endif break; case IPPROTO_UDP: sport = pd->hdr.udp->uh_sport; dport = pd->hdr.udp->uh_dport; +#ifdef __FreeBSD__ + pi = &udbinfo; +#else tb = &udbtable; +#endif break; default: return (0); @@ -2224,32 +2177,82 @@ pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd) saddr = pd->dst; daddr = pd->src; } - switch (pd->af) { + switch(af) { case AF_INET: +#ifdef __FreeBSD__ +#if (__FreeBSD_version >= 500043) + INP_INFO_RLOCK(pi); /* XXX LOR */ +#endif + 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) { +#if (__FreeBSD_version >= 500043) + INP_INFO_RUNLOCK(pi); +#endif + 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); + inp = in_pcblookup(tb, &saddr->v4, sport, &daddr->v4, + dport, INPLOOKUP_WILDCARD); if (inp == NULL) return (0); } +#endif break; #ifdef INET6 case AF_INET6: +#ifdef __FreeBSD__ +#if (__FreeBSD_version >= 500043) + INP_INFO_RLOCK(pi); +#endif + 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) { +#if (__FreeBSD_version >= 500043) + INP_INFO_RUNLOCK(pi); +#endif + 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); + inp = in_pcblookup(tb, &saddr->v6, sport, &daddr->v6, + dport, INPLOOKUP_WILDCARD | INPLOOKUP_IPV6); if (inp == NULL) return (0); } +#endif break; #endif /* INET6 */ default: return (0); } +#ifdef __FreeBSD__ +#if (__FreeBSD_version >= 500043) + INP_LOCK(inp); +#endif + *uid = inp->inp_socket->so_cred->cr_uid; + *gid = inp->inp_socket->so_cred->cr_groups[0]; +#if (__FreeBSD_version >= 500043) + INP_UNLOCK(inp); + INP_INFO_RUNLOCK(pi); +#endif +#else *uid = inp->inp_socket->so_euid; *gid = inp->inp_socket->so_egid; +#endif return (1); } @@ -2280,14 +2283,13 @@ pf_get_wscale(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af) if (wscale > TCP_MAX_WINSHIFT) wscale = TCP_MAX_WINSHIFT; wscale |= PF_WSCALE_FLAG; - /* FALLTHROUGH */ + /* fallthrough */ default: optlen = opt[1]; if (optlen < 2) optlen = 2; hlen -= optlen; opt += optlen; - break; } } return (wscale); @@ -2317,14 +2319,13 @@ pf_get_mss(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af) break; case TCPOPT_MAXSEG: bcopy((caddr_t)(opt + 2), (caddr_t)&mss, 2); - /* FALLTHROUGH */ + /* fallthrough */ default: optlen = opt[1]; if (optlen < 2) optlen = 2; hlen -= optlen; opt += optlen; - break; } } return (mss); @@ -2342,7 +2343,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) { @@ -2354,7 +2355,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 */ @@ -2366,7 +2375,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 */ @@ -2387,22 +2405,22 @@ pf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr) { struct pf_rule *r = s->rule.ptr; - s->rt_kif = NULL; + s->rt_ifp = NULL; if (!r->rt || r->rt == PF_FASTROUTE) return; switch (s->af) { #ifdef INET case AF_INET: - pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL, - &s->nat_src_node); - s->rt_kif = r->rpool.cur->kif; + pf_map_addr(AF_INET, &r->rpool, saddr, + &s->rt_addr, NULL); + s->rt_ifp = r->rpool.cur->ifp; break; #endif /* INET */ #ifdef INET6 case AF_INET6: - pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL, - &s->nat_src_node); - s->rt_kif = r->rpool.cur->kif; + pf_map_addr(AF_INET6, &r->rpool, saddr, + &s->rt_addr, NULL); + s->rt_ifp = r->rpool.cur->ifp; break; #endif /* INET6 */ } @@ -2410,11 +2428,12 @@ 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, + struct ifnet *ifp, struct mbuf *m, int ipoff, int off, void *h, struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm) { - struct pf_rule *nr = NULL; + struct pf_rule *nat = NULL, *rdr = NULL; struct pf_addr *saddr = pd->src, *daddr = pd->dst; + struct pf_addr baddr, naddr; struct tcphdr *th = pd->hdr.tcp; u_int16_t bport, nport = 0; sa_family_t af = pd->af; @@ -2423,7 +2442,6 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, 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; struct pf_tag *pftag = NULL; @@ -2435,37 +2453,35 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, if (direction == PF_OUT) { bport = nport = th->th_sport; /* check outgoing packet for BINAT/NAT */ - if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn, + if ((nat = pf_get_translation(pd, m, off, PF_OUT, ifp, saddr, th->th_sport, daddr, th->th_dport, - &pd->naddr, &nport)) != NULL) { - PF_ACPY(&pd->baddr, saddr, af); + &naddr, &nport)) != NULL) { + PF_ACPY(&baddr, saddr, af); pf_change_ap(saddr, &th->th_sport, pd->ip_sum, - &th->th_sum, &pd->naddr, nport, 0, af); + &th->th_sum, &naddr, nport, 0, af); rewrite++; - if (nr->natpass) + if (nat->natpass) r = NULL; - pd->nat_rule = nr; } } else { bport = nport = th->th_dport; /* check incoming packet for BINAT/RDR */ - if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn, - saddr, th->th_sport, daddr, th->th_dport, - &pd->naddr, &nport)) != NULL) { - PF_ACPY(&pd->baddr, daddr, af); + if ((rdr = pf_get_translation(pd, m, off, PF_IN, ifp, saddr, + th->th_sport, daddr, th->th_dport, + &naddr, &nport)) != NULL) { + PF_ACPY(&baddr, daddr, af); pf_change_ap(daddr, &th->th_dport, pd->ip_sum, - &th->th_sum, &pd->naddr, nport, 0, af); + &th->th_sum, &naddr, nport, 0, af); rewrite++; - if (nr->natpass) + if (rdr->natpass) r = NULL; - pd->nat_rule = nr; } } while (r != NULL) { r->evaluations++; - if (r->kif != NULL && - (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) + if (r->ifp != NULL && ((r->ifp != ifp && !r->ifnot) || + (r->ifp == ifp && r->ifnot))) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR].ptr; @@ -2490,16 +2506,19 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, else if ((r->flagset & th->th_flags) != r->flags) r = TAILQ_NEXT(r, entries); else if (r->uid.op && (lookup != -1 || (lookup = - pf_socket_lookup(&uid, &gid, direction, pd), 1)) && + pf_socket_lookup(&uid, &gid, direction, af, IPPROTO_TCP, + pd), 1)) && !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1], uid)) r = TAILQ_NEXT(r, entries); else if (r->gid.op && (lookup != -1 || (lookup = - pf_socket_lookup(&uid, &gid, direction, pd), 1)) && + pf_socket_lookup(&uid, &gid, direction, af, IPPROTO_TCP, + pd), 1)) && !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1], gid)) r = TAILQ_NEXT(r, entries); - else if (r->match_tag && !pf_match_tag(m, r, nr, pftag, &tag)) + else if (r->match_tag && + !pf_match_tag(m, r, nat, rdr, pftag, &tag)) r = TAILQ_NEXT(r, entries); else if (r->anchorname[0] && r->anchor == NULL) r = TAILQ_NEXT(r, entries); @@ -2528,12 +2547,18 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, a = *am; ruleset = *rsm; + r->packets++; + r->bytes += pd->tot_len; + if (a != NULL) { + a->packets++; + a->bytes += pd->tot_len; + } REASON_SET(&reason, PFRES_MATCH); if (r->log) { if (rewrite) - m_copyback(m, off, sizeof(*th), th); - PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset); + m_copyback(m, off, sizeof(*th), (caddr_t)th); + PFLOG_PACKET(ifp, h, m, af, direction, reason, r, a, ruleset); } if ((r->action == PF_DROP) && @@ -2541,16 +2566,14 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, (r->rule_flag & PFRULE_RETURNICMP) || (r->rule_flag & PFRULE_RETURN))) { /* undo NAT changes, if they have taken place */ - if (nr != NULL) { - if (direction == PF_OUT) { - pf_change_ap(saddr, &th->th_sport, pd->ip_sum, - &th->th_sum, &pd->baddr, bport, 0, af); - rewrite++; - } else { - pf_change_ap(daddr, &th->th_dport, pd->ip_sum, - &th->th_sum, &pd->baddr, bport, 0, af); - rewrite++; - } + if (nat != NULL) { + pf_change_ap(saddr, &th->th_sport, pd->ip_sum, + &th->th_sum, &baddr, bport, 0, af); + rewrite++; + } else if (rdr != NULL) { + pf_change_ap(daddr, &th->th_dport, pd->ip_sum, + &th->th_sum, &baddr, bport, 0, af); + rewrite++; } if (((r->rule_flag & PFRULE_RETURNRST) || (r->rule_flag & PFRULE_RETURN)) && @@ -2581,45 +2604,16 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, return (PF_DROP); } - if (r->keep_state || nr != NULL || + if (r->keep_state || nat != NULL || rdr != NULL || (pd->flags & PFDESC_TCP_NORM)) { /* create new state */ u_int16_t len; struct pf_state *s = NULL; - struct pf_src_node *sn = NULL; len = pd->tot_len - off - (th->th_off << 2); - - /* check maximums */ - if (r->max_states && (r->states >= r->max_states)) - goto cleanup; - /* 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) - goto cleanup; - /* src node for translation rule */ - if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) && - ((direction == PF_OUT && - pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) || - (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) - goto cleanup; - s = pool_get(&pf_state_pl, PR_NOWAIT); + if (!r->max_states || r->states < r->max_states) + s = pool_get(&pf_state_pl, PR_NOWAIT); if (s == NULL) { -cleanup: - if (sn != NULL && sn->states == 0 && sn->expire == 0) { - RB_REMOVE(pf_src_tree, &tree_src_tracking, sn); - pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; - pf_status.src_nodes--; - pool_put(&pf_src_tree_pl, sn); - } - if (nsn != sn && nsn != NULL && nsn->states == 0 && - nsn->expire == 0) { - RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn); - pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; - pf_status.src_nodes--; - pool_put(&pf_src_tree_pl, nsn); - } REASON_SET(&reason, PFRES_MEMORY); return (PF_DROP); } @@ -2628,7 +2622,10 @@ cleanup: if (a != NULL) a->states++; s->rule.ptr = r; - s->nat_rule.ptr = nr; + if (nat != NULL) + s->nat_rule.ptr = nat; + else + s->nat_rule.ptr = rdr; if (s->nat_rule.ptr != NULL) s->nat_rule.ptr->states++; s->anchor.ptr = a; @@ -2642,8 +2639,8 @@ cleanup: s->gwy.port = th->th_sport; /* sport */ PF_ACPY(&s->ext.addr, daddr, af); s->ext.port = th->th_dport; - if (nr != NULL) { - PF_ACPY(&s->lan.addr, &pd->baddr, af); + if (nat != NULL) { + PF_ACPY(&s->lan.addr, &baddr, af); s->lan.port = bport; } else { PF_ACPY(&s->lan.addr, &s->gwy.addr, af); @@ -2654,8 +2651,8 @@ cleanup: s->lan.port = th->th_dport; PF_ACPY(&s->ext.addr, saddr, af); s->ext.port = th->th_sport; - if (nr != NULL) { - PF_ACPY(&s->gwy.addr, &pd->baddr, af); + if (rdr != NULL) { + PF_ACPY(&s->gwy.addr, &baddr, af); s->gwy.port = bport; } else { PF_ACPY(&s->gwy.addr, &s->lan.addr, af); @@ -2689,27 +2686,27 @@ cleanup: } if (th->th_flags & TH_FIN) s->src.seqhi++; + s->dst.seqlo = 0; /* Haven't seen these yet */ s->dst.seqhi = 1; s->dst.max_win = 1; + s->dst.seqdiff = 0; /* Defer random generation */ s->src.state = TCPS_SYN_SENT; s->dst.state = TCPS_CLOSED; +#ifdef __FreeBSD__ + s->creation = time_second; + s->expire = time_second; +#else s->creation = time.tv_sec; s->expire = time.tv_sec; +#endif s->timeout = PFTM_TCP_FIRST_PACKET; + s->packets[0] = 1; + s->bytes[0] = pd->tot_len; pf_set_rt_ifp(s, saddr); - if (sn != NULL) { - s->src_node = sn; - s->src_node->states++; - } - if (nsn != NULL) { - PF_ACPY(&nsn->raddr, &pd->naddr, af); - s->nat_src_node = nsn; - s->nat_src_node->states++; - } + if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m, off, pd, th, &s->src, &s->dst)) { REASON_SET(&reason, PFRES_MEMORY); - pf_src_tree_remove_state(s); pool_put(&pf_state_pl, s); return (PF_DROP); } @@ -2717,14 +2714,12 @@ cleanup: pf_normalize_tcp_stateful(m, off, pd, &reason, th, &s->src, &s->dst, &rewrite)) { pf_normalize_tcp_cleanup(s); - pf_src_tree_remove_state(s); pool_put(&pf_state_pl, s); return (PF_DROP); } - if (pf_insert_state(BOUND_IFACE(r, kif), s)) { + if (pf_insert_state(s)) { pf_normalize_tcp_cleanup(s); REASON_SET(&reason, PFRES_MEMORY); - pf_src_tree_remove_state(s); pool_put(&pf_state_pl, s); return (PF_DROP); } else @@ -2732,17 +2727,14 @@ cleanup: if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN && r->keep_state == PF_STATE_SYNPROXY) { s->src.state = PF_TCPS_PROXY_SRC; - if (nr != NULL) { - if (direction == PF_OUT) { - pf_change_ap(saddr, &th->th_sport, - pd->ip_sum, &th->th_sum, &pd->baddr, - bport, 0, af); - } else { - pf_change_ap(daddr, &th->th_dport, - pd->ip_sum, &th->th_sum, &pd->baddr, - bport, 0, af); - } - } + if (nat != NULL) + pf_change_ap(saddr, &th->th_sport, + pd->ip_sum, &th->th_sum, &baddr, + bport, 0, af); + else if (rdr != NULL) + pf_change_ap(daddr, &th->th_dport, + pd->ip_sum, &th->th_sum, &baddr, + bport, 0, af); s->src.seqhi = arc4random(); /* Find mss option */ mss = pf_get_mss(m, off, th->th_off, af); @@ -2750,26 +2742,27 @@ cleanup: mss = pf_calc_mss(daddr, af, mss); s->src.mss = mss; pf_send_tcp(r, af, daddr, saddr, th->th_dport, - th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1, - TH_SYN|TH_ACK, 0, s->src.mss, 0); + th->th_sport, s->src.seqhi, + ntohl(th->th_seq) + 1, TH_SYN|TH_ACK, 0, s->src.mss, 0); return (PF_SYNPROXY_DROP); } } /* 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); } 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, + struct ifnet *ifp, struct mbuf *m, int ipoff, int off, void *h, struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm) { - struct pf_rule *nr = NULL; + struct pf_rule *nat = NULL, *rdr = NULL; struct pf_addr *saddr = pd->src, *daddr = pd->dst; + struct pf_addr baddr, naddr; struct udphdr *uh = pd->hdr.udp; u_int16_t bport, nport = 0; sa_family_t af = pd->af; @@ -2778,7 +2771,6 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, 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; struct pf_tag *pftag = NULL; @@ -2789,37 +2781,35 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, if (direction == PF_OUT) { bport = nport = uh->uh_sport; /* check outgoing packet for BINAT/NAT */ - if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn, + if ((nat = pf_get_translation(pd, m, off, PF_OUT, ifp, saddr, uh->uh_sport, daddr, uh->uh_dport, - &pd->naddr, &nport)) != NULL) { - PF_ACPY(&pd->baddr, saddr, af); + &naddr, &nport)) != NULL) { + PF_ACPY(&baddr, saddr, af); pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum, - &uh->uh_sum, &pd->naddr, nport, 1, af); + &uh->uh_sum, &naddr, nport, 1, af); rewrite++; - if (nr->natpass) + if (nat->natpass) r = NULL; - pd->nat_rule = nr; } } else { bport = nport = uh->uh_dport; /* check incoming packet for BINAT/RDR */ - if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn, - saddr, uh->uh_sport, daddr, uh->uh_dport, &pd->naddr, - &nport)) != NULL) { - PF_ACPY(&pd->baddr, daddr, af); + if ((rdr = pf_get_translation(pd, m, off, PF_IN, ifp, saddr, + uh->uh_sport, daddr, uh->uh_dport, &naddr, &nport)) + != NULL) { + PF_ACPY(&baddr, daddr, af); pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum, - &uh->uh_sum, &pd->naddr, nport, 1, af); + &uh->uh_sum, &naddr, nport, 1, af); rewrite++; - if (nr->natpass) + if (rdr->natpass) r = NULL; - pd->nat_rule = nr; } } while (r != NULL) { r->evaluations++; - if (r->kif != NULL && - (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) + if (r->ifp != NULL && ((r->ifp != ifp && !r->ifnot) || + (r->ifp == ifp && r->ifnot))) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR].ptr; @@ -2842,16 +2832,19 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, else if (r->rule_flag & PFRULE_FRAGMENT) r = TAILQ_NEXT(r, entries); else if (r->uid.op && (lookup != -1 || (lookup = - pf_socket_lookup(&uid, &gid, direction, pd), 1)) && + pf_socket_lookup(&uid, &gid, direction, af, IPPROTO_UDP, + pd), 1)) && !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1], uid)) r = TAILQ_NEXT(r, entries); else if (r->gid.op && (lookup != -1 || (lookup = - pf_socket_lookup(&uid, &gid, direction, pd), 1)) && + pf_socket_lookup(&uid, &gid, direction, af, IPPROTO_UDP, + pd), 1)) && !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1], gid)) r = TAILQ_NEXT(r, entries); - else if (r->match_tag && !pf_match_tag(m, r, nr, pftag, &tag)) + else if (r->match_tag && + !pf_match_tag(m, r, nat, rdr, pftag, &tag)) r = TAILQ_NEXT(r, entries); else if (r->anchorname[0] && r->anchor == NULL) r = TAILQ_NEXT(r, entries); @@ -2879,28 +2872,32 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, a = *am; ruleset = *rsm; + r->packets++; + r->bytes += pd->tot_len; + if (a != NULL) { + a->packets++; + a->bytes += pd->tot_len; + } REASON_SET(&reason, PFRES_MATCH); if (r->log) { if (rewrite) - m_copyback(m, off, sizeof(*uh), uh); - PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset); + m_copyback(m, off, sizeof(*uh), (caddr_t)uh); + PFLOG_PACKET(ifp, h, m, af, direction, reason, r, a, ruleset); } if ((r->action == PF_DROP) && ((r->rule_flag & PFRULE_RETURNICMP) || (r->rule_flag & PFRULE_RETURN))) { /* undo NAT changes, if they have taken place */ - if (nr != NULL) { - if (direction == PF_OUT) { - pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum, - &uh->uh_sum, &pd->baddr, bport, 1, af); - rewrite++; - } else { - pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum, - &uh->uh_sum, &pd->baddr, bport, 1, af); - rewrite++; - } + if (nat != NULL) { + pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum, + &uh->uh_sum, &baddr, bport, 1, af); + rewrite++; + } else if (rdr != NULL) { + pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum, + &uh->uh_sum, &baddr, bport, 1, af); + rewrite++; } if ((af == AF_INET) && r->return_icmp) pf_send_icmp(m, r->return_icmp >> 8, @@ -2918,41 +2915,13 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, return (PF_DROP); } - if (r->keep_state || nr != NULL) { + if (r->keep_state || nat != NULL || rdr != NULL) { /* create new state */ struct pf_state *s = NULL; - struct pf_src_node *sn = NULL; - - /* check maximums */ - if (r->max_states && (r->states >= r->max_states)) - goto cleanup; - /* 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) - goto cleanup; - /* src node for translation rule */ - if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) && - ((direction == PF_OUT && - pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) || - (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) - goto cleanup; - s = pool_get(&pf_state_pl, PR_NOWAIT); + + if (!r->max_states || r->states < r->max_states) + s = pool_get(&pf_state_pl, PR_NOWAIT); if (s == NULL) { -cleanup: - if (sn != NULL && sn->states == 0 && sn->expire == 0) { - RB_REMOVE(pf_src_tree, &tree_src_tracking, sn); - pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; - pf_status.src_nodes--; - pool_put(&pf_src_tree_pl, sn); - } - if (nsn != sn && nsn != NULL && nsn->states == 0 && - nsn->expire == 0) { - RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn); - pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; - pf_status.src_nodes--; - pool_put(&pf_src_tree_pl, nsn); - } REASON_SET(&reason, PFRES_MEMORY); return (PF_DROP); } @@ -2961,7 +2930,10 @@ cleanup: if (a != NULL) a->states++; s->rule.ptr = r; - s->nat_rule.ptr = nr; + if (nat != NULL) + s->nat_rule.ptr = nat; + else + s->nat_rule.ptr = rdr; if (s->nat_rule.ptr != NULL) s->nat_rule.ptr->states++; s->anchor.ptr = a; @@ -2975,8 +2947,8 @@ cleanup: s->gwy.port = uh->uh_sport; PF_ACPY(&s->ext.addr, daddr, af); s->ext.port = uh->uh_dport; - if (nr != NULL) { - PF_ACPY(&s->lan.addr, &pd->baddr, af); + if (nat != NULL) { + PF_ACPY(&s->lan.addr, &baddr, af); s->lan.port = bport; } else { PF_ACPY(&s->lan.addr, &s->gwy.addr, af); @@ -2987,32 +2959,37 @@ cleanup: s->lan.port = uh->uh_dport; PF_ACPY(&s->ext.addr, saddr, af); s->ext.port = uh->uh_sport; - if (nr != NULL) { - PF_ACPY(&s->gwy.addr, &pd->baddr, af); + if (rdr != NULL) { + PF_ACPY(&s->gwy.addr, &baddr, af); s->gwy.port = bport; } else { PF_ACPY(&s->gwy.addr, &s->lan.addr, af); s->gwy.port = s->lan.port; } } + s->src.seqlo = 0; + s->src.seqhi = 0; + s->src.seqdiff = 0; + s->src.max_win = 0; s->src.state = PFUDPS_SINGLE; + s->dst.seqlo = 0; + s->dst.seqhi = 0; + s->dst.seqdiff = 0; + s->dst.max_win = 0; s->dst.state = PFUDPS_NO_TRAFFIC; +#ifdef __FreeBSD__ + s->creation = time_second; + s->expire = time_second; +#else s->creation = time.tv_sec; s->expire = time.tv_sec; +#endif s->timeout = PFTM_UDP_FIRST_PACKET; + s->packets[0] = 1; + s->bytes[0] = pd->tot_len; pf_set_rt_ifp(s, saddr); - if (sn != NULL) { - s->src_node = sn; - s->src_node->states++; - } - if (nsn != NULL) { - PF_ACPY(&nsn->raddr, &pd->naddr, af); - s->nat_src_node = nsn; - s->nat_src_node->states++; - } - if (pf_insert_state(BOUND_IFACE(r, kif), s)) { + if (pf_insert_state(s)) { REASON_SET(&reason, PFRES_MEMORY); - pf_src_tree_remove_state(s); pool_put(&pf_state_pl, s); return (PF_DROP); } else @@ -3021,25 +2998,26 @@ 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); } int pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, - struct pfi_kif *kif, struct mbuf *m, int off, void *h, + struct ifnet *ifp, struct mbuf *m, int ipoff, int off, void *h, struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm) { - struct pf_rule *nr = NULL; + struct pf_rule *nat = NULL, *rdr = NULL; struct pf_addr *saddr = pd->src, *daddr = pd->dst; + struct pf_addr baddr, naddr; struct pf_rule *r, *a = NULL; struct pf_ruleset *ruleset = NULL; - struct pf_src_node *nsn = NULL; u_short reason; - u_int16_t icmpid; + u_int16_t icmpid = 0; /* make the compiler happy */ 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; struct pf_tag *pftag = NULL; int tag = -1; @@ -3081,58 +3059,56 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, if (direction == PF_OUT) { /* check outgoing packet for BINAT/NAT */ - if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn, - saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) { - PF_ACPY(&pd->baddr, saddr, af); + if ((nat = pf_get_translation(pd, m, off, PF_OUT, ifp, saddr, 0, + daddr, 0, &naddr, NULL)) != NULL) { + PF_ACPY(&baddr, saddr, af); switch (af) { #ifdef INET case AF_INET: pf_change_a(&saddr->v4.s_addr, pd->ip_sum, - pd->naddr.v4.s_addr, 0); + naddr.v4.s_addr, 0); break; #endif /* INET */ #ifdef INET6 case AF_INET6: pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum, - &pd->naddr, 0); + &naddr, 0); rewrite++; break; #endif /* INET6 */ } - if (nr->natpass) + if (nat->natpass) r = NULL; - pd->nat_rule = nr; } } else { /* check incoming packet for BINAT/RDR */ - if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn, - saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) { - PF_ACPY(&pd->baddr, daddr, af); + if ((rdr = pf_get_translation(pd, m, off, PF_IN, ifp, saddr, 0, + daddr, 0, &naddr, NULL)) != NULL) { + PF_ACPY(&baddr, daddr, af); switch (af) { #ifdef INET case AF_INET: pf_change_a(&daddr->v4.s_addr, - pd->ip_sum, pd->naddr.v4.s_addr, 0); + pd->ip_sum, naddr.v4.s_addr, 0); break; #endif /* INET */ #ifdef INET6 case AF_INET6: pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum, - &pd->naddr, 0); + &naddr, 0); rewrite++; break; #endif /* INET6 */ } - if (nr->natpass) + if (rdr->natpass) r = NULL; - pd->nat_rule = nr; } } while (r != NULL) { r->evaluations++; - if (r->kif != NULL && - (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) + if (r->ifp != NULL && ((r->ifp != ifp && !r->ifnot) || + (r->ifp == ifp && r->ifnot))) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR].ptr; @@ -3152,7 +3128,8 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, r = TAILQ_NEXT(r, entries); else if (r->rule_flag & PFRULE_FRAGMENT) r = TAILQ_NEXT(r, entries); - else if (r->match_tag && !pf_match_tag(m, r, nr, pftag, &tag)) + else if (r->match_tag && + !pf_match_tag(m, r, nat, rdr, pftag, &tag)) r = TAILQ_NEXT(r, entries); else if (r->anchorname[0] && r->anchor == NULL) r = TAILQ_NEXT(r, entries); @@ -3180,15 +3157,21 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, a = *am; ruleset = *rsm; + r->packets++; + r->bytes += pd->tot_len; + if (a != NULL) { + a->packets++; + a->bytes += pd->tot_len; + } REASON_SET(&reason, PFRES_MATCH); 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, a, ruleset); + PFLOG_PACKET(ifp, h, m, af, direction, reason, r, a, ruleset); } if (r->action != PF_PASS) @@ -3199,41 +3182,14 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, return (PF_DROP); } - if (!state_icmp && (r->keep_state || nr != NULL)) { + if (!state_icmp && (r->keep_state || + nat != NULL || rdr != NULL)) { /* create new state */ struct pf_state *s = NULL; - struct pf_src_node *sn = NULL; - - /* check maximums */ - if (r->max_states && (r->states >= r->max_states)) - goto cleanup; - /* 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) - goto cleanup; - /* src node for translation rule */ - if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) && - ((direction == PF_OUT && - pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) || - (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) - goto cleanup; - s = pool_get(&pf_state_pl, PR_NOWAIT); + + if (!r->max_states || r->states < r->max_states) + s = pool_get(&pf_state_pl, PR_NOWAIT); if (s == NULL) { -cleanup: - if (sn != NULL && sn->states == 0 && sn->expire == 0) { - RB_REMOVE(pf_src_tree, &tree_src_tracking, sn); - pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; - pf_status.src_nodes--; - pool_put(&pf_src_tree_pl, sn); - } - if (nsn != sn && nsn != NULL && nsn->states == 0 && - nsn->expire == 0) { - RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn); - pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; - pf_status.src_nodes--; - pool_put(&pf_src_tree_pl, nsn); - } REASON_SET(&reason, PFRES_MEMORY); return (PF_DROP); } @@ -3242,7 +3198,10 @@ cleanup: if (a != NULL) a->states++; s->rule.ptr = r; - s->nat_rule.ptr = nr; + if (nat != NULL) + s->nat_rule.ptr = nat; + else + s->nat_rule.ptr = rdr; if (s->nat_rule.ptr != NULL) s->nat_rule.ptr->states++; s->anchor.ptr = a; @@ -3256,8 +3215,8 @@ cleanup: s->gwy.port = icmpid; PF_ACPY(&s->ext.addr, daddr, af); s->ext.port = icmpid; - if (nr != NULL) - PF_ACPY(&s->lan.addr, &pd->baddr, af); + if (nat != NULL) + PF_ACPY(&s->lan.addr, &baddr, af); else PF_ACPY(&s->lan.addr, &s->gwy.addr, af); s->lan.port = icmpid; @@ -3266,28 +3225,36 @@ cleanup: s->lan.port = icmpid; PF_ACPY(&s->ext.addr, saddr, af); s->ext.port = icmpid; - if (nr != NULL) - PF_ACPY(&s->gwy.addr, &pd->baddr, af); + if (rdr != NULL) + PF_ACPY(&s->gwy.addr, &baddr, af); else PF_ACPY(&s->gwy.addr, &s->lan.addr, af); s->gwy.port = icmpid; } + + s->src.seqlo = 0; + s->src.seqhi = 0; + s->src.seqdiff = 0; + s->src.max_win = 0; + s->src.state = 0; + s->dst.seqlo = 0; + s->dst.seqhi = 0; + s->dst.seqdiff = 0; + s->dst.max_win = 0; + s->dst.state = 0; +#ifdef __FreeBSD__ + s->creation = time_second; + s->expire = time_second; +#else s->creation = time.tv_sec; s->expire = time.tv_sec; +#endif s->timeout = PFTM_ICMP_FIRST_PACKET; + s->packets[0] = 1; + s->bytes[0] = pd->tot_len; pf_set_rt_ifp(s, saddr); - if (sn != NULL) { - s->src_node = sn; - s->src_node->states++; - } - if (nsn != NULL) { - PF_ACPY(&nsn->raddr, &pd->naddr, af); - s->nat_src_node = nsn; - s->nat_src_node->states++; - } - if (pf_insert_state(BOUND_IFACE(r, kif), s)) { + if (pf_insert_state(s)) { REASON_SET(&reason, PFRES_MEMORY); - pf_src_tree_remove_state(s); pool_put(&pf_state_pl, s); return (PF_DROP); } else @@ -3298,7 +3265,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); @@ -3306,14 +3273,14 @@ cleanup: int pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, - struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd, + struct ifnet *ifp, struct mbuf *m, int off, void *h, struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm) { - struct pf_rule *nr = NULL; + struct pf_rule *nat = NULL, *rdr = NULL; struct pf_rule *r, *a = NULL; struct pf_ruleset *ruleset = NULL; - struct pf_src_node *nsn = NULL; struct pf_addr *saddr = pd->src, *daddr = pd->dst; + struct pf_addr baddr, naddr; sa_family_t af = pd->af; u_short reason; struct pf_tag *pftag = NULL; @@ -3323,54 +3290,52 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, if (direction == PF_OUT) { /* check outgoing packet for BINAT/NAT */ - if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn, - saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) { - PF_ACPY(&pd->baddr, saddr, af); + if ((nat = pf_get_translation(pd, m, off, PF_OUT, ifp, saddr, 0, + daddr, 0, &naddr, NULL)) != NULL) { + PF_ACPY(&baddr, saddr, af); switch (af) { #ifdef INET case AF_INET: pf_change_a(&saddr->v4.s_addr, pd->ip_sum, - pd->naddr.v4.s_addr, 0); + naddr.v4.s_addr, 0); break; #endif /* INET */ #ifdef INET6 case AF_INET6: - PF_ACPY(saddr, &pd->naddr, af); + PF_ACPY(saddr, &naddr, af); break; #endif /* INET6 */ } - if (nr->natpass) + if (nat->natpass) r = NULL; - pd->nat_rule = nr; } } else { /* check incoming packet for BINAT/RDR */ - if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn, - saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) { - PF_ACPY(&pd->baddr, daddr, af); + if ((rdr = pf_get_translation(pd, m, off, PF_IN, ifp, saddr, 0, + daddr, 0, &naddr, NULL)) != NULL) { + PF_ACPY(&baddr, daddr, af); switch (af) { #ifdef INET case AF_INET: pf_change_a(&daddr->v4.s_addr, - pd->ip_sum, pd->naddr.v4.s_addr, 0); + pd->ip_sum, naddr.v4.s_addr, 0); break; #endif /* INET */ #ifdef INET6 case AF_INET6: - PF_ACPY(daddr, &pd->naddr, af); + PF_ACPY(daddr, &naddr, af); break; #endif /* INET6 */ } - if (nr->natpass) + if (rdr->natpass) r = NULL; - pd->nat_rule = nr; } } while (r != NULL) { r->evaluations++; - if (r->kif != NULL && - (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) + if (r->ifp != NULL && ((r->ifp != ifp && !r->ifnot) || + (r->ifp == ifp && r->ifnot))) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR].ptr; @@ -3386,7 +3351,8 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, r = TAILQ_NEXT(r, entries); else if (r->rule_flag & PFRULE_FRAGMENT) r = TAILQ_NEXT(r, entries); - else if (r->match_tag && !pf_match_tag(m, r, nr, pftag, &tag)) + else if (r->match_tag && + !pf_match_tag(m, r, nat, rdr, pftag, &tag)) r = TAILQ_NEXT(r, entries); else if (r->anchorname[0] && r->anchor == NULL) r = TAILQ_NEXT(r, entries); @@ -3414,33 +3380,36 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, a = *am; ruleset = *rsm; + r->packets++; + r->bytes += pd->tot_len; + if (a != NULL) { + a->packets++; + a->bytes += pd->tot_len; + } REASON_SET(&reason, PFRES_MATCH); - if (r->log) - PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset); + PFLOG_PACKET(ifp, h, m, af, direction, reason, r, a, ruleset); if ((r->action == PF_DROP) && ((r->rule_flag & PFRULE_RETURNICMP) || (r->rule_flag & PFRULE_RETURN))) { struct pf_addr *a = NULL; - if (nr != NULL) { - if (direction == PF_OUT) - a = saddr; - else - a = daddr; - } + if (nat != NULL) + a = saddr; + else if (rdr != NULL) + a = daddr; if (a != NULL) { switch (af) { #ifdef INET case AF_INET: pf_change_a(&a->v4.s_addr, pd->ip_sum, - pd->baddr.v4.s_addr, 0); + baddr.v4.s_addr, 0); break; #endif /* INET */ #ifdef INET6 case AF_INET6: - PF_ACPY(a, &pd->baddr, af); + PF_ACPY(a, &baddr, af); break; #endif /* INET6 */ } @@ -3461,41 +3430,13 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, return (PF_DROP); } - if (r->keep_state || nr != NULL) { + if (r->keep_state || nat != NULL || rdr != NULL) { /* create new state */ struct pf_state *s = NULL; - struct pf_src_node *sn = NULL; - - /* check maximums */ - if (r->max_states && (r->states >= r->max_states)) - goto cleanup; - /* 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) - goto cleanup; - /* src node for translation rule */ - if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) && - ((direction == PF_OUT && - pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) || - (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) - goto cleanup; - s = pool_get(&pf_state_pl, PR_NOWAIT); + + if (!r->max_states || r->states < r->max_states) + s = pool_get(&pf_state_pl, PR_NOWAIT); if (s == NULL) { -cleanup: - if (sn != NULL && sn->states == 0 && sn->expire == 0) { - RB_REMOVE(pf_src_tree, &tree_src_tracking, sn); - pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; - pf_status.src_nodes--; - pool_put(&pf_src_tree_pl, sn); - } - if (nsn != sn && nsn != NULL && nsn->states == 0 && - nsn->expire == 0) { - RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn); - pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; - pf_status.src_nodes--; - pool_put(&pf_src_tree_pl, nsn); - } REASON_SET(&reason, PFRES_MEMORY); return (PF_DROP); } @@ -3504,7 +3445,10 @@ cleanup: if (a != NULL) a->states++; s->rule.ptr = r; - s->nat_rule.ptr = nr; + if (nat != NULL) + s->nat_rule.ptr = nat; + else + s->nat_rule.ptr = rdr; if (s->nat_rule.ptr != NULL) s->nat_rule.ptr->states++; s->anchor.ptr = a; @@ -3515,37 +3459,51 @@ cleanup: s->af = af; if (direction == PF_OUT) { PF_ACPY(&s->gwy.addr, saddr, af); + s->gwy.port = 0; PF_ACPY(&s->ext.addr, daddr, af); - if (nr != NULL) - PF_ACPY(&s->lan.addr, &pd->baddr, af); + s->ext.port = 0; + if (nat != NULL) + PF_ACPY(&s->lan.addr, &baddr, af); else PF_ACPY(&s->lan.addr, &s->gwy.addr, af); + s->lan.port = 0; } else { PF_ACPY(&s->lan.addr, daddr, af); + s->lan.port = 0; PF_ACPY(&s->ext.addr, saddr, af); - if (nr != NULL) - PF_ACPY(&s->gwy.addr, &pd->baddr, af); + s->ext.port = 0; + if (rdr != NULL) + PF_ACPY(&s->gwy.addr, &baddr, af); else PF_ACPY(&s->gwy.addr, &s->lan.addr, af); + s->gwy.port = 0; } + s->src.seqlo = 0; + s->src.seqhi = 0; + s->src.seqdiff = 0; + s->src.max_win = 0; s->src.state = PFOTHERS_SINGLE; + s->dst.seqlo = 0; + s->dst.seqhi = 0; + s->dst.seqdiff = 0; + s->dst.max_win = 0; s->dst.state = PFOTHERS_NO_TRAFFIC; +#ifdef __FreeBSD__ + s->creation = time_second; + s->expire = time_second; +#else s->creation = time.tv_sec; s->expire = time.tv_sec; +#endif s->timeout = PFTM_OTHER_FIRST_PACKET; + s->packets[0] = 1; + s->bytes[0] = pd->tot_len; pf_set_rt_ifp(s, saddr); - if (sn != NULL) { - s->src_node = sn; - s->src_node->states++; - } - if (nsn != NULL) { - PF_ACPY(&nsn->raddr, &pd->naddr, af); - s->nat_src_node = nsn; - s->nat_src_node->states++; - } - if (pf_insert_state(BOUND_IFACE(r, kif), s)) { + if (pf_insert_state(s)) { REASON_SET(&reason, PFRES_MEMORY); - pf_src_tree_remove_state(s); + if (r->log) + PFLOG_PACKET(ifp, h, m, af, direction, reason, + r, a, ruleset); pool_put(&pf_state_pl, s); return (PF_DROP); } else @@ -3556,7 +3514,7 @@ cleanup: } int -pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, +pf_test_fragment(struct pf_rule **rm, int direction, struct ifnet *ifp, struct mbuf *m, void *h, struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm) { @@ -3570,8 +3528,8 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); while (r != NULL) { r->evaluations++; - if (r->kif != NULL && - (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) + if (r->ifp != NULL && ((r->ifp != ifp && !r->ifnot) || + (r->ifp == ifp && r->ifnot))) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR].ptr; @@ -3589,7 +3547,8 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, r->flagset || r->type || r->code || r->os_fingerprint != PF_OSFP_ANY) r = TAILQ_NEXT(r, entries); - else if (r->match_tag && !pf_match_tag(m, r, NULL, pftag, &tag)) + else if (r->match_tag && + !pf_match_tag(m, r, NULL, NULL, pftag, &tag)) r = TAILQ_NEXT(r, entries); else if (r->anchorname[0] && r->anchor == NULL) r = TAILQ_NEXT(r, entries); @@ -3613,10 +3572,15 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, a = *am; ruleset = *rsm; + r->packets++; + r->bytes += pd->tot_len; + if (a != NULL) { + a->packets++; + a->bytes += pd->tot_len; + } REASON_SET(&reason, PFRES_MATCH); - if (r->log) - PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset); + PFLOG_PACKET(ifp, h, m, af, direction, reason, r, a, ruleset); if (r->action != PF_PASS) return (PF_DROP); @@ -3630,41 +3594,36 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, } int -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, +pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp, + struct mbuf *m, int ipoff, int off, void *h, struct pf_pdesc *pd, u_short *reason) { - struct pf_state key; + struct pf_tree_node key; struct tcphdr *th = pd->hdr.tcp; u_int16_t win = ntohs(th->th_win); u_int32_t ack, end, seq; u_int8_t sws, dws; - int ackskew; + int ackskew, dirndx; int copyback = 0; struct pf_state_peer *src, *dst; key.af = pd->af; key.proto = IPPROTO_TCP; - if (direction == PF_IN) { - PF_ACPY(&key.ext.addr, pd->src, key.af); - PF_ACPY(&key.gwy.addr, pd->dst, key.af); - key.ext.port = th->th_sport; - key.gwy.port = th->th_dport; - } else { - PF_ACPY(&key.lan.addr, pd->src, key.af); - PF_ACPY(&key.ext.addr, pd->dst, key.af); - key.lan.port = th->th_sport; - key.ext.port = th->th_dport; - } + PF_ACPY(&key.addr[0], pd->src, key.af); + PF_ACPY(&key.addr[1], pd->dst, key.af); + key.port[0] = th->th_sport; + key.port[1] = th->th_dport; STATE_LOOKUP(); if (direction == (*state)->direction) { src = &(*state)->src; dst = &(*state)->dst; + dirndx = 0; } else { src = &(*state)->dst; dst = &(*state)->src; + dirndx = 1; } if ((*state)->src.state == PF_TCPS_PROXY_SRC) { @@ -3705,8 +3664,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, (*state)->dst.seqhi = arc4random(); pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr, &dst->addr, src->port, dst->port, - (*state)->dst.seqhi, 0, TH_SYN, 0, - (*state)->src.mss, 0); + (*state)->dst.seqhi, 0, TH_SYN, 0, (*state)->src.mss, 0); return (PF_SYNPROXY_DROP); } else if (((th->th_flags & (TH_SYN|TH_ACK)) != (TH_SYN|TH_ACK)) || @@ -3863,6 +3821,9 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, (ackskew <= (MAXACKWINDOW << sws))) { /* Acking not more than one window forward */ + (*state)->packets[dirndx]++; + (*state)->bytes[dirndx] += pd->tot_len; + /* update max window */ if (src->max_win < win) src->max_win = win; @@ -3891,7 +3852,11 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, src->state = dst->state = TCPS_TIME_WAIT; /* update expire time */ +#ifdef __FreeBSD__ + (*state)->expire = time_second; +#else (*state)->expire = time.tv_sec; +#endif if (src->state >= TCPS_FIN_WAIT_2 && dst->state >= TCPS_FIN_WAIT_2) (*state)->timeout = PFTM_TCP_CLOSED; @@ -3947,6 +3912,9 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, (*state)->packets[0], (*state)->packets[1]); } + (*state)->packets[dirndx]++; + (*state)->bytes[dirndx] += pd->tot_len; + /* update max window */ if (src->max_win < win) src->max_win = win; @@ -4012,8 +3980,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, } if (dst->scrub || src->scrub) { - if (pf_normalize_tcp_stateful(m, off, pd, reason, th, - src, dst, ©back)) + if (pf_normalize_tcp_stateful(m, off, pd, reason, th, src, dst, + ©back)) return (PF_DROP); } @@ -4029,47 +3997,56 @@ 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); } + (*state)->rule.ptr->packets++; + (*state)->rule.ptr->bytes += pd->tot_len; + if ((*state)->nat_rule.ptr != NULL) { + (*state)->nat_rule.ptr->packets++; + (*state)->nat_rule.ptr->bytes += pd->tot_len; + } + if ((*state)->anchor.ptr != NULL) { + (*state)->anchor.ptr->packets++; + (*state)->anchor.ptr->bytes += pd->tot_len; + } return (PF_PASS); } int -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) +pf_test_state_udp(struct pf_state **state, int direction, struct ifnet *ifp, + struct mbuf *m, int ipoff, int off, void *h, struct pf_pdesc *pd) { struct pf_state_peer *src, *dst; - struct pf_state key; + struct pf_tree_node key; struct udphdr *uh = pd->hdr.udp; + int dirndx; key.af = pd->af; key.proto = IPPROTO_UDP; - if (direction == PF_IN) { - PF_ACPY(&key.ext.addr, pd->src, key.af); - PF_ACPY(&key.gwy.addr, pd->dst, key.af); - key.ext.port = uh->uh_sport; - key.gwy.port = uh->uh_dport; - } else { - PF_ACPY(&key.lan.addr, pd->src, key.af); - PF_ACPY(&key.ext.addr, pd->dst, key.af); - key.lan.port = uh->uh_sport; - key.ext.port = uh->uh_dport; - } + PF_ACPY(&key.addr[0], pd->src, key.af); + PF_ACPY(&key.addr[1], pd->dst, key.af); + key.port[0] = uh->uh_sport; + key.port[1] = uh->uh_dport; STATE_LOOKUP(); if (direction == (*state)->direction) { src = &(*state)->src; dst = &(*state)->dst; + dirndx = 0; } else { src = &(*state)->dst; dst = &(*state)->src; + dirndx = 1; } + (*state)->packets[dirndx]++; + (*state)->bytes[dirndx] += pd->tot_len; + /* update states */ if (src->state < PFUDPS_SINGLE) src->state = PFUDPS_SINGLE; @@ -4077,7 +4054,11 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif, dst->state = PFUDPS_MULTIPLE; /* update expire time */ +#ifdef __FreeBSD__ + (*state)->expire = time_second; +#else (*state)->expire = time.tv_sec; +#endif if (src->state == PFUDPS_MULTIPLE && dst->state == PFUDPS_MULTIPLE) (*state)->timeout = PFTM_UDP_MULTIPLE; else @@ -4093,20 +4074,31 @@ 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); } + (*state)->rule.ptr->packets++; + (*state)->rule.ptr->bytes += pd->tot_len; + if ((*state)->nat_rule.ptr != NULL) { + (*state)->nat_rule.ptr->packets++; + (*state)->nat_rule.ptr->bytes += pd->tot_len; + } + if ((*state)->anchor.ptr != NULL) { + (*state)->anchor.ptr->packets++; + (*state)->anchor.ptr->bytes += pd->tot_len; + } return (PF_PASS); } int -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) +pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, + struct mbuf *m, int ipoff, int off, void *h, struct pf_pdesc *pd) { struct pf_addr *saddr = pd->src, *daddr = pd->dst; - u_int16_t icmpid, *icmpsum; - u_int8_t icmptype; - int state_icmp = 0; + 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, dirndx; switch (pd->proto) { #ifdef INET @@ -4144,25 +4136,25 @@ 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; + struct pf_tree_node key; key.af = pd->af; key.proto = pd->proto; - if (direction == PF_IN) { - PF_ACPY(&key.ext.addr, pd->src, key.af); - PF_ACPY(&key.gwy.addr, pd->dst, key.af); - key.ext.port = icmpid; - key.gwy.port = icmpid; - } else { - PF_ACPY(&key.lan.addr, pd->src, key.af); - PF_ACPY(&key.ext.addr, pd->dst, key.af); - key.lan.port = icmpid; - key.ext.port = icmpid; - } + PF_ACPY(&key.addr[0], saddr, key.af); + PF_ACPY(&key.addr[1], daddr, key.af); + key.port[0] = icmpid; + key.port[1] = icmpid; STATE_LOOKUP(); + dirndx = (direction == (*state)->direction) ? 0 : 1; + (*state)->packets[dirndx]++; + (*state)->bytes[dirndx] += pd->tot_len; +#ifdef __FreeBSD__ + (*state)->expire = time_second; +#else (*state)->expire = time.tv_sec; +#endif (*state)->timeout = PFTM_ICMP_ERROR_REPLY; /* translate source/destination address, if necessary */ @@ -4183,7 +4175,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 */ } @@ -4203,7 +4195,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 */ } @@ -4226,8 +4218,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) { @@ -4317,7 +4309,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_tree_node key; struct pf_state_peer *src, *dst; u_int8_t dws; int copyback = 0; @@ -4336,17 +4328,10 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, key.af = pd2.af; key.proto = IPPROTO_TCP; - if (direction == PF_IN) { - PF_ACPY(&key.ext.addr, pd2.dst, key.af); - PF_ACPY(&key.gwy.addr, pd2.src, key.af); - key.ext.port = th.th_dport; - key.gwy.port = th.th_sport; - } else { - PF_ACPY(&key.lan.addr, pd2.dst, key.af); - PF_ACPY(&key.ext.addr, pd2.src, key.af); - key.lan.port = th.th_dport; - key.ext.port = th.th_sport; - } + PF_ACPY(&key.addr[0], pd2.dst, pd2.af); + key.port[0] = th.th_dport; + PF_ACPY(&key.addr[1], pd2.src, pd2.af); + key.port[1] = th.th_sport; STATE_LOOKUP(); @@ -4358,8 +4343,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, dst = &(*state)->dst; } - if (src->wscale && dst->wscale && - !(th.th_flags & TH_SYN)) + if (src->wscale && dst->wscale && !(th.th_flags & TH_SYN)) dws = dst->wscale & PF_WSCALE_MASK; else dws = 0; @@ -4409,22 +4393,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); @@ -4432,7 +4416,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; + struct pf_tree_node key; if (!pf_pull_hdr(m, off2, &uh, sizeof(uh), NULL, NULL, pd2.af)) { @@ -4444,17 +4428,10 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, key.af = pd2.af; key.proto = IPPROTO_UDP; - if (direction == PF_IN) { - PF_ACPY(&key.ext.addr, pd2.dst, key.af); - PF_ACPY(&key.gwy.addr, pd2.src, key.af); - key.ext.port = uh.uh_dport; - key.gwy.port = uh.uh_sport; - } else { - PF_ACPY(&key.lan.addr, pd2.dst, key.af); - PF_ACPY(&key.ext.addr, pd2.src, key.af); - key.lan.port = uh.uh_dport; - key.ext.port = uh.uh_sport; - } + PF_ACPY(&key.addr[0], pd2.dst, pd2.af); + key.port[0] = uh.uh_dport; + PF_ACPY(&key.addr[1], pd2.src, pd2.af); + key.port[1] = uh.uh_sport; STATE_LOOKUP(); @@ -4476,21 +4453,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); @@ -4499,7 +4478,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; + struct pf_tree_node key; if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN, NULL, NULL, pd2.af)) { @@ -4511,17 +4490,10 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, key.af = pd2.af; key.proto = IPPROTO_ICMP; - if (direction == PF_IN) { - PF_ACPY(&key.ext.addr, pd2.dst, key.af); - PF_ACPY(&key.gwy.addr, pd2.src, key.af); - key.ext.port = iih.icmp_id; - key.gwy.port = iih.icmp_id; - } else { - PF_ACPY(&key.lan.addr, pd2.dst, key.af); - PF_ACPY(&key.ext.addr, pd2.src, key.af); - key.lan.port = iih.icmp_id; - key.ext.port = iih.icmp_id; - } + PF_ACPY(&key.addr[0], pd2.dst, pd2.af); + key.port[0] = iih.icmp_id; + PF_ACPY(&key.addr[1], pd2.src, pd2.af); + key.port[1] = iih.icmp_id; STATE_LOOKUP(); @@ -4539,9 +4511,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); @@ -4551,7 +4526,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; + struct pf_tree_node key; if (!pf_pull_hdr(m, off2, &iih, sizeof(struct icmp6_hdr), NULL, NULL, pd2.af)) { @@ -4563,17 +4538,10 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, key.af = pd2.af; key.proto = IPPROTO_ICMPV6; - if (direction == PF_IN) { - PF_ACPY(&key.ext.addr, pd2.dst, key.af); - PF_ACPY(&key.gwy.addr, pd2.src, key.af); - key.ext.port = iih.icmp6_id; - key.gwy.port = iih.icmp6_id; - } else { - PF_ACPY(&key.lan.addr, pd2.dst, key.af); - PF_ACPY(&key.ext.addr, pd2.src, key.af); - key.lan.port = iih.icmp6_id; - key.ext.port = iih.icmp6_id; - } + PF_ACPY(&key.addr[0], pd2.dst, pd2.af); + key.port[0] = iih.icmp6_id; + PF_ACPY(&key.addr[1], pd2.src, pd2.af); + key.port[1] = iih.icmp6_id; STATE_LOOKUP(); @@ -4592,10 +4560,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); @@ -4603,21 +4572,14 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, } #endif /* INET6 */ default: { - struct pf_state key; + struct pf_tree_node key; key.af = pd2.af; key.proto = pd2.proto; - if (direction == PF_IN) { - PF_ACPY(&key.ext.addr, pd2.dst, key.af); - PF_ACPY(&key.gwy.addr, pd2.src, key.af); - key.ext.port = 0; - key.gwy.port = 0; - } else { - PF_ACPY(&key.lan.addr, pd2.dst, key.af); - PF_ACPY(&key.ext.addr, pd2.src, key.af); - key.lan.port = 0; - key.ext.port = 0; - } + PF_ACPY(&key.addr[0], pd2.dst, pd2.af); + key.port[0] = 0; + PF_ACPY(&key.addr[1], pd2.src, pd2.af); + key.port[1] = 0; STATE_LOOKUP(); @@ -4639,17 +4601,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 */ } @@ -4663,36 +4626,35 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, } int -pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif, +pf_test_state_other(struct pf_state **state, int direction, struct ifnet *ifp, struct pf_pdesc *pd) { struct pf_state_peer *src, *dst; - struct pf_state key; + struct pf_tree_node key; + int dirndx; key.af = pd->af; key.proto = pd->proto; - if (direction == PF_IN) { - PF_ACPY(&key.ext.addr, pd->src, key.af); - PF_ACPY(&key.gwy.addr, pd->dst, key.af); - key.ext.port = 0; - key.gwy.port = 0; - } else { - PF_ACPY(&key.lan.addr, pd->src, key.af); - PF_ACPY(&key.ext.addr, pd->dst, key.af); - key.lan.port = 0; - key.ext.port = 0; - } + PF_ACPY(&key.addr[0], pd->src, key.af); + PF_ACPY(&key.addr[1], pd->dst, key.af); + key.port[0] = 0; + key.port[1] = 0; STATE_LOOKUP(); if (direction == (*state)->direction) { src = &(*state)->src; dst = &(*state)->dst; + dirndx = 0; } else { src = &(*state)->dst; dst = &(*state)->src; + dirndx = 1; } + (*state)->packets[dirndx]++; + (*state)->bytes[dirndx] += pd->tot_len; + /* update states */ if (src->state < PFOTHERS_SINGLE) src->state = PFOTHERS_SINGLE; @@ -4700,7 +4662,11 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif, dst->state = PFOTHERS_MULTIPLE; /* update expire time */ +#ifdef __FreeBSD__ + (*state)->expire = time_second; +#else (*state)->expire = time.tv_sec; +#endif if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE) (*state)->timeout = PFTM_OTHER_MULTIPLE; else @@ -4740,6 +4706,16 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif, } } + (*state)->rule.ptr->packets++; + (*state)->rule.ptr->bytes += pd->tot_len; + if ((*state)->nat_rule.ptr != NULL) { + (*state)->nat_rule.ptr->packets++; + (*state)->nat_rule.ptr->bytes += pd->tot_len; + } + if ((*state)->anchor.ptr != NULL) { + (*state)->anchor.ptr->packets++; + (*state)->anchor.ptr->bytes += pd->tot_len; + } return (PF_PASS); } @@ -4766,8 +4742,7 @@ pf_pull_hdr(struct mbuf *m, int off, void *p, int len, } return (NULL); } - if (m->m_pkthdr.len < off + len || - ntohs(h->ip_len) < off + len) { + if (m->m_pkthdr.len < off + len || ntohs(h->ip_len) < off + len) { ACTION_SET(actionp, PF_DROP); REASON_SET(reasonp, PFRES_SHORT); return (NULL); @@ -4806,7 +4781,15 @@ pf_routable(struct pf_addr *addr, sa_family_t af) dst->sin_family = af; 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 if (ro.ro_rt != NULL) { ret = 1; @@ -4817,20 +4800,184 @@ pf_routable(struct pf_addr *addr, sa_family_t af) } #ifdef INET + +#if defined(__FreeBSD__) && (__FreeBSD_version < 501105) +int +ip_fragment(struct ip *ip, struct mbuf **m_frag, int mtu, + u_long if_hwassist_flags, int sw_csum) +{ + int error = 0; + int hlen = ip->ip_hl << 2; + int len = (mtu - hlen) & ~7; /* size of payload in each fragment */ + int off; + struct mbuf *m0 = *m_frag; /* the original packet */ + int firstlen; + struct mbuf **mnext; + int nfrags; + + if (ip->ip_off & IP_DF) { /* Fragmentation not allowed */ + ipstat.ips_cantfrag++; + return EMSGSIZE; + } + + /* + * Must be able to put at least 8 bytes per fragment. + */ + if (len < 8) + return EMSGSIZE; + + /* + * If the interface will not calculate checksums on + * fragmented packets, then do it here. + */ + if (m0->m_pkthdr.csum_flags & CSUM_DELAY_DATA && + (if_hwassist_flags & CSUM_IP_FRAGS) == 0) { + in_delayed_cksum(m0); + m0->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; + } + + if (len > PAGE_SIZE) { + /* + * Fragment large datagrams such that each segment + * contains a multiple of PAGE_SIZE amount of data, + * plus headers. This enables a receiver to perform + * page-flipping zero-copy optimizations. + * + * XXX When does this help given that sender and receiver + * could have different page sizes, and also mtu could + * be less than the receiver's page size ? + */ + int newlen; + struct mbuf *m; + + for (m = m0, off = 0; m && (off+m->m_len) <= mtu; m = m->m_next) + off += m->m_len; + + /* + * firstlen (off - hlen) must be aligned on an + * 8-byte boundary + */ + if (off < hlen) + goto smart_frag_failure; + off = ((off - hlen) & ~7) + hlen; + newlen = (~PAGE_MASK) & mtu; + if ((newlen + sizeof (struct ip)) > mtu) { + /* we failed, go back the default */ +smart_frag_failure: + newlen = len; + off = hlen + len; + } + len = newlen; + + } else { + off = hlen + len; + } + + firstlen = off - hlen; + mnext = &m0->m_nextpkt; /* pointer to next packet */ + + /* + * Loop through length of segment after first fragment, + * make new header and copy data of each part and link onto chain. + * Here, m0 is the original packet, m is the fragment being created. + * The fragments are linked off the m_nextpkt of the original + * packet, which after processing serves as the first fragment. + */ + for (nfrags = 1; off < ip->ip_len; off += len, nfrags++) { + struct ip *mhip; /* ip header on the fragment */ + struct mbuf *m; + int mhlen = sizeof (struct ip); + + MGETHDR(m, M_DONTWAIT, MT_HEADER); + if (m == 0) { + error = ENOBUFS; + ipstat.ips_odropped++; + goto done; + } + m->m_flags |= (m0->m_flags & M_MCAST) | M_FRAG; + /* + * In the first mbuf, leave room for the link header, then + * copy the original IP header including options. The payload + * goes into an additional mbuf chain returned by m_copy(). + */ + m->m_data += max_linkhdr; + mhip = mtod(m, struct ip *); + *mhip = *ip; + if (hlen > sizeof (struct ip)) { + mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); + mhip->ip_v = IPVERSION; + mhip->ip_hl = mhlen >> 2; + } + m->m_len = mhlen; + /* XXX do we need to add ip->ip_off below ? */ + mhip->ip_off = ((off - hlen) >> 3) + ip->ip_off; + if (off + len >= ip->ip_len) { /* last fragment */ + len = ip->ip_len - off; + m->m_flags |= M_LASTFRAG; + } else + mhip->ip_off |= IP_MF; + mhip->ip_len = htons((u_short)(len + mhlen)); + m->m_next = m_copy(m0, off, len); + if (m->m_next == 0) { /* copy failed */ + m_free(m); + error = ENOBUFS; /* ??? */ + ipstat.ips_odropped++; + goto done; + } + m->m_pkthdr.len = mhlen + len; + m->m_pkthdr.rcvif = (struct ifnet *)0; +#ifdef MAC + mac_create_fragment(m0, m); +#endif + m->m_pkthdr.csum_flags = m0->m_pkthdr.csum_flags; + mhip->ip_off = htons(mhip->ip_off); + mhip->ip_sum = 0; + if (sw_csum & CSUM_DELAY_IP) + mhip->ip_sum = in_cksum(m, mhlen); + *mnext = m; + mnext = &m->m_nextpkt; + } + ipstat.ips_ofragments += nfrags; + + /* set first marker for fragment chain */ + m0->m_flags |= M_FIRSTFRAG | M_FRAG; + m0->m_pkthdr.csum_data = nfrags; + + /* + * Update first fragment by trimming what's been copied out + * and updating header. + */ + m_adj(m0, hlen + firstlen - ip->ip_len); + m0->m_pkthdr.len = hlen + firstlen; + ip->ip_len = htons((u_short)m0->m_pkthdr.len); + ip->ip_off |= IP_MF; + ip->ip_off = htons(ip->ip_off); + ip->ip_sum = 0; + if (sw_csum & CSUM_DELAY_IP) + ip->ip_sum = in_cksum(m0, hlen); + +done: + *m_frag = m0; + return error; +} +#endif /* __FreeBSD__ && __FreeBSD_version > 501105 */ + void pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, struct pf_state *s) { struct mbuf *m0, *m1; struct route iproute; - struct route *ro; + struct route *ro = NULL; /* XXX: was uninitialized */ struct sockaddr_in *dst; struct ip *ip; struct ifnet *ifp = NULL; struct m_tag *mtag; struct pf_addr naddr; - struct pf_src_node *sn = NULL; int error = 0; +#ifdef __FreeBSD__ + int sw_csum; +#endif if (m == NULL || *m == NULL || r == NULL || (dir != PF_IN && dir != PF_OUT) || oifp == NULL) @@ -4845,7 +4992,11 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, goto bad; m_tag_prepend(m0, mtag); } +#ifdef __FreeBSD__ + m0 = m_dup(*m, M_DONTWAIT); +#else m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT); +#endif if (m0 == NULL) return; } else { @@ -4881,72 +5032,94 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, if (TAILQ_EMPTY(&r->rpool.list)) panic("pf_route: TAILQ_EMPTY(&r->rpool.list)"); if (s == NULL) { - pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src, - &naddr, NULL, &sn); + pf_map_addr(AF_INET, &r->rpool, + (struct pf_addr *)&ip->ip_src, + &naddr, NULL); if (!PF_AZERO(&naddr, AF_INET)) dst->sin_addr.s_addr = naddr.v4.s_addr; - ifp = r->rpool.cur->kif ? - r->rpool.cur->kif->pfik_ifp : NULL; + ifp = r->rpool.cur->ifp; } else { if (!PF_AZERO(&s->rt_addr, AF_INET)) dst->sin_addr.s_addr = s->rt_addr.v4.s_addr; - ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL; + ifp = s->rt_ifp; } } if (ifp == NULL) goto bad; - mtag = m_tag_find(m0, PACKET_TAG_PF_ROUTED, NULL); - if (mtag == NULL) { - struct m_tag *mtag; + if (m_tag_find(m0, PACKET_TAG_PF_ROUTED, NULL) != NULL) + goto bad; + mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 0, M_NOWAIT); + if (mtag == NULL) + goto bad; + m_tag_prepend(m0, mtag); - mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 0, M_NOWAIT); - if (mtag == NULL) + if (oifp != ifp) { +#ifdef __FreeBSD__ + PF_UNLOCK(); + if (pf_test(PF_OUT, ifp, &m0) != PF_PASS) { + PF_LOCK(); goto bad; - m_tag_prepend(m0, mtag); - } - - if (oifp != ifp && mtag == NULL) { + } else if (m0 == NULL) { + PF_LOCK(); + goto done; + } + PF_LOCK(); +#else if (pf_test(PF_OUT, ifp, &m0) != PF_PASS) goto bad; else if (m0 == NULL) goto done; +#endif if (m0->m_len < sizeof(struct ip)) panic("pf_route: m0->m_len < sizeof(struct ip)"); ip = mtod(m0, struct ip *); } - /* Copied from ip_output. */ -#ifdef IPSEC - /* - * If deferred crypto processing is needed, check that the - * interface supports it. - */ - if ((mtag = m_tag_find(m0, PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED, NULL)) - != NULL && (ifp->if_capabilities & IFCAP_IPSEC) == 0) { - /* Notify IPsec to do its own crypto. */ - ipsp_skipcrypto_unmark((struct tdb_ident *)(mtag + 1)); - goto bad; - } -#endif /* IPSEC */ - - /* Catch routing changes wrt. hardware checksumming for TCP or UDP. */ - 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 &= ~M_TCPV4_CSUM_OUT; /* Clear */ - } - } 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 &= ~M_UDPV4_CSUM_OUT; /* Clear */ +#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. */ if (ntohs(ip->ip_len) <= ifp->if_mtu) { if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) && ifp->if_bridge == NULL) { @@ -4964,7 +5137,7 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, 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. @@ -4972,27 +5145,56 @@ 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(); +#endif icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0, ifp); +#ifdef __FreeBSD__ + PF_LOCK(); +#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); } @@ -5025,7 +5227,6 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, struct ip6_hdr *ip6; struct ifnet *ifp = NULL; struct pf_addr naddr; - struct pf_src_node *sn = NULL; int error = 0; if (m == NULL || *m == NULL || r == NULL || @@ -5041,7 +5242,11 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, goto bad; m_tag_prepend(m0, mtag); } +#ifdef __FreeBSD__ + m0 = m_dup(*m, M_DONTWAIT); +#else m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT); +#endif if (m0 == NULL) return; } else { @@ -5067,24 +5272,30 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, if (mtag == NULL) goto bad; m_tag_prepend(m0, mtag); +#ifdef __FreeBSD__ + PF_UNLOCK(); + ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL); + PF_LOCK(); +#else ip6_output(m0, NULL, NULL, 0, NULL, NULL); +#endif return; } if (TAILQ_EMPTY(&r->rpool.list)) panic("pf_route6: TAILQ_EMPTY(&r->rpool.list)"); if (s == NULL) { - pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src, - &naddr, NULL, &sn); + pf_map_addr(AF_INET6, &r->rpool, + (struct pf_addr *)&ip6->ip6_src, &naddr, NULL); if (!PF_AZERO(&naddr, AF_INET6)) PF_ACPY((struct pf_addr *)&dst->sin6_addr, &naddr, AF_INET6); - ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL; + ifp = r->rpool.cur->ifp; } else { if (!PF_AZERO(&s->rt_addr, AF_INET6)) PF_ACPY((struct pf_addr *)&dst->sin6_addr, &s->rt_addr, AF_INET6); - ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL; + ifp = s->rt_ifp; } if (ifp == NULL) @@ -5097,10 +5308,22 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, if (mtag == NULL) goto bad; m_tag_prepend(m0, mtag); +#ifdef __FreeBSD__ + PF_UNLOCK(); + if (pf_test6(PF_OUT, ifp, &m0) != PF_PASS) { + PF_LOCK(); + goto bad; + } else if (m0 == NULL) { + PF_LOCK(); + goto done; + } + PF_LOCK(); +#else if (pf_test6(PF_OUT, ifp, &m0) != PF_PASS) goto bad; else if (m0 == NULL) goto done; +#endif } } @@ -5111,12 +5334,26 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, 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; } @@ -5132,6 +5369,135 @@ bad: #endif /* INET6 */ +#ifdef __FreeBSD__ +/* + * XXX + * FreeBSD supports cksum offload for the following drivers. + * em(4), gx(4), lge(4), nge(4), ti(4), xl(4) + * If we can make full use of it we would outperform ipfw/ipfilter in + * very heavy traffic. + * I have not tested 'cause I don't have NICs that supports cksum offload. + * (There might be problems. Typical phenomena would be + * 1. No route message for UDP packet. + * 2. No connection acceptance from external hosts regardless of rule set.) + */ +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(m->m_pkthdr.csum_data + + IPPROTO_TCP) + ip->ip_len); + } + 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); + if (sum == 0) { + m->m_pkthdr.csum_flags |= + (CSUM_DATA_VALID | + CSUM_PSEUDO_HDR); + m->m_pkthdr.csum_data = 0xffff; + } + } + break; +#ifdef INET6 + case AF_INET6: + if (m->m_len < sizeof(struct ip6_hdr)) + return (1); + sum = in6_cksum(m, p, off, len); + /* + * XXX + * IPv6 H/W cksum off-load not supported yet! + * + * if (sum == 0) { + * m->m_pkthdr.csum_flags |= + * (CSUM_DATA_VALID|CSUM_PSEUDO_HDR); + * m->m_pkthdr.csum_data = 0xffff; + *} + */ + 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); + } + return (0); +} +#else /* * check protocol (tcp/udp/icmp/icmp6) checksum and set mbuf flag * off is the offset where the protocol header starts @@ -5139,8 +5505,7 @@ bad: * returns 0 when the checksum is valid, otherwise returns 1. */ int -pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, - sa_family_t af) +pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t af) { u_int16_t flag_ok, flag_bad; u_int16_t sum; @@ -5220,49 +5585,42 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, m->m_pkthdr.csum |= flag_ok; return (0); } - -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); -} +#endif #ifdef INET int pf_test(int dir, struct ifnet *ifp, struct mbuf **m0) { - struct pfi_kif *kif; - u_short action, reason = 0, log = 0; - struct mbuf *m = *m0; - struct ip *h; - 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; - + u_short action, reason = 0, log = 0; + struct mbuf *m = *m0; + struct ip *h = NULL; /* XXX: was uninitialized */ + struct pf_rule *a = NULL, *r = &pf_default_rule, *tr; + struct pf_state *s = NULL; + struct pf_ruleset *ruleset = NULL; + struct pf_pdesc pd; + int off; + int pqid = 0; + +#ifdef __FreeBSD__ + PF_LOCK(); +#endif if (!pf_status.running || - (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) - return (PF_PASS); - - kif = pfi_index2kif[ifp->if_index]; - if (kif == NULL) - return (PF_DROP); + (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) { +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif + return (PF_PASS); + } +#if defined(__FreeBSD__) && (__FreeBSD_version >= 501000) + M_ASSERTPKTHDR(m); +#else #ifdef DIAGNOSTIC if ((m->m_flags & M_PKTHDR) == 0) panic("non-M_PKTHDR is passed to pf_test"); #endif +#endif - memset(&pd, 0, sizeof(pd)); if (m->m_pkthdr.len < (int)sizeof(*h)) { action = PF_DROP; REASON_SET(&reason, PFRES_SHORT); @@ -5271,7 +5629,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0) } /* We do IP header normalization and packet reassembly here */ - if (pf_normalize_ip(m0, dir, kif, &reason) != PF_PASS) { + if (pf_normalize_ip(m0, dir, ifp, &reason) != PF_PASS) { action = PF_DROP; goto done; } @@ -5286,9 +5644,9 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0) goto done; } + memset(&pd, 0, sizeof(pd)); pd.src = (struct pf_addr *)&h->ip_src; pd.dst = (struct pf_addr *)&h->ip_dst; - PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET); pd.ip_sum = &h->ip_sum; pd.proto = h->ip_p; pd.af = AF_INET; @@ -5297,7 +5655,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0) /* handle fragments that didn't get reassembled by normalization */ if (h->ip_off & htons(IP_MF | IP_OFFMASK)) { - action = pf_test_fragment(&r, dir, kif, m, h, + action = pf_test_fragment(&r, dir, ifp, m, h, &pd, &a, &ruleset); goto done; } @@ -5321,21 +5679,17 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0) pd.p_len = pd.tot_len - off - (th.th_off << 2); if ((th.th_flags & TH_ACK) && pd.p_len == 0) pqid = 1; - action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd); + action = pf_normalize_tcp(dir, ifp, m, 0, off, h, &pd); if (action == PF_DROP) - goto done; - action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd, + break; + action = pf_test_state_tcp(&s, dir, ifp, m, 0, off, h, &pd, &reason); if (action == PF_PASS) { -#if NPFSYNC - pfsync_update_state(s); -#endif r = s->rule.ptr; - a = s->anchor.ptr; log = s->log; } else if (s == NULL) - action = pf_test_tcp(&r, &s, dir, kif, - m, off, h, &pd, &a, &ruleset); + action = pf_test_tcp(&r, &s, dir, ifp, + m, 0, off, h, &pd, &a, &ruleset); break; } @@ -5353,23 +5707,14 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0) action = PF_DROP; 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; - goto done; - } - action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd); + action = pf_test_state_udp(&s, dir, ifp, m, 0, off, h, &pd); if (action == PF_PASS) { -#if NPFSYNC - pfsync_update_state(s); -#endif r = s->rule.ptr; a = s->anchor.ptr; log = s->log; } else if (s == NULL) - action = pf_test_udp(&r, &s, dir, kif, - m, off, h, &pd, &a, &ruleset); + action = pf_test_udp(&r, &s, dir, ifp, + m, 0, off, h, &pd, &a, &ruleset); break; } @@ -5387,36 +5732,55 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0) action = PF_DROP; goto done; } - action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd); + action = pf_test_state_icmp(&s, dir, ifp, m, 0, off, h, &pd); if (action == PF_PASS) { -#if NPFSYNC - pfsync_update_state(s); -#endif r = s->rule.ptr; + r->packets++; + r->bytes += ntohs(h->ip_len); a = s->anchor.ptr; + if (a != NULL) { + a->packets++; + a->bytes += ntohs(h->ip_len); + } log = s->log; } else if (s == NULL) - action = pf_test_icmp(&r, &s, dir, kif, - m, off, h, &pd, &a, &ruleset); + action = pf_test_icmp(&r, &s, dir, ifp, + m, 0, off, h, &pd, &a, &ruleset); break; } default: - action = pf_test_state_other(&s, dir, kif, &pd); + action = pf_test_state_other(&s, dir, ifp, &pd); if (action == PF_PASS) { -#if NPFSYNC - pfsync_update_state(s); -#endif r = s->rule.ptr; a = s->anchor.ptr; log = s->log; } else if (s == NULL) - action = pf_test_other(&r, &s, dir, kif, m, off, h, + action = pf_test_other(&r, &s, dir, ifp, m, off, h, &pd, &a, &ruleset); break; } + if (ifp == status_ifp) { + pf_status.bcounters[0][dir == PF_OUT] += pd.tot_len; + pf_status.pcounters[0][dir == PF_OUT][action != PF_PASS]++; + } + done: + tr = r; + if (r == &pf_default_rule && s != NULL && s->nat_rule.ptr != NULL) + tr = s->nat_rule.ptr; + if (tr->src.addr.type == PF_ADDR_TABLE) + pfr_update_stats(tr->src.addr.p.tbl, + (s == NULL || s->direction == dir) ? pd.src : pd.dst, pd.af, + pd.tot_len, dir == PF_OUT, r->action == PF_PASS, + tr->src.not); + if (tr->dst.addr.type == PF_ADDR_TABLE) + pfr_update_stats(tr->dst.addr.p.tbl, + (s == NULL || s->direction == dir) ? pd.dst : pd.src, pd.af, + pd.tot_len, dir == PF_OUT, r->action == PF_PASS, + tr->dst.not); + if (action == PF_PASS && h->ip_hl > 5 && !((s && s->allow_opts) || r->allow_opts)) { action = PF_DROP; @@ -5446,87 +5810,8 @@ done: } #endif - /* - * connections redirected to loopback should not match sockets - * bound specifically to loopback due to security implications, - * see tcp_input() and in_pcblookup_listen(). - */ - if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP || - 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 && - 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) { - r->packets++; - r->bytes += pd.tot_len; - if (a != NULL) { - 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++; - s->nat_rule.ptr->bytes += pd.tot_len; - } - if (s->src_node != NULL) { - s->src_node->packets++; - s->src_node->bytes += pd.tot_len; - } - if (s->nat_src_node != NULL) { - s->nat_src_node->packets++; - s->nat_src_node->bytes += pd.tot_len; - } - } - tr = r; - nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule; - if (nr != NULL) { - struct pf_addr *x; - /* - * XXX: we need to make sure that the addresses - * passed to pfr_update_stats() are the same than - * the addresses used during matching (pfr_match) - */ - if (r == &pf_default_rule) { - tr = nr; - x = (s == NULL || s->direction == dir) ? - &pd.baddr : &pd.naddr; - } else - x = (s == NULL || s->direction == dir) ? - &pd.naddr : &pd.baddr; - if (x == &pd.baddr || s == NULL) { - /* we need to change the address */ - if (dir == PF_OUT) - pd.src = x; - else - pd.dst = x; - } - } - if (tr->src.addr.type == PF_ADDR_TABLE) - pfr_update_stats(tr->src.addr.p.tbl, (s == NULL || - s->direction == dir) ? pd.src : pd.dst, pd.af, - pd.tot_len, dir == PF_OUT, r->action == PF_PASS, - tr->src.not); - if (tr->dst.addr.type == PF_ADDR_TABLE) - pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL || - s->direction == dir) ? pd.dst : pd.src, pd.af, - pd.tot_len, dir == PF_OUT, r->action == PF_PASS, - tr->dst.not); - } - + PFLOG_PACKET(ifp, h, m, AF_INET, dir, reason, r, a, ruleset); if (action == PF_SYNPROXY_DROP) { m_freem(*m0); @@ -5536,6 +5821,10 @@ done: /* pf_route can free the mbuf causing *m0 to become NULL */ pf_route(m0, r, dir, ifp, s); +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif + return (action); } #endif /* INET */ @@ -5544,30 +5833,36 @@ done: int pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0) { - struct pfi_kif *kif; - u_short action, reason = 0, log = 0; - struct mbuf *m = *m0; - struct ip6_hdr *h; - 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; + u_short action, reason = 0, log = 0; + struct mbuf *m = *m0; + struct ip6_hdr *h = NULL; /* make the compiler happy */ + struct pf_rule *a = NULL, *r = &pf_default_rule, *tr; + struct pf_state *s = NULL; + struct pf_ruleset *ruleset = NULL; + struct pf_pdesc pd; + int off, terminal = 0; + +#ifdef __FreeBSD__ + PF_LOCK(); +#endif if (!pf_status.running || - (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) + (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) { +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif return (PF_PASS); + } - kif = pfi_index2kif[ifp->if_index]; - if (kif == NULL) - return (PF_DROP); - +#if defined(__FreeBSD__) && (__FreeBSD_version >= 501000) + M_ASSERTPKTHDR(m); +#else #ifdef DIAGNOSTIC if ((m->m_flags & M_PKTHDR) == 0) panic("non-M_PKTHDR is passed to pf_test"); #endif +#endif - memset(&pd, 0, sizeof(pd)); if (m->m_pkthdr.len < (int)sizeof(*h)) { action = PF_DROP; REASON_SET(&reason, PFRES_SHORT); @@ -5576,16 +5871,16 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0) } /* We do IP header normalization and packet reassembly here */ - if (pf_normalize_ip6(m0, dir, kif, &reason) != PF_PASS) { + if (pf_normalize_ip6(m0, dir, ifp, &reason) != PF_PASS) { action = PF_DROP; goto done; } m = *m0; h = mtod(m, struct ip6_hdr *); + memset(&pd, 0, sizeof(pd)); pd.src = (struct pf_addr *)&h->ip6_src; pd.dst = (struct pf_addr *)&h->ip6_dst; - PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET6); pd.ip_sum = NULL; pd.af = AF_INET6; pd.tos = 0; @@ -5596,7 +5891,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0) do { switch (pd.proto) { case IPPROTO_FRAGMENT: - action = pf_test_fragment(&r, dir, kif, m, h, + action = pf_test_fragment(&r, dir, ifp, m, h, &pd, &a, &ruleset); if (action == PF_DROP) REASON_SET(&reason, PFRES_FRAG); @@ -5648,21 +5943,17 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0) goto done; } pd.p_len = pd.tot_len - off - (th.th_off << 2); - action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd); + action = pf_normalize_tcp(dir, ifp, m, 0, off, h, &pd); if (action == PF_DROP) - goto done; - action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd, + break; + action = pf_test_state_tcp(&s, dir, ifp, m, 0, off, h, &pd, &reason); if (action == PF_PASS) { -#if NPFSYNC - pfsync_update_state(s); -#endif r = s->rule.ptr; - a = s->anchor.ptr; log = s->log; } else if (s == NULL) - action = pf_test_tcp(&r, &s, dir, kif, - m, off, h, &pd, &a, &ruleset); + action = pf_test_tcp(&r, &s, dir, ifp, + m, 0, off, h, &pd, &a, &ruleset); break; } @@ -5680,23 +5971,13 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0) action = PF_DROP; 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; - goto done; - } - action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd); + action = pf_test_state_udp(&s, dir, ifp, m, 0, off, h, &pd); if (action == PF_PASS) { -#if NPFSYNC - pfsync_update_state(s); -#endif r = s->rule.ptr; - a = s->anchor.ptr; log = s->log; } else if (s == NULL) - action = pf_test_udp(&r, &s, dir, kif, - m, off, h, &pd, &a, &ruleset); + action = pf_test_udp(&r, &s, dir, ifp, + m, 0, off, h, &pd, &a, &ruleset); break; } @@ -5714,34 +5995,45 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0) action = PF_DROP; goto done; } - action = pf_test_state_icmp(&s, dir, kif, - m, off, h, &pd); + action = pf_test_state_icmp(&s, dir, ifp, + m, 0, off, h, &pd); if (action == PF_PASS) { -#if NPFSYNC - pfsync_update_state(s); -#endif r = s->rule.ptr; - a = s->anchor.ptr; + r->packets++; + r->bytes += h->ip6_plen; log = s->log; } else if (s == NULL) - action = pf_test_icmp(&r, &s, dir, kif, - m, off, h, &pd, &a, &ruleset); + action = pf_test_icmp(&r, &s, dir, ifp, + m, 0, off, h, &pd, &a, &ruleset); break; } default: - action = pf_test_state_other(&s, dir, kif, &pd); - if (action == PF_PASS) { - r = s->rule.ptr; - a = s->anchor.ptr; - log = s->log; - } else if (s == NULL) - action = pf_test_other(&r, &s, dir, kif, m, off, h, - &pd, &a, &ruleset); + action = pf_test_other(&r, &s, dir, ifp, m, off, h, + &pd, &a, &ruleset); break; } + if (ifp == status_ifp) { + pf_status.bcounters[1][dir == PF_OUT] += pd.tot_len; + pf_status.pcounters[1][dir == PF_OUT][action != PF_PASS]++; + } + done: + tr = r; + if (r == &pf_default_rule && s != NULL && s->nat_rule.ptr != NULL) + tr = s->nat_rule.ptr; + if (tr->src.addr.type == PF_ADDR_TABLE) + pfr_update_stats(tr->src.addr.p.tbl, + (s == NULL || s->direction == dir) ? pd.src : pd.dst, pd.af, + pd.tot_len, dir == PF_OUT, r->action == PF_PASS, + tr->src.not); + if (tr->dst.addr.type == PF_ADDR_TABLE) + pfr_update_stats(tr->dst.addr.p.tbl, + (s == NULL || s->direction == dir) ? pd.dst : pd.src, pd.af, + pd.tot_len, dir == PF_OUT, r->action == PF_PASS, + tr->dst.not); + /* XXX handle IPv6 options, if not allowed. not implemented. */ #ifdef ALTQ @@ -5764,82 +6056,8 @@ done: } #endif - if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP || - 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) && - 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) { - r->packets++; - r->bytes += pd.tot_len; - if (a != NULL) { - 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++; - s->nat_rule.ptr->bytes += pd.tot_len; - } - if (s->src_node != NULL) { - s->src_node->packets++; - s->src_node->bytes += pd.tot_len; - } - if (s->nat_src_node != NULL) { - s->nat_src_node->packets++; - s->nat_src_node->bytes += pd.tot_len; - } - } - tr = r; - nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule; - if (nr != NULL) { - struct pf_addr *x; - /* - * XXX: we need to make sure that the addresses - * passed to pfr_update_stats() are the same than - * the addresses used during matching (pfr_match) - */ - if (r == &pf_default_rule) { - tr = nr; - x = (s == NULL || s->direction == dir) ? - &pd.baddr : &pd.naddr; - } else { - x = (s == NULL || s->direction == dir) ? - &pd.naddr : &pd.baddr; - } - if (x == &pd.baddr || s == NULL) { - if (dir == PF_OUT) - pd.src = x; - else - pd.dst = x; - } - } - if (tr->src.addr.type == PF_ADDR_TABLE) - pfr_update_stats(tr->src.addr.p.tbl, (s == NULL || - s->direction == dir) ? pd.src : pd.dst, pd.af, - pd.tot_len, dir == PF_OUT, r->action == PF_PASS, - tr->src.not); - if (tr->dst.addr.type == PF_ADDR_TABLE) - pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL || - s->direction == dir) ? pd.dst : pd.src, pd.af, - pd.tot_len, dir == PF_OUT, r->action == PF_PASS, - tr->dst.not); - } - + PFLOG_PACKET(ifp, h, m, AF_INET6, dir, reason, r, a, ruleset); if (action == PF_SYNPROXY_DROP) { m_freem(*m0); @@ -5849,6 +6067,9 @@ done: /* pf_route6 can free the mbuf causing *m0 to become NULL */ pf_route6(m0, r, dir, ifp, s); +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif return (action); } #endif /* INET6 */ diff --git a/sys/contrib/pf/net/pf_ioctl.c b/sys/contrib/pf/net/pf_ioctl.c index dd25ce2..3053de3 100644 --- a/sys/contrib/pf/net/pf_ioctl.c +++ b/sys/contrib/pf/net/pf_ioctl.c @@ -1,8 +1,8 @@ -/* $OpenBSD: pf_ioctl.c,v 1.112 2004/03/22 04:54:18 mcbride Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: pf_ioctl.c,v 1.81.2.2 2004/04/30 23:28:58 brad Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier - * Copyright (c) 2002,2003 Henning Brauer * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,7 +35,10 @@ * */ -#include "pfsync.h" +#ifdef __FreeBSD__ +#include "opt_inet.h" +#include "opt_inet6.h" +#endif #include <sys/param.h> #include <sys/systm.h> @@ -46,9 +49,14 @@ #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> +#else #include <sys/timeout.h> #include <sys/pool.h> -#include <sys/malloc.h> +#endif #include <net/if.h> #include <net/if_types.h> @@ -61,67 +69,305 @@ #include <netinet/ip_var.h> #include <netinet/ip_icmp.h> -#include <dev/rndvar.h> #include <net/pfvar.h> -#if NPFSYNC > 0 -#include <net/if_pfsync.h> -#endif /* NPFSYNC > 0 */ - #ifdef INET6 #include <netinet/ip6.h> #include <netinet/in_pcb.h> +#if defined(__FreeBSD__) && (__FreeBSD_version < 501108) +#include <netinet6/ip6protosw.h> +#endif #endif /* INET6 */ #ifdef ALTQ #include <altq/altq.h> #endif +#ifdef __FreeBSD__ +#if (__FreeBSD_version >= 500112) +#include <sys/limits.h> +#else +#include <machine/limits.h> +#endif +#include <sys/lock.h> +#include <sys/mutex.h> +#if __FreeBSD_version < 501108 +#include <sys/protosw.h> +#endif +#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); -int pfopen(dev_t, int, int, struct proc *); -int pfclose(dev_t, int, int, struct proc *); +int pfopen(struct cdev *, int, int, struct proc *); +int pfclose(struct cdev *, int, int, struct proc *); +#endif struct pf_pool *pf_get_pool(char *, char *, u_int32_t, - u_int8_t, u_int8_t, u_int8_t, u_int8_t, u_int8_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 *); 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 ALTQ -int pf_begin_altq(u_int32_t *); -int pf_rollback_altq(u_int32_t); -int pf_commit_altq(u_int32_t); -#endif /* ALTQ */ -int pf_begin_rules(u_int32_t *, int, char *, char *); -int pf_rollback_rules(u_int32_t, int, char *, char *); -int pf_commit_rules(u_int32_t, int, char *, char *); +#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 __FreeBSD__ +extern struct callout pf_expire_to; +#if __FreeBSD_version < 501108 +extern struct protosw inetsw[]; +#endif +#else extern struct timeout pf_expire_to; +#endif struct pf_rule pf_default_rule; +#ifdef ALTQ +static int pfaltq_running; +#endif #define TAGID_MAX 50000 -TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags), - pf_qids = TAILQ_HEAD_INITIALIZER(pf_qids); +TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags); + +#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x -#if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE) -#error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE + +#ifdef __FreeBSD__ +static struct cdev *pf_dev; + +/* + * XXX - These are new and need to be checked when moveing to a new version + */ +static int pf_beginrules(void *addr); +static int pf_commitrules(void *addr); +#ifdef ALTQ +static int pf_beginaltqs(void *addr); +static int pf_commitaltqs(void *addr); +static int pf_stopaltq(void); +#endif +static void pf_clearstates(void); +static int pf_clear_tables(void *addr); +/* + * XXX - These are new and need to be checked when moveing to a new version + */ + +#if (__FreeBSD_version < 501108) +static int pf_check_in(void *ip, int hlen, struct ifnet *ifp, int dir, + struct mbuf **m); +static int pf_check_out(void *ip, int hlen, struct ifnet *ifp, int dir, + struct mbuf **m); +#ifdef INET6 +static int pf_check6_in(void *ip, int hlen, struct ifnet *ifp, int dir, + struct mbuf **m); +static int pf_check6_out(void *ip, int hlen, struct ifnet *ifp, int dir, + struct mbuf **m); +#endif +#else /* (__FreeBSD_version >= 501108) */ +static int pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, + int dir); +static int pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, + int dir); +#ifdef INET6 +static int pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, + int dir); +static int pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, + int dir); +#endif +#endif /* (__FreeBSD_version >= 501108) */ +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 = { +#if (__FreeBSD_version < 500105) + /* open */ noopen, + /* close */ noclose, + /* read */ noread, + /* write */ nowrite, + /* ioctl */ pfioctl, + /* poll */ nopoll, + /* mmap */ nommap, + /* strategy */ nostrategy, + /* name */ PF_NAME, + /* maj */ PF_CDEV_MAJOR, + /* dump */ nodump, + /* psize */ nopsize, + /* flags */ 0, + /* kqfilter */ nokqfilter, +#elif (__FreeBSD_version < 501110) + .d_open = noopen, + .d_close = noclose, + .d_read = noread, + .d_write = nowrite, + .d_ioctl = pfioctl, + .d_poll = nopoll, + .d_mmap = nommap, + .d_strategy = nostrategy, + .d_name = PF_NAME, + .d_maj = MAJOR_AUTO, /* PF_CDEV_MAJOR */ + .d_dump = nodump, + .d_flags = 0, + .d_kqfilter = nokqfilter, +#else + .d_ioctl = pfioctl, + .d_name = PF_NAME, + .d_version = D_VERSION, #endif -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); +}; -#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x +static volatile int pf_pfil_hooked = 0; +struct mtx pf_task_mtx; + +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_tree_pl = pf_rule_pl = pf_addr_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_tree_pl); + UMA_DESTROY(pf_rule_pl); + UMA_DESTROY(pf_addr_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_pl); + UMA_DESTROY(pf_state_scrub_pl); +} + +int +pfattach(void) +{ + u_int32_t *my_timeout = pf_default_rule.timeout; + int error = 1; + + do { + UMA_CREATE(pf_tree_pl, struct pf_tree_node, "pftrpl"); + UMA_CREATE(pf_rule_pl, struct pf_rule, "pfrulepl"); + UMA_CREATE(pf_addr_pl, struct pf_addr_dyn, "pfaddrpl"); + 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(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"); + error = 0; + } while(0); + if (error) { + cleanup_pf_zone(); + return (error); + } + pfr_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_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_lan_ext); + RB_INIT(&tree_ext_gwy); + TAILQ_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]; + + /* 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] = 120; /* First TCP packet */ + my_timeout[PFTM_TCP_OPENING] = 30; /* No response yet */ + my_timeout[PFTM_TCP_ESTABLISHED] = 24*60*60; /* Established */ + my_timeout[PFTM_TCP_CLOSING] = 15 * 60; /* Half closed */ + my_timeout[PFTM_TCP_FIN_WAIT] = 45; /* Got both FINs */ + my_timeout[PFTM_TCP_CLOSED] = 90; /* Got a RST */ + my_timeout[PFTM_UDP_FIRST_PACKET] = 60; /* First UDP packet */ + my_timeout[PFTM_UDP_SINGLE] = 30; /* Unidirectional */ + my_timeout[PFTM_UDP_MULTIPLE] = 60; /* Bidirectional */ + my_timeout[PFTM_ICMP_FIRST_PACKET] = 20; /* First ICMP packet */ + my_timeout[PFTM_ICMP_ERROR_REPLY] = 10; /* Got error response */ + my_timeout[PFTM_OTHER_FIRST_PACKET] = 60; /* First packet */ + my_timeout[PFTM_OTHER_SINGLE] = 30; /* Unidirectional */ + my_timeout[PFTM_OTHER_MULTIPLE] = 60; /* Bidirectional */ + my_timeout[PFTM_FRAG] = 30; /* Fragment expire */ + my_timeout[PFTM_INTERVAL] = 10; /* Expire interval */ + + /* + * XXX + * The 2nd arg. 0 to callout_init(9) shoule be set to CALLOUT_MPSAFE + * if Gaint lock is removed from the network stack. + */ + callout_init(&pf_expire_to, 0); + callout_reset(&pf_expire_to, my_timeout[PFTM_INTERVAL] * hz, + pf_purge_timeout, &pf_expire_to); + pf_normalize_init(); + pf_status.debug = PF_DEBUG_URGENT; + pf_pfil_hooked = 0; + return (error); +} +#else /* !__FreeBSD__ */ void pfattach(int num) { u_int32_t *timeout = pf_default_rule.timeout; + pool_init(&pf_tree_pl, sizeof(struct pf_tree_node), 0, 0, 0, "pftrpl", + NULL); pool_init(&pf_rule_pl, sizeof(struct pf_rule), 0, 0, 0, "pfrulepl", &pool_allocator_nointr); - pool_init(&pf_src_tree_pl, sizeof(struct pf_src_node), 0, 0, 0, - "pfsrctrpl", NULL); + pool_init(&pf_addr_pl, sizeof(struct pf_addr_dyn), 0, 0, 0, "pfaddrpl", + &pool_allocator_nointr); pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl", NULL); pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl", @@ -129,13 +375,13 @@ pfattach(int num) pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0, "pfpooladdrpl", NULL); pfr_initialize(); - pfi_initialize(); pf_osfp_initialize(); - pool_sethardlimit(pf_pool_limits[PF_LIMIT_STATES].pp, - pf_pool_limits[PF_LIMIT_STATES].limit, NULL, 0); + pool_sethardlimit(&pf_state_pl, pf_pool_limits[PF_LIMIT_STATES].limit, + NULL, 0); - RB_INIT(&tree_src_tracking); + RB_INIT(&tree_lan_ext); + RB_INIT(&tree_ext_gwy); TAILQ_INIT(&pf_anchors); pf_init_ruleset(&pf_main_ruleset); TAILQ_INIT(&pf_altqs[0]); @@ -143,7 +389,6 @@ pfattach(int num) 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; @@ -152,7 +397,7 @@ pfattach(int num) /* initialize default timeouts */ timeout[PFTM_TCP_FIRST_PACKET] = 120; /* First TCP packet */ - timeout[PFTM_TCP_OPENING] = 30; /* No response yet */ + timeout[PFTM_TCP_OPENING] = 30; /* No response yet */ timeout[PFTM_TCP_ESTABLISHED] = 24*60*60; /* Established */ timeout[PFTM_TCP_CLOSING] = 15 * 60; /* Half closed */ timeout[PFTM_TCP_FIN_WAIT] = 45; /* Got both FINs */ @@ -167,21 +412,16 @@ pfattach(int num) timeout[PFTM_OTHER_MULTIPLE] = 60; /* Bidirectional */ timeout[PFTM_FRAG] = 30; /* Fragment expire */ timeout[PFTM_INTERVAL] = 10; /* Expire interval */ - timeout[PFTM_SRC_NODE] = 0; /* Source tracking */ 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)); pf_status.debug = PF_DEBUG_URGENT; - - /* XXX do our best to avoid a conflict */ - pf_status.hostid = arc4random(); } 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); @@ -189,16 +429,17 @@ 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 *anchorname, char *rulesetname, u_int32_t ticket, - u_int8_t rule_action, u_int8_t rule_number, u_int8_t r_last, + u_int8_t rule_action, u_int32_t rule_number, u_int8_t r_last, u_int8_t active, u_int8_t check_ticket) { struct pf_ruleset *ruleset; @@ -323,8 +564,7 @@ pf_find_ruleset(char *anchorname, char *rulesetname) } struct pf_ruleset * -pf_find_or_create_ruleset(char anchorname[PF_ANCHOR_NAME_SIZE], - char rulesetname[PF_RULESET_NAME_SIZE]) +pf_find_or_create_ruleset(char *anchorname, char *rulesetname) { struct pf_anchor *anchor, *a; struct pf_ruleset *ruleset, *r; @@ -383,8 +623,7 @@ pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset) 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) + !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr)) return; anchor = ruleset->anchor; @@ -415,9 +654,8 @@ pf_empty_pool(struct pf_palist *poola) struct pf_pooladdr *empty_pool_pa; while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) { - pfi_dynaddr_remove(&empty_pool_pa->addr); + pf_dynaddr_remove(&empty_pool_pa->addr); pf_tbladdr_remove(&empty_pool_pa->addr); - pfi_detach_rule(empty_pool_pa->kif); TAILQ_REMOVE(poola, empty_pool_pa, entries); pool_put(&pf_pooladdr_pl, empty_pool_pa); } @@ -440,35 +678,27 @@ pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule) rule->entries.tqe_prev = NULL; rule->nr = -1; } - - if (rule->states > 0 || rule->src_nodes > 0 || - rule->entries.tqe_prev != NULL) + if (rule->states > 0 || rule->entries.tqe_prev != NULL) return; pf_tag_unref(rule->tag); pf_tag_unref(rule->match_tag); -#ifdef ALTQ - if (rule->pqid != rule->qid) - pf_qid_unref(rule->pqid); - pf_qid_unref(rule->qid); -#endif - pfi_dynaddr_remove(&rule->src.addr); - pfi_dynaddr_remove(&rule->dst.addr); + pf_dynaddr_remove(&rule->src.addr); + pf_dynaddr_remove(&rule->dst.addr); if (rulequeue == NULL) { pf_tbladdr_remove(&rule->src.addr); pf_tbladdr_remove(&rule->dst.addr); } - pfi_detach_rule(rule->kif); pf_empty_pool(&rule->rpool.list); pool_put(&pf_rule_pl, rule); } -static u_int16_t -tagname2tag(struct pf_tags *head, char *tagname) +u_int16_t +pf_tagname2tag(char *tagname) { struct pf_tagname *tag, *p = NULL; u_int16_t new_tagid = 1; - TAILQ_FOREACH(tag, head, entries) + TAILQ_FOREACH(tag, &pf_tags, entries) if (strcmp(tagname, tag->name) == 0) { tag->ref++; return (tag->tag); @@ -481,8 +711,8 @@ tagname2tag(struct pf_tags *head, char *tagname) */ /* new entry */ - if (!TAILQ_EMPTY(head)) - for (p = TAILQ_FIRST(head); p != NULL && + if (!TAILQ_EMPTY(&pf_tags)) + for (p = TAILQ_FIRST(&pf_tags); p != NULL && p->tag == new_tagid; p = TAILQ_NEXT(p, entries)) new_tagid = p->tag + 1; @@ -502,36 +732,36 @@ tagname2tag(struct pf_tags *head, char *tagname) if (p != NULL) /* insert new entry before p */ TAILQ_INSERT_BEFORE(p, tag, entries); else /* either list empty or no free slot in between */ - TAILQ_INSERT_TAIL(head, tag, entries); + TAILQ_INSERT_TAIL(&pf_tags, tag, entries); return (tag->tag); } -static void -tag2tagname(struct pf_tags *head, u_int16_t tagid, char *p) +void +pf_tag2tagname(u_int16_t tagid, char *p) { struct pf_tagname *tag; - TAILQ_FOREACH(tag, head, entries) + TAILQ_FOREACH(tag, &pf_tags, entries) if (tag->tag == tagid) { strlcpy(p, tag->name, PF_TAG_NAME_SIZE); return; } } -static void -tag_unref(struct pf_tags *head, u_int16_t tag) +void +pf_tag_unref(u_int16_t tag) { struct pf_tagname *p, *next; if (tag == 0) return; - for (p = TAILQ_FIRST(head); p != NULL; p = next) { + for (p = TAILQ_FIRST(&pf_tags); p != NULL; p = next) { next = TAILQ_NEXT(p, entries); if (tag == p->tag) { if (--p->ref == 0) { - TAILQ_REMOVE(head, p, entries); + TAILQ_REMOVE(&pf_tags, p, entries); free(p, M_TEMP); } break; @@ -539,212 +769,13 @@ tag_unref(struct pf_tags *head, u_int16_t tag) } } -u_int16_t -pf_tagname2tag(char *tagname) -{ - return (tagname2tag(&pf_tags, tagname)); -} - -void -pf_tag2tagname(u_int16_t tagid, char *p) -{ - return (tag2tagname(&pf_tags, tagid, p)); -} - -void -pf_tag_unref(u_int16_t tag) -{ - return (tag_unref(&pf_tags, tag)); -} - -#ifdef ALTQ -u_int32_t -pf_qname2qid(char *qname) -{ - return ((u_int32_t)tagname2tag(&pf_qids, qname)); -} - -void -pf_qid2qname(u_int32_t qid, char *p) -{ - return (tag2tagname(&pf_qids, (u_int16_t)qid, p)); -} - -void -pf_qid_unref(u_int32_t qid) -{ - return (tag_unref(&pf_qids, (u_int16_t)qid)); -} - -int -pf_begin_altq(u_int32_t *ticket) -{ - struct pf_altq *altq; - int error = 0; - - /* Purge the old altq list */ - while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { - TAILQ_REMOVE(pf_altqs_inactive, altq, entries); - if (altq->qname[0] == 0) { - /* detach and destroy the discipline */ - error = altq_remove(altq); - } else - pf_qid_unref(altq->qid); - pool_put(&pf_altq_pl, altq); - } - if (error) - return (error); - *ticket = ++ticket_altqs_inactive; - altqs_inactive_open = 1; - return (0); -} - -int -pf_rollback_altq(u_int32_t ticket) -{ - struct pf_altq *altq; - int error = 0; - - if (!altqs_inactive_open || ticket != ticket_altqs_inactive) - return (0); - /* Purge the old altq list */ - while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { - TAILQ_REMOVE(pf_altqs_inactive, altq, entries); - if (altq->qname[0] == 0) { - /* detach and destroy the discipline */ - error = altq_remove(altq); - } else - pf_qid_unref(altq->qid); - pool_put(&pf_altq_pl, altq); - } - altqs_inactive_open = 0; - return (error); -} - -int -pf_commit_altq(u_int32_t ticket) -{ - struct pf_altqqueue *old_altqs; - struct pf_altq *altq; - int s, err, error = 0; - - if (!altqs_inactive_open || ticket != ticket_altqs_inactive) - return (EBUSY); - - /* swap altqs, keep the old. */ - s = splsoftnet(); - old_altqs = pf_altqs_active; - pf_altqs_active = pf_altqs_inactive; - pf_altqs_inactive = old_altqs; - ticket_altqs_active = ticket_altqs_inactive; - - /* Attach new disciplines */ - TAILQ_FOREACH(altq, pf_altqs_active, entries) { - if (altq->qname[0] == 0) { - /* attach the discipline */ - error = altq_pfattach(altq); - if (error) { - splx(s); - return (error); - } - } - } - - /* Purge the old altq list */ - while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { - TAILQ_REMOVE(pf_altqs_inactive, altq, entries); - if (altq->qname[0] == 0) { - /* detach and destroy the discipline */ - err = altq_pfdetach(altq); - if (err != 0 && error == 0) - error = err; - err = altq_remove(altq); - if (err != 0 && error == 0) - error = err; - } else - pf_qid_unref(altq->qid); - pool_put(&pf_altq_pl, altq); - } - splx(s); - - altqs_inactive_open = 0; - return (error); -} -#endif /* ALTQ */ - -int -pf_begin_rules(u_int32_t *ticket, int rs_num, char *anchor, char *ruleset) -{ - struct pf_ruleset *rs; - struct pf_rule *rule; - - if (rs_num < 0 || rs_num >= PF_RULESET_MAX) - return (EINVAL); - rs = pf_find_or_create_ruleset(anchor, ruleset); - if (rs == NULL) - return (EINVAL); - while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) - pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule); - *ticket = ++rs->rules[rs_num].inactive.ticket; - rs->rules[rs_num].inactive.open = 1; - return (0); -} - -int -pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor, char *ruleset) -{ - struct pf_ruleset *rs; - struct pf_rule *rule; - - if (rs_num < 0 || rs_num >= PF_RULESET_MAX) - return (EINVAL); - rs = pf_find_ruleset(anchor, ruleset); - 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) - pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule); - rs->rules[rs_num].inactive.open = 0; - return (0); -} - +#ifdef __FreeBSD__ int -pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor, char *ruleset) -{ - struct pf_ruleset *rs; - struct pf_rule *rule; - struct pf_rulequeue *old_rules; - int s; - - if (rs_num < 0 || rs_num >= PF_RULESET_MAX) - return (EINVAL); - rs = pf_find_ruleset(anchor, ruleset); - if (rs == NULL || !rs->rules[rs_num].inactive.open || - ticket != rs->rules[rs_num].inactive.ticket) - return (EBUSY); - - /* Swap rules, keep the old. */ - s = splsoftnet(); - old_rules = rs->rules[rs_num].active.ptr; - rs->rules[rs_num].active.ptr = - rs->rules[rs_num].inactive.ptr; - rs->rules[rs_num].inactive.ptr = old_rules; - 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); - rs->rules[rs_num].inactive.open = 0; - pf_remove_if_empty_ruleset(rs); - pf_update_anchor_rules(); - splx(s); - 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; @@ -787,19 +818,10 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCRCLRASTATS: case DIOCRTSTADDRS: case DIOCOSFPGET: - case DIOCGETSRCNODES: - case DIOCCLRSRCNODES: - case DIOCIGETIFACES: - case DIOCICLRISTATS: - break; - case DIOCRCLRTABLES: - case DIOCRADDTABLES: - case DIOCRDELTABLES: - case DIOCRSETTFLAGS: - if (((struct pfioc_table *)addr)->pfrio_flags & - PFR_FLAG_DUMMY) - break; /* dummy operation ok */ - return (EPERM); +#ifdef __FreeBSD__ + case DIOCGIFSPEED: +#endif + break; default: return (EPERM); } @@ -828,38 +850,51 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCRGETASTATS: case DIOCRTSTADDRS: case DIOCOSFPGET: - case DIOCGETSRCNODES: - case DIOCIGETIFACES: +#ifdef __FreeBSD__ + case DIOCGIFSPEED: +#endif break; - case DIOCRCLRTABLES: - case DIOCRADDTABLES: - case DIOCRDELTABLES: - case DIOCRCLRTSTATS: - case DIOCRCLRADDRS: - case DIOCRADDADDRS: - case DIOCRDELADDRS: - case DIOCRSETADDRS: - case DIOCRSETTFLAGS: - if (((struct pfioc_table *)addr)->pfrio_flags & - PFR_FLAG_DUMMY) - break; /* dummy operation ok */ - return (EACCES); default: return (EACCES); } +#ifdef __FreeBSD__ + PF_LOCK(); +#endif + switch (cmd) { case DIOCSTART: if (pf_status.running) error = EEXIST; else { + u_int32_t states = pf_status.states; +#ifdef __FreeBSD__ + PF_UNLOCK(); + error = hook_pf(); + PF_LOCK(); + if (error) { + DPFPRINTF(PF_DEBUG_MISC, + ("pf: pfil registeration fail\n")); + break; + } +#endif + bzero(&pf_status, sizeof(struct pf_status)); pf_status.running = 1; + pf_status.states = states; +#ifdef __FreeBSD__ + pf_status.since = time_second; +#else pf_status.since = time.tv_sec; - if (pf_status.stateid == 0) { - pf_status.stateid = time.tv_sec; - pf_status.stateid = pf_status.stateid << 32; - } +#endif + if (status_ifp != NULL) +#if defined(__FreeBSD__) && (__FreeBSD_version < 501113) + snprintf(pf_status.ifname, IFNAMSIZ, "%s%d", + status_ifp->if_name, status_ifp->if_unit); +#else + strlcpy(pf_status.ifname, + status_ifp->if_xname, IFNAMSIZ); +#endif DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n")); } break; @@ -869,16 +904,40 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = ENOENT; else { pf_status.running = 0; - pf_status.since = time.tv_sec; +#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 DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n")); } break; case DIOCBEGINRULES: { struct pfioc_rule *pr = (struct pfioc_rule *)addr; + struct pf_ruleset *ruleset; + struct pf_rule *rule; + int rs_num; - error = pf_begin_rules(&pr->ticket, pf_get_ruleset_number( - pr->rule.action), pr->anchor, pr->ruleset); + ruleset = pf_find_or_create_ruleset(pr->anchor, pr->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } + rs_num = pf_get_ruleset_number(pr->rule.action); + if (rs_num >= PF_RULESET_MAX) { + error = EINVAL; + break; + } + while ((rule = + TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr)) != NULL) + pf_rm_rule(ruleset->rules[rs_num].inactive.ptr, rule); + pr->ticket = ++ruleset->rules[rs_num].inactive.ticket; break; } @@ -922,11 +981,10 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } bcopy(&pr->rule, rule, sizeof(struct pf_rule)); rule->anchor = NULL; - rule->kif = NULL; + rule->ifp = NULL; TAILQ_INIT(&rule->rpool.list); /* initialize refcounting */ rule->states = 0; - rule->src_nodes = 0; rule->entries.tqe_prev = NULL; #ifndef INET if (rule->af == AF_INET) { @@ -949,27 +1007,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_attach_rule(rule->ifname); - if (rule->kif == NULL) { + rule->ifp = ifunit(rule->ifname); + if (rule->ifp == NULL) { pool_put(&pf_rule_pl, rule); error = EINVAL; break; } } -#ifdef ALTQ - /* set queue IDs */ - if (rule->qname[0] != 0) { - if ((rule->qid = pf_qname2qid(rule->qname)) == 0) - error = EBUSY; - else if (rule->pqname[0] != 0) { - if ((rule->pqid = - pf_qname2qid(rule->pqname)) == 0) - error = EBUSY; - } else - rule->pqid = rule->qid; - } -#endif if (rule->tagname[0]) if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0) error = EBUSY; @@ -979,9 +1024,9 @@ 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 (pfi_dynaddr_setup(&rule->src.addr, rule->af)) + if (pf_dynaddr_setup(&rule->src.addr, rule->af)) error = EINVAL; - if (pfi_dynaddr_setup(&rule->dst.addr, rule->af)) + if (pf_dynaddr_setup(&rule->dst.addr, rule->af)) error = EINVAL; if (pf_tbladdr_setup(ruleset, &rule->src.addr)) error = EINVAL; @@ -1011,9 +1056,48 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCCOMMITRULES: { struct pfioc_rule *pr = (struct pfioc_rule *)addr; + struct pf_ruleset *ruleset; + struct pf_rulequeue *old_rules; + struct pf_rule *rule; + int rs_num; + + ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } + rs_num = pf_get_ruleset_number(pr->rule.action); + if (rs_num >= PF_RULESET_MAX) { + error = EINVAL; + break; + } + if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) { + error = EBUSY; + break; + } + +#ifdef ALTQ + /* set queue IDs */ + if (rs_num == PF_RULESET_FILTER) + pf_rule_set_qid(ruleset->rules[rs_num].inactive.ptr); +#endif + + /* Swap rules, keep the old. */ + s = splsoftnet(); + old_rules = ruleset->rules[rs_num].active.ptr; + ruleset->rules[rs_num].active.ptr = + ruleset->rules[rs_num].inactive.ptr; + ruleset->rules[rs_num].inactive.ptr = old_rules; + ruleset->rules[rs_num].active.ticket = + ruleset->rules[rs_num].inactive.ticket; + pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr); - error = pf_commit_rules(pr->ticket, pf_get_ruleset_number( - pr->rule.action), pr->anchor, pr->ruleset); + /* Purge the old rule list. */ + while ((rule = TAILQ_FIRST(old_rules)) != NULL) + pf_rm_rule(old_rules, rule); + pf_remove_if_empty_ruleset(ruleset); + pf_update_anchor_rules(); + splx(s); break; } @@ -1075,8 +1159,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } bcopy(rule, &pr->rule, sizeof(struct pf_rule)); - pfi_dynaddr_copyout(&pr->rule.src.addr); - pfi_dynaddr_copyout(&pr->rule.dst.addr); + pf_dynaddr_copyout(&pr->rule.src.addr); + pf_dynaddr_copyout(&pr->rule.dst.addr); pf_tbladdr_copyout(&pr->rule.src.addr); pf_tbladdr_copyout(&pr->rule.dst.addr); for (i = 0; i < PF_SKIP_COUNT; ++i) @@ -1160,26 +1244,23 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } #endif /* INET6 */ if (newrule->ifname[0]) { - newrule->kif = pfi_attach_rule(newrule->ifname); - if (newrule->kif == NULL) { + newrule->ifp = ifunit(newrule->ifname); + if (newrule->ifp == NULL) { pool_put(&pf_rule_pl, newrule); error = EINVAL; break; } } else - newrule->kif = NULL; + newrule->ifp = NULL; #ifdef ALTQ /* set queue IDs */ if (newrule->qname[0] != 0) { - if ((newrule->qid = - pf_qname2qid(newrule->qname)) == 0) - error = EBUSY; - else if (newrule->pqname[0] != 0) { - if ((newrule->pqid = - pf_qname2qid(newrule->pqname)) == 0) - error = EBUSY; - } else + newrule->qid = pf_qname_to_qid(newrule->qname); + if (newrule->pqname[0] != 0) + newrule->pqid = + pf_qname_to_qid(newrule->pqname); + else newrule->pqid = newrule->qid; } #endif @@ -1194,9 +1275,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (newrule->rt && !newrule->direction) error = EINVAL; - if (pfi_dynaddr_setup(&newrule->src.addr, newrule->af)) + if (pf_dynaddr_setup(&newrule->src.addr, newrule->af)) error = EINVAL; - if (pfi_dynaddr_setup(&newrule->dst.addr, newrule->af)) + if (pf_dynaddr_setup(&newrule->dst.addr, newrule->af)) error = EINVAL; if (pf_tbladdr_setup(ruleset, &newrule->src.addr)) error = EINVAL; @@ -1274,61 +1355,45 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } case DIOCCLRSTATES: { - struct pf_state *state; - struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; - int killed = 0; + struct pf_tree_node *n; s = splsoftnet(); - 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 - killed++; - } - } + RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) + n->state->timeout = PFTM_PURGE; pf_purge_expired_states(); pf_status.states = 0; - psk->psk_af = killed; -#if NPFSYNC - pfsync_clear_states(pf_status.hostid, psk->psk_ifname); -#endif splx(s); break; } case DIOCKILLSTATES: { - struct pf_state *state; + struct pf_tree_node *n; + struct pf_state *st; struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; int killed = 0; s = splsoftnet(); - 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) && + RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) { + st = n->state; + if ((!psk->psk_af || st->af == psk->psk_af) && + (!psk->psk_proto || psk->psk_proto == st->proto) && PF_MATCHA(psk->psk_src.not, &psk->psk_src.addr.v.a.addr, - &psk->psk_src.addr.v.a.mask, - &state->lan.addr, state->af) && + &psk->psk_src.addr.v.a.mask, &st->lan.addr, + st->af) && PF_MATCHA(psk->psk_dst.not, &psk->psk_dst.addr.v.a.addr, - &psk->psk_dst.addr.v.a.mask, - &state->ext.addr, state->af) && + &psk->psk_dst.addr.v.a.mask, &st->ext.addr, + st->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], - state->lan.port)) && + st->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], - state->ext.port)) && - (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname, - state->u.s.kif->pfik_name))) { - state->timeout = PFTM_PURGE; + st->ext.port))) { + st->timeout = PFTM_PURGE; killed++; } } @@ -1341,7 +1406,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCADDSTATE: { struct pfioc_state *ps = (struct pfioc_state *)addr; struct pf_state *state; - struct pfi_kif *kif; if (ps->state.timeout >= PFTM_MAX && ps->state.timeout != PFTM_UNTIL_PACKET) { @@ -1354,26 +1418,19 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } s = splsoftnet(); - kif = pfi_lookup_create(ps->state.u.ifname); - if (kif == NULL) { - pool_put(&pf_state_pl, state); - error = ENOENT; - splx(s); - break; - } bcopy(&ps->state, state, sizeof(struct pf_state)); - bzero(&state->u, sizeof(state->u)); - state->rule.ptr = &pf_default_rule; + state->rule.ptr = NULL; state->nat_rule.ptr = NULL; state->anchor.ptr = NULL; - state->rt_kif = NULL; + state->rt_ifp = NULL; +#ifdef __FreeBSD__ + state->creation = time_second; +#else state->creation = time.tv_sec; - state->pfsync_time = 0; +#endif state->packets[0] = state->packets[1] = 0; state->bytes[0] = state->bytes[1] = 0; - - if (pf_insert_state(kif, state)) { - pfi_maybe_destroy(kif); + if (pf_insert_state(state)) { pool_put(&pf_state_pl, state); error = ENOMEM; } @@ -1383,31 +1440,36 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCGETSTATE: { struct pfioc_state *ps = (struct pfioc_state *)addr; - struct pf_state *state; + struct pf_tree_node *n; u_int32_t nr; nr = 0; s = splsoftnet(); - RB_FOREACH(state, pf_state_tree_id, &tree_id) { + RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) { if (nr >= ps->nr) break; nr++; } - if (state == NULL) { + if (n == NULL) { error = EBUSY; splx(s); break; } - 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; + bcopy(n->state, &ps->state, sizeof(struct pf_state)); + ps->state.rule.nr = n->state->rule.ptr->nr; + ps->state.nat_rule.nr = (n->state->nat_rule.ptr == NULL) ? + -1 : n->state->nat_rule.ptr->nr; + ps->state.anchor.nr = (n->state->anchor.ptr == NULL) ? + -1 : n->state->anchor.ptr->nr; splx(s); - ps->state.expire = pf_state_expires(state); + ps->state.expire = pf_state_expires(n->state); +#ifdef __FreeBSD__ + if (ps->state.expire > time_second) + ps->state.expire -= time_second; +#else if (ps->state.expire > time.tv_sec) ps->state.expire -= time.tv_sec; +#endif else ps->state.expire = 0; break; @@ -1415,53 +1477,59 @@ 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_tree_node *n; struct pf_state *p, pstore; - struct pfi_kif *kif; u_int32_t nr = 0; int space = ps->ps_len; if (space == 0) { s = splsoftnet(); - TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) - nr += kif->pfik_states; + RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) + nr++; splx(s); ps->ps_len = sizeof(struct pf_state) * nr; +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif return (0); } s = splsoftnet(); p = ps->ps_states; - TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) - RB_FOREACH(state, pf_state_tree_ext_gwy, - &kif->pfik_ext_gwy) { - int secs = time.tv_sec; + RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) { +#ifdef __FreeBSD__ + int secs = time_second; +#else + int secs = time.tv_sec; +#endif - if ((nr+1) * sizeof(*p) > (unsigned)ps->ps_len) - break; + if ((nr + 1) * sizeof(*p) > (unsigned)ps->ps_len) + break; - 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 == - NULL) ? -1 : state->anchor.ptr->nr; - 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) { - splx(s); - goto fail; - } - p++; - nr++; + bcopy(n->state, &pstore, sizeof(pstore)); + pstore.rule.nr = n->state->rule.ptr->nr; + pstore.nat_rule.nr = (n->state->nat_rule.ptr == NULL) ? + -1 : n->state->nat_rule.ptr->nr; + pstore.anchor.nr = (n->state->anchor.ptr == NULL) ? + -1 : n->state->anchor.ptr->nr; + pstore.creation = secs - pstore.creation; + pstore.expire = pf_state_expires(n->state); + if (pstore.expire > secs) + pstore.expire -= secs; + else + pstore.expire = 0; +#ifdef __FreeBSD__ + PF_COPYOUT(&pstore, p, sizeof(*p), error); +#else + error = copyout(&pstore, p, sizeof(*p)); +#endif + if (error) { + splx(s); + goto fail; } + p++; + nr++; + } ps->ps_len = sizeof(struct pf_state) * nr; splx(s); break; @@ -1470,44 +1538,68 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCGETSTATUS: { struct pf_status *s = (struct pf_status *)addr; bcopy(&pf_status, s, sizeof(struct pf_status)); - pfi_fill_oldstatus(s); break; } case DIOCSETSTATUSIF: { struct pfioc_if *pi = (struct pfioc_if *)addr; + struct ifnet *ifp; if (pi->ifname[0] == 0) { + status_ifp = NULL; bzero(pf_status.ifname, IFNAMSIZ); break; } - if (ifunit(pi->ifname) == NULL) { + if ((ifp = ifunit(pi->ifname)) == NULL) { error = EINVAL; break; - } - strlcpy(pf_status.ifname, pi->ifname, IFNAMSIZ); - break; + } else if (ifp == status_ifp) + break; + status_ifp = ifp; + /* fallthrough into DIOCCLRSTATUS */ } case DIOCCLRSTATUS: { - bzero(pf_status.counters, sizeof(pf_status.counters)); - bzero(pf_status.fcounters, sizeof(pf_status.fcounters)); - bzero(pf_status.scounters, sizeof(pf_status.scounters)); - if (*pf_status.ifname) - pfi_clr_istats(pf_status.ifname, NULL, - PFI_FLAG_INSTANCE); + u_int32_t running = pf_status.running; + u_int32_t states = pf_status.states; + u_int32_t since = pf_status.since; + u_int32_t debug = pf_status.debug; + + bzero(&pf_status, sizeof(struct pf_status)); + pf_status.running = running; + pf_status.states = states; + pf_status.since = since; + pf_status.debug = debug; + if (status_ifp != NULL) +#if defined(__FreeBSD__) && (__FreeBSD_version < 501113) + snprintf(pf_status.ifname, IFNAMSIZ, "%s%d", + status_ifp->if_name, status_ifp->if_unit); +#else + strlcpy(pf_status.ifname, + status_ifp->if_xname, IFNAMSIZ); +#endif break; } case DIOCNATLOOK: { struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr; - struct pf_state *state; - struct pf_state key; - int m = 0, direction = pnl->direction; + struct pf_state *st; + struct pf_tree_node key; + int direction = pnl->direction; key.af = pnl->af; key.proto = pnl->proto; + /* + * userland gives us source and dest of connection, reverse + * the lookup so we ask for what happens with the return + * traffic, enabling us to find it in the state tree. + */ + PF_ACPY(&key.addr[1], &pnl->saddr, pnl->af); + key.port[1] = pnl->sport; + PF_ACPY(&key.addr[0], &pnl->daddr, pnl->af); + key.port[0] = pnl->dport; + if (!pnl->proto || PF_AZERO(&pnl->saddr, pnl->af) || PF_AZERO(&pnl->daddr, pnl->af) || @@ -1515,40 +1607,22 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; else { s = splsoftnet(); - - /* - * userland gives us source and dest of connection, - * reverse the lookup so we ask for what happens with - * the return traffic, enabling us to find it in the - * state tree. - */ - if (direction == PF_IN) { - PF_ACPY(&key.ext.addr, &pnl->daddr, pnl->af); - key.ext.port = pnl->dport; - PF_ACPY(&key.gwy.addr, &pnl->saddr, pnl->af); - key.gwy.port = pnl->sport; - state = pf_find_state_all(&key, PF_EXT_GWY, &m); - } else { - PF_ACPY(&key.lan.addr, &pnl->daddr, pnl->af); - key.lan.port = pnl->dport; - PF_ACPY(&key.ext.addr, &pnl->saddr, pnl->af); - key.ext.port = pnl->sport; - state = pf_find_state_all(&key, PF_LAN_EXT, &m); - } - if (m > 1) - error = E2BIG; /* more than one state */ - else if (state != NULL) { + if (direction == PF_IN) + st = pf_find_state(&tree_ext_gwy, &key); + else + st = pf_find_state(&tree_lan_ext, &key); + if (st != NULL) { if (direction == PF_IN) { - PF_ACPY(&pnl->rsaddr, &state->lan.addr, - state->af); - pnl->rsport = state->lan.port; + PF_ACPY(&pnl->rsaddr, &st->lan.addr, + st->af); + pnl->rsport = st->lan.port; PF_ACPY(&pnl->rdaddr, &pnl->daddr, pnl->af); pnl->rdport = pnl->dport; } else { - PF_ACPY(&pnl->rdaddr, &state->gwy.addr, - state->af); - pnl->rdport = state->gwy.port; + PF_ACPY(&pnl->rdaddr, &st->gwy.addr, + st->af); + pnl->rdport = st->gwy.port; PF_ACPY(&pnl->rsaddr, &pnl->saddr, pnl->af); pnl->rsport = pnl->sport; @@ -1601,16 +1675,19 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) struct pfioc_limit *pl = (struct pfioc_limit *)addr; int old_limit; - if (pl->index < 0 || pl->index >= PF_LIMIT_MAX || - pf_pool_limits[pl->index].pp == NULL) { + if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) { 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; @@ -1637,6 +1714,26 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) 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 ) + psp->baudrate = ifp->if_baudrate; + else + error = EINVAL; + } else + error = EINVAL; + break; + } +#endif /* __FreeBSD__ */ + #ifdef ALTQ case DIOCSTARTALTQ: { struct pf_altq *altq; @@ -1705,8 +1802,24 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCBEGINALTQS: { u_int32_t *ticket = (u_int32_t *)addr; + struct pf_altq *altq; - error = pf_begin_altq(ticket); + /* Purge the old altq list */ + while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { + TAILQ_REMOVE(pf_altqs_inactive, altq, entries); + if (altq->qname[0] == 0) { + /* detach and destroy the discipline */ +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif + error = altq_remove(altq); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif + } + pool_put(&pf_altq_pl, altq); + } + *ticket = ++ticket_altqs_inactive; break; } @@ -1730,11 +1843,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) * copy the necessary fields */ if (altq->qname[0] != 0) { - if ((altq->qid = pf_qname2qid(altq->qname)) == 0) { - error = EBUSY; - pool_put(&pf_altq_pl, altq); - break; - } TAILQ_FOREACH(a, pf_altqs_inactive, entries) { if (strncmp(a->ifname, altq->ifname, IFNAMSIZ) == 0 && a->qname[0] == 0) { @@ -1744,7 +1852,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; @@ -1756,9 +1870,75 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } case DIOCCOMMITALTQS: { - u_int32_t ticket = *(u_int32_t *)addr; + u_int32_t *ticket = (u_int32_t *)addr; + struct pf_altqqueue *old_altqs; + struct pf_altq *altq; + struct pf_anchor *anchor; + struct pf_ruleset *ruleset; + int err; - error = pf_commit_altq(ticket); + if (*ticket != ticket_altqs_inactive) { + error = EBUSY; + break; + } + + /* Swap altqs, keep the old. */ + s = splsoftnet(); + old_altqs = pf_altqs_active; + pf_altqs_active = pf_altqs_inactive; + pf_altqs_inactive = old_altqs; + ticket_altqs_active = ticket_altqs_inactive; + + /* Attach new disciplines */ + TAILQ_FOREACH(altq, pf_altqs_active, entries) { + if (altq->qname[0] == 0) { + /* attach the discipline */ +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif + error = altq_pfattach(altq); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif + if (error) { + splx(s); + goto fail; + } + } + } + + /* Purge the old altq list */ + while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { + TAILQ_REMOVE(pf_altqs_inactive, altq, entries); + if (altq->qname[0] == 0) { + /* detach and destroy the discipline */ +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif + err = altq_pfdetach(altq); + if (err != 0 && error == 0) + error = err; + err = altq_remove(altq); + if (err != 0 && error == 0) + error = err; +#ifdef __FreeBSD__ + PF_LOCK(); +#endif + } + pool_put(&pf_altq_pl, altq); + } + splx(s); + + /* update queue IDs */ + pf_rule_set_qid( + pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); + TAILQ_FOREACH(anchor, &pf_anchors, entries) { + TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) { + pf_rule_set_qid( + ruleset->rules[PF_RULESET_FILTER].active.ptr + ); + } + } break; } @@ -1829,7 +2009,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) splx(s); break; } +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif error = altq_getqstats(altq, pq->buf, &nbytes); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif splx(s); if (error == 0) { pq->scheduler = altq->scheduler; @@ -1875,16 +2061,15 @@ 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_attach_rule(pa->ifname); - if (pa->kif == NULL) { + pa->ifp = ifunit(pa->ifname); + if (pa->ifp == NULL) { pool_put(&pf_pooladdr_pl, pa); error = EINVAL; break; } } - if (pfi_dynaddr_setup(&pa->addr, pp->af)) { - pfi_dynaddr_remove(&pa->addr); - pfi_detach_rule(pa->kif); + if (pf_dynaddr_setup(&pa->addr, pp->af)) { + pf_dynaddr_remove(&pa->addr); pool_put(&pf_pooladdr_pl, pa); error = EINVAL; break; @@ -1934,7 +2119,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr)); - pfi_dynaddr_copyout(&pp->addr.addr); + pf_dynaddr_copyout(&pp->addr.addr); pf_tbladdr_copyout(&pp->addr.addr); splx(s); break; @@ -1990,18 +2175,17 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } #endif /* INET6 */ if (newpa->ifname[0]) { - newpa->kif = pfi_attach_rule(newpa->ifname); - if (newpa->kif == NULL) { + newpa->ifp = ifunit(newpa->ifname); + if (newpa->ifp == NULL) { pool_put(&pf_pooladdr_pl, newpa); error = EINVAL; break; } } else - newpa->kif = NULL; - if (pfi_dynaddr_setup(&newpa->addr, pca->af) || + newpa->ifp = NULL; + if (pf_dynaddr_setup(&newpa->addr, pca->af) || pf_tbladdr_setup(ruleset, &newpa->addr)) { - pfi_dynaddr_remove(&newpa->addr); - pfi_detach_rule(newpa->kif); + pf_dynaddr_remove(&newpa->addr); pool_put(&pf_pooladdr_pl, newpa); error = EINVAL; break; @@ -2031,9 +2215,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (pca->action == PF_CHANGE_REMOVE) { TAILQ_REMOVE(&pool->list, oldpa, entries); - pfi_dynaddr_remove(&oldpa->addr); + pf_dynaddr_remove(&oldpa->addr); pf_tbladdr_remove(&oldpa->addr); - pfi_detach_rule(oldpa->kif); pool_put(&pf_pooladdr_pl, oldpa); } else { if (oldpa == NULL) @@ -2126,7 +2309,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel, - io->pfrio_flags | PFR_FLAG_USERIOCTL); + io->pfrio_flags); break; } @@ -2138,7 +2321,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } error = pfr_add_tables(io->pfrio_buffer, io->pfrio_size, - &io->pfrio_nadd, io->pfrio_flags | PFR_FLAG_USERIOCTL); + &io->pfrio_nadd, io->pfrio_flags); break; } @@ -2150,7 +2333,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } error = pfr_del_tables(io->pfrio_buffer, io->pfrio_size, - &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL); + &io->pfrio_ndel, io->pfrio_flags); break; } @@ -2162,7 +2345,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } error = pfr_get_tables(&io->pfrio_table, io->pfrio_buffer, - &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); + &io->pfrio_size, io->pfrio_flags); break; } @@ -2174,7 +2357,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } error = pfr_get_tstats(&io->pfrio_table, io->pfrio_buffer, - &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); + &io->pfrio_size, io->pfrio_flags); break; } @@ -2186,7 +2369,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } error = pfr_clr_tstats(io->pfrio_buffer, io->pfrio_size, - &io->pfrio_nzero, io->pfrio_flags | PFR_FLAG_USERIOCTL); + &io->pfrio_nzero, io->pfrio_flags); break; } @@ -2199,7 +2382,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size, io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange, - &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL); + &io->pfrio_ndel, io->pfrio_flags); break; } @@ -2211,7 +2394,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel, - io->pfrio_flags | PFR_FLAG_USERIOCTL); + io->pfrio_flags); break; } @@ -2223,8 +2406,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } error = pfr_add_addrs(&io->pfrio_table, io->pfrio_buffer, - io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags | - PFR_FLAG_USERIOCTL); + io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags); break; } @@ -2236,8 +2418,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } error = pfr_del_addrs(&io->pfrio_table, io->pfrio_buffer, - io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags | - PFR_FLAG_USERIOCTL); + io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags); break; } @@ -2250,8 +2431,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); + &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags); break; } @@ -2263,7 +2443,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } error = pfr_get_addrs(&io->pfrio_table, io->pfrio_buffer, - &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); + &io->pfrio_size, io->pfrio_flags); break; } @@ -2275,7 +2455,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } error = pfr_get_astats(&io->pfrio_table, io->pfrio_buffer, - &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); + &io->pfrio_size, io->pfrio_flags); break; } @@ -2287,8 +2467,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } error = pfr_clr_astats(&io->pfrio_table, io->pfrio_buffer, - io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags | - PFR_FLAG_USERIOCTL); + io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags); break; } @@ -2300,8 +2479,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } error = pfr_tst_addrs(&io->pfrio_table, io->pfrio_buffer, - io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags | - PFR_FLAG_USERIOCTL); + io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags); break; } @@ -2313,7 +2491,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } error = pfr_ina_begin(&io->pfrio_table, &io->pfrio_ticket, - &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL); + &io->pfrio_ndel, io->pfrio_flags); break; } @@ -2325,8 +2503,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } error = pfr_ina_commit(&io->pfrio_table, io->pfrio_ticket, - &io->pfrio_nadd, &io->pfrio_nchange, io->pfrio_flags | - PFR_FLAG_USERIOCTL); + &io->pfrio_nadd, &io->pfrio_nchange, io->pfrio_flags); break; } @@ -2339,10 +2516,16 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer, io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr, - io->pfrio_ticket, io->pfrio_flags | PFR_FLAG_USERIOCTL); + io->pfrio_ticket, io->pfrio_flags); break; } + case DIOCOSFPFLUSH: + s = splsoftnet(); + pf_osfp_flush(); + splx(s); + break; + case DIOCOSFPADD: { struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr; s = splsoftnet(); @@ -2359,297 +2542,696 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } - case DIOCXBEGIN: { - struct pfioc_trans *io = (struct pfioc_trans *)addr; - struct pfioc_trans_e ioe; - struct pfr_table table; - int i; + default: + error = ENODEV; + break; + } +fail: +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif + return (error); +} + +#ifdef __FreeBSD__ +/* + * XXX - Check for version missmatch!!! + */ +static int +pf_beginrules(void *addr) +{ + struct pfioc_rule *pr = (struct pfioc_rule *)addr; + struct pf_ruleset *ruleset; + struct pf_rule *rule; + int rs_num; + int error = 0; - if (io->esize != sizeof(ioe)) { - error = ENODEV; - goto fail; + do { + ruleset = pf_find_or_create_ruleset(pr->anchor, pr->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; } - for (i = 0; i < io->size; i++) { - if (copyin(io->array+i, &ioe, sizeof(ioe))) { - error = EFAULT; - goto fail; - } - switch (ioe.rs_num) { + rs_num = pf_get_ruleset_number(pr->rule.action); + if (rs_num >= PF_RULESET_MAX) { + error = EINVAL; + break; + } + while ((rule = + TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr)) != NULL) + pf_rm_rule(ruleset->rules[rs_num].inactive.ptr, rule); + pr->ticket = ++ruleset->rules[rs_num].inactive.ticket; + } while(0); + + return (error); +} + +static int +pf_commitrules(void *addr) +{ + struct pfioc_rule *pr = (struct pfioc_rule *)addr; + struct pf_ruleset *ruleset; + struct pf_rulequeue *old_rules; + struct pf_rule *rule; + int rs_num, s; + int error = 0; + + do { + ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } + rs_num = pf_get_ruleset_number(pr->rule.action); + if (rs_num >= PF_RULESET_MAX) { + error = EINVAL; + break; + } + if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) { + error = EBUSY; + break; + } + #ifdef ALTQ - case PF_RULESET_ALTQ: - if (ioe.anchor[0] || ioe.ruleset[0]) { - error = EINVAL; - goto fail; - } - 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)); - strlcpy(table.pfrt_ruleset, ioe.ruleset, - sizeof(table.pfrt_ruleset)); - 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, ioe.ruleset))) - goto fail; - break; - } - if (copyout(&ioe, io->array+i, sizeof(io->array[i]))) { - error = EFAULT; - goto fail; - } + /* set queue IDs */ + if (rs_num == PF_RULESET_FILTER) + pf_rule_set_qid(ruleset->rules[rs_num].inactive.ptr); +#endif + + /* Swap rules, keep the old. */ + s = splsoftnet(); + old_rules = ruleset->rules[rs_num].active.ptr; + ruleset->rules[rs_num].active.ptr = + ruleset->rules[rs_num].inactive.ptr; + ruleset->rules[rs_num].inactive.ptr = old_rules; + ruleset->rules[rs_num].active.ticket = + ruleset->rules[rs_num].inactive.ticket; + pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr); + + /* Purge the old rule list. */ + while ((rule = TAILQ_FIRST(old_rules)) != NULL) + pf_rm_rule(old_rules, rule); + pf_remove_if_empty_ruleset(ruleset); + pf_update_anchor_rules(); + splx(s); + } while (0); + + return (error); +} + +#ifdef ALTQ +static int +pf_beginaltqs(void *addr) +{ + u_int32_t *ticket = (u_int32_t *)addr; + struct pf_altq *altq; + int error = 0; + + /* Purge the old altq list */ + while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { + TAILQ_REMOVE(pf_altqs_inactive, altq, entries); + if (altq->qname[0] == 0) { +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif + /* detach and destroy the discipline */ + error = altq_remove(altq); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif } - break; + uma_zfree(pf_altq_pl, altq); } + *ticket = ++ticket_altqs_inactive; - case DIOCXROLLBACK: { - struct pfioc_trans *io = (struct pfioc_trans *)addr; - struct pfioc_trans_e ioe; - struct pfr_table table; - int i; + return (error); +} - if (io->esize != sizeof(ioe)) { - error = ENODEV; - goto fail; +static int +pf_commitaltqs(void *addr) +{ + u_int32_t *ticket = (u_int32_t *)addr; + struct pf_altqqueue *old_altqs; + struct pf_altq *altq; + struct pf_anchor *anchor; + struct pf_ruleset *ruleset; + int err; + int s; + int error = 0; + + do { + if (*ticket != ticket_altqs_inactive) { + error = EBUSY; + break; } - for (i = 0; i < io->size; i++) { - if (copyin(io->array+i, &ioe, sizeof(ioe))) { - error = EFAULT; - goto fail; - } - switch (ioe.rs_num) { -#ifdef ALTQ - case PF_RULESET_ALTQ: - if (ioe.anchor[0] || ioe.ruleset[0]) { - error = EINVAL; - goto fail; + + /* Swap altqs, keep the old. */ + s = splsoftnet(); + old_altqs = pf_altqs_active; + pf_altqs_active = pf_altqs_inactive; + pf_altqs_inactive = old_altqs; + ticket_altqs_active = ticket_altqs_inactive; + + /* Attach new disciplines */ + TAILQ_FOREACH(altq, pf_altqs_active, entries) { + if (altq->qname[0] == 0) { + /* attach the discipline */ +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif + error = altq_pfattach(altq); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif + if (error) { + splx(s); + goto altq_fail; } - 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)); - strlcpy(table.pfrt_ruleset, ioe.ruleset, - sizeof(table.pfrt_ruleset)); - 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, ioe.ruleset))) - goto fail; /* really bad */ - break; } } - 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)) { - error = ENODEV; - goto fail; + /* Purge the old altq list */ + while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { + TAILQ_REMOVE(pf_altqs_inactive, altq, entries); + if (altq->qname[0] == 0) { + /* detach and destroy the discipline */ +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif + err = altq_pfdetach(altq); + if (err != 0 && error == 0) + error = err; + err = altq_remove(altq); + if (err != 0 && error == 0) + error = err; +#ifdef __FreeBSD__ + PF_LOCK(); +#endif + } + uma_zfree(pf_altq_pl, altq); } - /* first makes sure everything will succeed */ - for (i = 0; i < io->size; i++) { - if (copyin(io->array+i, &ioe, sizeof(ioe))) { - error = EFAULT; - goto fail; + splx(s); + + /* update queue IDs */ + pf_rule_set_qid( + pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); + TAILQ_FOREACH(anchor, &pf_anchors, entries) { + TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) { + pf_rule_set_qid( + ruleset->rules[PF_RULESET_FILTER].active.ptr + ); } - switch (ioe.rs_num) { -#ifdef ALTQ - case PF_RULESET_ALTQ: - if (ioe.anchor[0] || ioe.ruleset[0]) { - error = EINVAL; - goto fail; - } - if (!altqs_inactive_open || ioe.ticket != - ticket_altqs_inactive) { - error = EBUSY; - goto fail; - } - break; -#endif /* ALTQ */ - case PF_RULESET_TABLE: - rs = pf_find_ruleset(ioe.anchor, ioe.ruleset); - if (rs == NULL || !rs->topen || ioe.ticket != - rs->tticket) { - error = EBUSY; - goto fail; - } - break; - default: - if (ioe.rs_num < 0 || ioe.rs_num >= - PF_RULESET_MAX) { + } + } while (0); + +altq_fail: + + return (error); +} + +static int +pf_stopaltq(void) +{ + struct pf_altq *altq; + struct ifnet *ifp; + struct tb_profile tb; + int err; + int s; + int error = 0; + + do { + /* disable all altq interfaces on active list */ + s = splsoftnet(); + TAILQ_FOREACH(altq, pf_altqs_active, entries) { + if (altq->qname[0] == 0) { + if ((ifp = ifunit(altq->ifname)) == NULL) { error = EINVAL; - goto fail; + break; } - rs = pf_find_ruleset(ioe.anchor, ioe.ruleset); - if (rs == NULL || - !rs->rules[ioe.rs_num].inactive.open || - rs->rules[ioe.rs_num].inactive.ticket != - ioe.ticket) { - error = EBUSY; - goto fail; + if (ifp->if_snd.altq_type != ALTQT_NONE) { + err = altq_disable(&ifp->if_snd); + if (err != 0 && error == 0) + error = err; } - break; + /* clear tokenbucket regulator */ + tb.rate = 0; + err = tbr_set(&ifp->if_snd, &tb); + if (err != 0 && error == 0) + error = err; } } - /* now do the commit - no errors should happen here */ - for (i = 0; i < io->size; i++) { - if (copyin(io->array+i, &ioe, sizeof(ioe))) { - error = EFAULT; - goto fail; - } - switch (ioe.rs_num) { + if (error == 0) + pfaltq_running = 0; + splx(s); + } while (0); + + return (error); +} +#endif + +static void +pf_clearstates(void) +{ + struct pf_tree_node *n; + int s; + + s = splsoftnet(); + RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) + n->state->timeout = PFTM_PURGE; + pf_purge_expired_states(); + pf_status.states = 0; + splx(s); +} + +static int +pf_clear_tables(void *addr) +{ + struct pfioc_table *io = (struct pfioc_table *)addr; + int error; + + error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel, + io->pfrio_flags); + + return (error); +} + +static int +shutdown_pf(void) +{ + struct pfioc_rule pr; #ifdef ALTQ - case PF_RULESET_ALTQ: - 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)); - strlcpy(table.pfrt_ruleset, ioe.ruleset, - sizeof(table.pfrt_ruleset)); - 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, ioe.ruleset))) - goto fail; /* really bad */ - break; - } - } - break; - } + struct pfioc_altq pa; +#endif + struct pfioc_table io; + int error = 0; - case DIOCGETSRCNODES: { - struct pfioc_src_nodes *psn = (struct pfioc_src_nodes *)addr; - struct pf_src_node *n; - struct pf_src_node *p, pstore; - u_int32_t nr = 0; - int space = psn->psn_len; + callout_stop(&pf_expire_to); - if (space == 0) { - s = splsoftnet(); - RB_FOREACH(n, pf_src_tree, &tree_src_tracking) - nr++; - splx(s); - psn->psn_len = sizeof(struct pf_src_node) * nr; - return (0); + PF_LOCK(); + pf_status.running = 0; + do { +#ifdef ALTQ + if ((error = pf_stopaltq())) { + DPFPRINTF(PF_DEBUG_MISC, + ("ALTQ: stop(%i)\n", error)); + break; + } +#endif + bzero(&pr, sizeof(pr)); + pr.rule.action = PF_SCRUB; + if ((error = pf_beginrules(&pr))) { + DPFPRINTF(PF_DEBUG_MISC, + ("PF_SCRUB: begin(%i)\n", error)); + break; + } + if ((error = pf_commitrules(&pr))) { + DPFPRINTF(PF_DEBUG_MISC, + ("PF_SCRUB: commit(%i)\n", error)); + break; } - s = splsoftnet(); - p = psn->psn_src_nodes; - RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { - int secs = time.tv_sec; + pr.rule.action = PF_PASS; + if ((error = pf_beginrules(&pr))) { + DPFPRINTF(PF_DEBUG_MISC, + ("PF_PASS: begin(%i)\n", error)); + break; + } + if ((error = pf_commitrules(&pr))) { + DPFPRINTF(PF_DEBUG_MISC, + ("PF_PASS: commit(%i)\n", error)); + break; + } - if ((nr + 1) * sizeof(*p) > (unsigned)psn->psn_len) - break; +/* + * XXX not sure, but can't hurt: + */ + bzero(&pr, sizeof(pr)); + pr.rule.action = PF_NAT; + if ((error = pf_beginrules(&pr))) { + DPFPRINTF(PF_DEBUG_MISC, + ("PF_NAT: begin(%i)\n", error)); + break; + } + if ((error = pf_commitrules(&pr))) { + DPFPRINTF(PF_DEBUG_MISC, + ("PF_NAT: commit(%i)\n", error)); + break; + } - 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; - else - pstore.expire = 0; - error = copyout(&pstore, p, sizeof(*p)); - if (error) { - splx(s); - goto fail; - } - p++; - nr++; + pr.rule.action = PF_BINAT; + if ((error = pf_beginrules(&pr))) { + DPFPRINTF(PF_DEBUG_MISC, + ("PF_BINAT: begin(%i)\n", error)); + break; + } + if ((error = pf_commitrules(&pr))) { + DPFPRINTF(PF_DEBUG_MISC, + ("PF_BINAT: begin(%i)\n", error)); + break; } - psn->psn_len = sizeof(struct pf_src_node) * nr; - splx(s); - break; - } - case DIOCCLRSRCNODES: { - struct pf_src_node *n; - struct pf_state *state; + pr.rule.action = PF_RDR; + if ((error = pf_beginrules(&pr))) { + DPFPRINTF(PF_DEBUG_MISC, + ("PF_RDR: begin(%i)\n", error)); + break; + } + if ((error = pf_commitrules(&pr))) { + DPFPRINTF(PF_DEBUG_MISC, + ("PF_RDR: commit(%i)\n", error)); + break; + } - s = splsoftnet(); - RB_FOREACH(state, pf_state_tree_id, &tree_id) { - state->src_node = NULL; - state->nat_src_node = NULL; +#ifdef ALTQ + bzero(&pa, sizeof(pa)); + if ((error = pf_beginaltqs(&pa))) { + DPFPRINTF(PF_DEBUG_MISC, + ("ALTQ: begin(%i)\n", error)); + break; } - RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { - n->expire = 1; - n->states = 0; + if ((error = pf_commitaltqs(&pa))) { + DPFPRINTF(PF_DEBUG_MISC, + ("ALTQ: commit(%i)\n", error)); + break; } - pf_purge_expired_src_nodes(); - pf_status.src_nodes = 0; - splx(s); - break; +#endif + pf_clearstates(); + + bzero(&io, sizeof(io)); + if ((error = pf_clear_tables(&io))) { + DPFPRINTF(PF_DEBUG_MISC, + ("TABLES: clear(%i)\n", error)); + break; + } + pf_osfp_flush(); + } while(0); + + PF_UNLOCK(); + return (error); +} + +static int +#if (__FreeBSD_version < 501108) +pf_check_in(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m) +#else +pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) +#endif +{ + /* + * 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); + 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 +#if (__FreeBSD_version < 501108) +pf_check_out(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m) +#else +pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) +#endif +{ + /* + * 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); + 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 +#if (__FreeBSD_version < 501108) +pf_check6_in(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m) +#else +pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) +#endif +{ + /* + * IPv6 does not affected ip_len/ip_off byte order changes. + */ + int chk; + + chk = pf_test6(PF_IN, ifp, m); + if (chk && *m) { + m_freem(*m); + *m = NULL; } + return chk; +} - case DIOCSETHOSTID: { - u_int32_t *hostid = (u_int32_t *)addr; +static int +#if (__FreeBSD_version < 501108) +pf_check6_out(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m) +#else +pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) +#endif +{ + /* + * IPv6 does not affected ip_len/ip_off byte order changes. + */ + int chk; - if (*hostid == 0) { - error = EINVAL; - goto fail; - } - pf_status.hostid = *hostid; - break; + /* 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); + if (chk && *m) { + m_freem(*m); + *m = NULL; + } + return chk; +} +#endif /* INET6 */ - case DIOCOSFPFLUSH: - s = splsoftnet(); - pf_osfp_flush(); - splx(s); - break; +static int +hook_pf(void) +{ +#if (__FreeBSD_version >= 501108) + struct pfil_head *pfh_inet; +#ifdef INET6 + struct pfil_head *pfh_inet6; +#endif +#endif + + PF_ASSERT(MA_NOTOWNED); - case DIOCIGETIFACES: { - struct pfioc_iface *io = (struct pfioc_iface *)addr; + if (pf_pfil_hooked) + return (0); + +#if (__FreeBSD_version < 501108) + /* + * XXX + * There is no easy way to get pfil header pointer with address + * family such as AF_INET, AF_INET6. + * Needs direct variable reference. + */ - 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_flags); - break; + pfil_add_hook(pf_check_in, PFIL_IN, + &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); + pfil_add_hook(pf_check_out, PFIL_OUT, + &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); +#ifdef INET6 + pfil_add_hook(pf_check6_in, PFIL_IN, + &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); + pfil_add_hook(pf_check6_out, PFIL_OUT, + &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); +#endif +#else /* __FreeBSD_version >= 501108 */ + 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 +#endif /* __FreeBSD_version >= 501108 */ + + pf_pfil_hooked = 1; + return (0); +} + +static int +dehook_pf(void) +{ +#if (__FreeBSD_version >= 501108) + struct pfil_head *pfh_inet; +#ifdef INET6 + struct pfil_head *pfh_inet6; +#endif +#endif + + PF_ASSERT(MA_NOTOWNED); + + if (pf_pfil_hooked == 0) + return (0); + +#if (__FreeBSD_version < 501108) + pfil_remove_hook(pf_check_in, PFIL_IN, + &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); + pfil_remove_hook(pf_check_out, PFIL_OUT, + &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); +#ifdef INET6 + pfil_remove_hook(pf_check6_in, PFIL_IN, + &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); + pfil_remove_hook(pf_check6_out, PFIL_OUT, + &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); +#endif +#else /* __FreeBSD_version >= 501108 */ + 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 +#endif /* __FreeBSD_version >= 501108 */ + + 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); +} - case DIOCICLRISTATS: { - struct pfioc_iface *io = (struct pfioc_iface *)addr; +static int +pf_unload(void) +{ + int error = 0; - error = pfi_clr_istats(io->pfiio_name, &io->pfiio_nzero, - io->pfiio_flags); + 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; + } + shutdown_pf(); + cleanup_pf_zone(); + pf_osfp_cleanup(); + 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 = ENODEV; + error = EINVAL; break; } -fail: - - return (error); + return error; } + +static moduledata_t pf_mod = { + "pf", + pf_modevent, + 0 +}; + +DECLARE_MODULE(pf, pf_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); +MODULE_DEPEND(pf, pflog, PFLOG_MINVER, PFLOG_PREFVER, PFLOG_MAXVER); +MODULE_DEPEND(pf, pfsync, PFSYNC_MINVER, PFSYNC_PREFVER, PFSYNC_MAXVER); +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 d2c6456..10f066e 100644 --- a/sys/contrib/pf/net/pf_norm.c +++ b/sys/contrib/pf/net/pf_norm.c @@ -1,4 +1,5 @@ -/* $OpenBSD: pf_norm.c,v 1.80 2004/03/09 21:44:41 mcbride Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: pf_norm.c,v 1.75.2.1 2004/04/30 23:28:36 brad Exp $ */ /* * Copyright 2001 Niels Provos <provos@citi.umich.edu> @@ -25,7 +26,15 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifdef __FreeBSD__ +#include "opt_inet.h" +#include "opt_inet6.h" +#include "opt_random_ip_id.h" /* or ip_var does not export it */ +#include "opt_pf.h" +#define NPFLOG DEV_PFLOG +#else #include "pflog.h" +#endif #include <sys/param.h> #include <sys/systm.h> @@ -35,9 +44,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 +71,49 @@ #include <net/pfvar.h> +#if defined(__FreeBSD__) && defined(INET6) +/* + * XXX: This should go to netinet/ip6.h (KAME) + */ +/* IPv6 options: common part */ +struct ip6_opt { + u_int8_t ip6o_type; + u_int8_t ip6o_len; +} __packed; + +/* Jumbo Payload Option */ +struct ip6_opt_jumbo { + u_int8_t ip6oj_type; + u_int8_t ip6oj_len; + u_int8_t ip6oj_jumbo_len[4]; +} __packed; + +/* NSAP Address Option */ +struct ip6_opt_nsap { + u_int8_t ip6on_type; + u_int8_t ip6on_len; + u_int8_t ip6on_src_nsap_len; + u_int8_t ip6on_dst_nsap_len; + /* followed by source NSAP */ + /* followed by destination NSAP */ +} __packed; + +/* Tunnel Limit Option */ +struct ip6_opt_tunnel { + u_int8_t ip6ot_type; + u_int8_t ip6ot_len; + u_int8_t ip6ot_encap_limit; +} __packed; + +/* Router Alert Option */ +struct ip6_opt_router { + u_int8_t ip6or_type; + u_int8_t ip6or_len; + u_int8_t ip6or_value[2]; +} __packed; +#endif /* __FreeBSD__ && INET6 */ + +#ifndef __FreeBSD__ struct pf_frent { LIST_ENTRY(pf_frent) fr_next; struct ip *fr_ip; @@ -71,12 +125,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,6 +150,7 @@ 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; @@ -105,6 +162,9 @@ RB_PROTOTYPE(pf_frag_tree, pf_fragment, fr_entry, pf_frag_compare); RB_GENERATE(pf_frag_tree, pf_fragment, fr_entry, pf_frag_compare); /* Private prototypes */ +#ifndef RANDOM_IP_ID +extern u_int16_t ip_randomid(void); +#endif void pf_ip2key(struct pf_fragment *, struct ip *); void pf_remove_fragment(struct pf_fragment *); void pf_flush_fragments(void); @@ -122,13 +182,28 @@ int pf_normalize_tcpopt(struct pf_rule *, struct mbuf *, { printf("%s: ", __func__); printf x ;} /* 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", @@ -144,12 +219,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; @@ -173,11 +253,21 @@ void pf_purge_expired_fragments(void) { struct pf_fragment *frag; +#ifdef __FreeBSD__ + u_int32_t expire = time_second - + pf_default_rule.timeout[PFTM_FRAG]; +#else u_int32_t expire = time.tv_sec - pf_default_rule.timeout[PFTM_FRAG]; +#endif 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; @@ -186,14 +276,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 } } @@ -252,9 +354,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--; @@ -284,7 +394,11 @@ pf_find_fragment(struct ip *ip, struct pf_frag_tree *tree) frag = RB_FIND(pf_frag_tree, tree, &key); if (frag != NULL) { /* XXX Are we sure we want to update the timeout? */ +#ifdef __FreeBSD__ + frag->fr_timeout = time_second; +#else frag->fr_timeout = time.tv_sec; +#endif if (BUFFER_FRAGMENTS(frag)) { TAILQ_REMOVE(&pf_fragqueue, frag, frag_next); TAILQ_INSERT_HEAD(&pf_fragqueue, frag, frag_next); @@ -327,7 +441,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; @@ -349,7 +468,11 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag, (*frag)->fr_dst = frent->fr_ip->ip_dst; (*frag)->fr_p = frent->fr_ip->ip_p; (*frag)->fr_id = frent->fr_ip->ip_id; +#ifdef __FreeBSD__ + (*frag)->fr_timeout = time_second; +#else (*frag)->fr_timeout = time.tv_sec; +#endif LIST_INIT(&(*frag)->fr_queue); RB_INSERT(pf_frag_tree, &pf_frag_tree, *frag); @@ -370,11 +493,16 @@ 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 * - 4 > off) + 4 > off) { u_int16_t precut; @@ -455,7 +583,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); @@ -524,7 +656,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) { @@ -551,7 +688,11 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff, (*frag)->fr_dst = h->ip_dst; (*frag)->fr_p = h->ip_p; (*frag)->fr_id = h->ip_id; +#ifdef __FreeBSD__ + (*frag)->fr_timeout = time_second; +#else (*frag)->fr_timeout = time.tv_sec; +#endif cur->fr_off = off; cur->fr_end = max; @@ -577,7 +718,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; @@ -619,10 +765,23 @@ 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); + /* From KAME Project : We have missed this! */ + m_adj(*m0, (h->ip_hl << 2) - + (*m0)->m_pkthdr.len); +#else *m0 = m_copym2(m, 0, h->ip_hl << 2, M_NOWAIT); +#endif if (*m0 == NULL) goto no_mem; +#ifdef __FreeBSD__ + 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; @@ -637,11 +796,14 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff, h = mtod(m, struct ip *); - - KASSERT((int)m->m_len == - ntohs(h->ip_len) - precut); - h->ip_off = htons(ntohs(h->ip_off) + - (precut >> 3)); +#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); } else { hosed++; @@ -695,8 +857,13 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff, m->m_pkthdr.len = plen; } h = mtod(m, struct ip *); - KASSERT((int)m->m_len == - ntohs(h->ip_len) - aftercut); +#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++; @@ -734,7 +901,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, @@ -810,7 +982,7 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff, } int -pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason) +pf_normalize_ip(struct mbuf **m0, int dir, struct ifnet *ifp, u_short *reason) { struct mbuf *m = *m0; struct pf_rule *r; @@ -827,8 +999,7 @@ 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 (r->kif != NULL && - (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) + if (r->ifp != NULL && r->ifp != ifp) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != dir) r = r->skip[PF_SKIP_DIR].ptr; @@ -991,13 +1162,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); + PFLOG_PACKET(ifp, 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); + PFLOG_PACKET(ifp, h, m, AF_INET, dir, *reason, r, NULL, NULL); return (PF_DROP); bad: @@ -1009,15 +1180,14 @@ 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); + PFLOG_PACKET(ifp, h, m, AF_INET, dir, *reason, r, NULL, NULL); return (PF_DROP); } #ifdef INET6 int -pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif, - u_short *reason) +pf_normalize_ip6(struct mbuf **m0, int dir, struct ifnet *ifp, u_short *reason) { struct mbuf *m = *m0; struct pf_rule *r; @@ -1037,8 +1207,7 @@ 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 (r->kif != NULL && - (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) + if (r->ifp != NULL && r->ifp != ifp) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != dir) r = r->skip[PF_SKIP_DIR].ptr; @@ -1172,25 +1341,25 @@ 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); + PFLOG_PACKET(ifp, 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); + PFLOG_PACKET(ifp, 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); + PFLOG_PACKET(ifp, h, m, AF_INET6, dir, *reason, r, NULL, NULL); return (PF_DROP); } #endif int -pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff, +pf_normalize_tcp(int dir, struct ifnet *ifp, struct mbuf *m, int ipoff, int off, void *h, struct pf_pdesc *pd) { struct pf_rule *r, *rm = NULL; @@ -1203,8 +1372,7 @@ 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 (r->kif != NULL && - (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) + if (r->ifp != NULL && r->ifp != ifp) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != dir) r = r->skip[PF_SKIP_DIR].ptr; @@ -1290,14 +1458,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); + PFLOG_PACKET(ifp, h, m, AF_INET, dir, reason, r, NULL, NULL); return (PF_DROP); } @@ -1308,7 +1476,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) @@ -1338,7 +1511,7 @@ pf_normalize_tcp_init(struct mbuf *m, int off, struct pf_pdesc *pd, * the connections. They must all set an enabled bit in pfss_flags */ if ((th->th_flags & TH_SYN) == 0) - return (0); + return 0; if (th->th_off > (sizeof(struct tcphdr) >> 2) && src->scrub && @@ -1362,8 +1535,8 @@ pf_normalize_tcp_init(struct mbuf *m, int off, struct pf_pdesc *pd, } /* FALLTHROUGH */ default: - hlen -= opt[1]; - opt += opt[1]; + hlen -= MAX(opt[1], 2); + opt += MAX(opt[1], 2); break; } } @@ -1392,7 +1565,12 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, u_int8_t *opt; int copyback = 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 @@ -1413,7 +1591,7 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, #endif /* INET */ #ifdef INET6 case AF_INET6: { - if (src->scrub) { + if (dst->scrub) { struct ip6_hdr *h = mtod(m, struct ip6_hdr *); if (h->ip6_hlim > src->scrub->pfss_ttl) src->scrub->pfss_ttl = h->ip6_hlim; @@ -1457,13 +1635,11 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, &th->th_sum, ts_value, 0); copyback = 1; } - - /* Modulate TS reply iff valid (!0) */ - memcpy(&ts_value, &opt[6], - sizeof(u_int32_t)); - if (ts_value && dst->scrub && + if (dst->scrub && (dst->scrub->pfss_flags & PFSS_TIMESTAMP)) { + memcpy(&ts_value, &opt[6], + sizeof(u_int32_t)); ts_value = htonl(ntohl(ts_value) - dst->scrub->pfss_ts_mod); pf_change_a(&opt[6], @@ -1473,8 +1649,8 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, } /* FALLTHROUGH */ default: - hlen -= opt[1]; - opt += opt[1]; + hlen -= MAX(opt[1], 2); + opt += MAX(opt[1], 2); break; } } diff --git a/sys/contrib/pf/net/pf_osfp.c b/sys/contrib/pf/net/pf_osfp.c index 98cc01a..8687cb0 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.9 2004/01/04 20:08:42 pvalchev Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: pf_osfp.c,v 1.3 2003/08/27 18:23:36 frantzen Exp $ */ /* * Copyright (c) 2003 Mike Frantzen <frantzen@w4g.org> @@ -36,12 +37,15 @@ #include <netinet/ip6.h> #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. */ @@ -50,14 +54,17 @@ typedef struct pool pool_t; # include <errno.h> # include <stdio.h> # include <stdlib.h> -# include <string.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> +# include <stdarg.h> # define DPFPRINTF(format, x...) fprintf(stderr, format , ##x) # else # define DPFPRINTF(format, x...) ((void)0) @@ -229,15 +236,46 @@ 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", NULL); pool_init(&pf_osfp_pl, sizeof(struct pf_os_fingerprint), 0, 0, 0, "pfosfp", NULL); +#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 diff --git a/sys/contrib/pf/net/pf_table.c b/sys/contrib/pf/net/pf_table.c index 42d4cee..fb10915 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.47 2004/03/09 21:44:41 mcbride Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: pf_table.c,v 1.41 2003/08/22 15:19:23 henning 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,16 +61,6 @@ return (EINVAL); \ } while (0) -#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)) - #define FILLIN_SIN(sin, addr) \ do { \ (sin).sin_len = sizeof(sin); \ @@ -81,8 +83,8 @@ } while (0) #define SUNION2PF(su, af) (((af)==AF_INET) ? \ - (struct pf_addr *)&(su)->sin.sin_addr : \ - (struct pf_addr *)&(su)->sin6.sin6_addr) + (struct pf_addr *)&(su)->sin.sin_addr : \ + (struct pf_addr *)&(su)->sin6.sin6_addr) #define AF_BITS(af) (((af)==AF_INET)?32:128) #define ADDR_NETWORK(ad) ((ad)->pfra_net < AF_BITS((ad)->pfra_af)) @@ -101,33 +103,34 @@ struct pfr_walktree { PFRW_ENQUEUE, PFRW_GET_ADDRS, PFRW_GET_ASTATS, - PFRW_POOL_GET, - PFRW_DYNADDR_UPDATE + PFRW_POOL_GET } pfrw_op; union { struct pfr_addr *pfrw1_addr; struct pfr_astats *pfrw1_astats; struct pfr_kentryworkq *pfrw1_workq; struct pfr_kentry *pfrw1_kentry; - struct pfi_dynaddr *pfrw1_dyn; } pfrw_1; int pfrw_free; - int pfrw_flags; }; #define pfrw_addr pfrw_1.pfrw1_addr #define pfrw_astats pfrw_1.pfrw1_astats #define pfrw_workq pfrw_1.pfrw1_workq #define pfrw_kentry pfrw_1.pfrw1_kentry -#define pfrw_dyn pfrw_1.pfrw1_dyn #define pfrw_cnt pfrw_free #define senderr(e) do { rv = (e); goto _bad; } while (0) +#ifdef __FreeBSD__ +uma_zone_t pfr_ktable_pl; +uma_zone_t pfr_kentry_pl; +#else struct pool pfr_ktable_pl; struct pool pfr_kentry_pl; +#endif struct sockaddr_in pfr_sin; struct sockaddr_in6 pfr_sin6; -union sockaddr_union pfr_mask; +union sockaddr_union pfr_mask; struct pf_addr pfr_ffaddr; void pfr_copyout_addr(struct pfr_addr *, @@ -147,14 +150,14 @@ void pfr_remove_kentries(struct pfr_ktable *, struct pfr_kentryworkq *); void pfr_clstats_kentries(struct pfr_kentryworkq *, long, int); -void pfr_reset_feedback(struct pfr_addr *, int, int); +void pfr_reset_feedback(struct pfr_addr *, int); void pfr_prepare_network(union sockaddr_union *, int, int); int pfr_route_kentry(struct pfr_ktable *, struct pfr_kentry *); int pfr_unroute_kentry(struct pfr_ktable *, struct pfr_kentry *); int pfr_walktree(struct radix_node *, void *); -int pfr_validate_table(struct pfr_table *, int, int); +int pfr_validate_table(struct pfr_table *, int); void pfr_commit_ktable(struct pfr_ktable *, long); void pfr_insert_ktables(struct pfr_ktableworkq *); void pfr_insert_ktable(struct pfr_ktable *); @@ -169,12 +172,12 @@ void pfr_destroy_ktable(struct pfr_ktable *, int); int pfr_ktable_compare(struct pfr_ktable *, struct pfr_ktable *); struct pfr_ktable *pfr_lookup_table(struct pfr_table *); -void pfr_clean_node_mask(struct pfr_ktable *, +void pfr_clean_node_mask(struct pfr_ktable *, struct pfr_kentryworkq *); int pfr_table_count(struct pfr_table *, int); int pfr_skip_table(struct pfr_table *, struct pfr_ktable *, int); -struct pfr_kentry *pfr_kentry_byidx(struct pfr_ktable *, int, int); +struct pfr_kentry *pfr_kentry_byidx(struct pfr_ktable *, int, int); RB_PROTOTYPE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare); RB_GENERATE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare); @@ -186,10 +189,12 @@ int pfr_ktable_cnt; void pfr_initialize(void) { +#ifndef __FreeBSD__ pool_init(&pfr_ktable_pl, sizeof(struct pfr_ktable), 0, 0, 0, "pfrktable", NULL); pool_init(&pfr_kentry_pl, sizeof(struct pfr_kentry), 0, 0, 0, "pfrkentry", NULL); +#endif pfr_sin.sin_len = sizeof(pfr_sin); pfr_sin.sin_family = AF_INET; @@ -207,7 +212,7 @@ pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags) int s; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); - if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) + if (pfr_validate_table(tbl, 0)) return (EINVAL); kt = pfr_lookup_table(tbl); if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) @@ -240,10 +245,18 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfr_kentry *p, *q; struct pfr_addr ad; int i, rv, s, xadd = 0; +#ifdef __FreeBSD__ + int ec; + /* + * XXX Is it OK under LP64 environments? + */ + long tzero = (long)time_second; +#else long tzero = time.tv_sec; +#endif ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); - if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) + if (pfr_validate_table(tbl, 0)) return (EINVAL); kt = pfr_lookup_table(tbl); if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) @@ -255,8 +268,14 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, return (ENOMEM); SLIST_INIT(&workq); for (i = 0; i < size; i++) { - if (COPYIN(addr+i, &ad, sizeof(ad))) +#ifdef __FreeBSD__ + PF_COPYIN(addr+i, &ad, sizeof(ad), ec); + if (ec) + senderr(EFAULT); +#else + if (copyin(addr+i, &ad, sizeof(ad))) senderr(EFAULT); +#endif if (pfr_validate_addr(&ad)) senderr(EINVAL); p = pfr_lookup_addr(kt, &ad, 1); @@ -283,9 +302,17 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, xadd++; } } +#ifdef __FreeBSD__ + if (flags & PFR_FLAG_FEEDBACK) { + PF_COPYOUT(&ad, addr+i, sizeof(ad), ec); + if (ec) + senderr(EFAULT); + } +#else if (flags & PFR_FLAG_FEEDBACK) - if (COPYOUT(&ad, addr+i, sizeof(ad))) + if (copyout(&ad, addr+i, sizeof(ad))) senderr(EFAULT); +#endif } pfr_clean_node_mask(tmpkt, &workq); if (!(flags & PFR_FLAG_DUMMY)) { @@ -304,7 +331,7 @@ _bad: pfr_clean_node_mask(tmpkt, &workq); pfr_destroy_kentries(&workq); if (flags & PFR_FLAG_FEEDBACK) - pfr_reset_feedback(addr, size, flags); + pfr_reset_feedback(addr, size); pfr_destroy_ktable(tmpkt, 0); return (rv); } @@ -318,9 +345,12 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfr_kentry *p; struct pfr_addr ad; int i, rv, s, xdel = 0; +#ifdef __FreeBSD__ + int ec; +#endif ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); - if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) + if (pfr_validate_table(tbl, 0)) return (EINVAL); kt = pfr_lookup_table(tbl); if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) @@ -330,8 +360,14 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, pfr_mark_addrs(kt); SLIST_INIT(&workq); for (i = 0; i < size; i++) { - if (COPYIN(addr+i, &ad, sizeof(ad))) +#ifdef __FreeBSD__ + PF_COPYIN(addr+i, &ad, sizeof(ad), ec); + if (ec) + senderr(EFAULT); +#else + if (copyin(addr+i, &ad, sizeof(ad))) senderr(EFAULT); +#endif if (pfr_validate_addr(&ad)) senderr(EINVAL); p = pfr_lookup_addr(kt, &ad, 1); @@ -351,9 +387,17 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, SLIST_INSERT_HEAD(&workq, p, pfrke_workq); xdel++; } +#ifdef __FreeBSD__ + if (flags & PFR_FLAG_FEEDBACK) { + PF_COPYOUT(&ad, addr+i, sizeof(ad), ec); + if (ec) + senderr(EFAULT); + } +#else if (flags & PFR_FLAG_FEEDBACK) - if (COPYOUT(&ad, addr+i, sizeof(ad))) + if (copyout(&ad, addr+i, sizeof(ad))) senderr(EFAULT); +#endif } if (!(flags & PFR_FLAG_DUMMY)) { if (flags & PFR_FLAG_ATOMIC) @@ -367,7 +411,7 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, return (0); _bad: if (flags & PFR_FLAG_FEEDBACK) - pfr_reset_feedback(addr, size, flags); + pfr_reset_feedback(addr, size); return (rv); } @@ -380,10 +424,18 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfr_kentry *p, *q; struct pfr_addr ad; int i, rv, s, xadd = 0, xdel = 0, xchange = 0; +#ifdef __FreeBSD__ + int ec; + /* + * XXX Is it OK under LP64 environments? + */ + long tzero = (long)time_second; +#else long tzero = time.tv_sec; +#endif ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); - if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) + if (pfr_validate_table(tbl, 0)) return (EINVAL); kt = pfr_lookup_table(tbl); if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) @@ -398,8 +450,14 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, SLIST_INIT(&delq); SLIST_INIT(&changeq); for (i = 0; i < size; i++) { - if (COPYIN(addr+i, &ad, sizeof(ad))) +#ifdef __FreeBSD__ + PF_COPYIN(addr+i, &ad, sizeof(ad), ec); + if (ec) senderr(EFAULT); +#else + if (copyin(addr+i, &ad, sizeof(ad))) + senderr(EFAULT); +#endif if (pfr_validate_addr(&ad)) senderr(EINVAL); ad.pfra_fback = PFR_FB_NONE; @@ -434,9 +492,17 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, } } _skip: +#ifdef __FreeBSD__ + if (flags & PFR_FLAG_FEEDBACK) { + PF_COPYOUT(&ad, addr+i, sizeof(ad), ec); + if (ec) + senderr(EFAULT); + } +#else if (flags & PFR_FLAG_FEEDBACK) - if (COPYOUT(&ad, addr+i, sizeof(ad))) + if (copyout(&ad, addr+i, sizeof(ad))) senderr(EFAULT); +#endif } pfr_enqueue_addrs(kt, &delq, &xdel, ENQUEUE_UNMARKED_ONLY); if ((flags & PFR_FLAG_FEEDBACK) && *size2) { @@ -448,8 +514,14 @@ _skip: SLIST_FOREACH(p, &delq, pfrke_workq) { pfr_copyout_addr(&ad, p); ad.pfra_fback = PFR_FB_DELETED; - if (COPYOUT(&ad, addr+size+i, sizeof(ad))) +#ifdef __FreeBSD__ + PF_COPYOUT(&ad, addr+size+i, sizeof(ad), ec); + if (ec) + senderr(EFAULT); +#else + if (copyout(&ad, addr+size+i, sizeof(ad))) senderr(EFAULT); +#endif i++; } } @@ -470,7 +542,7 @@ _skip: *ndel = xdel; if (nchange != NULL) *nchange = xchange; - if ((flags & PFR_FLAG_FEEDBACK) && size2) + if ((flags & PFR_FLAG_FEEDBACK) && *size2) *size2 = size+xdel; pfr_destroy_ktable(tmpkt, 0); return (0); @@ -478,7 +550,7 @@ _bad: pfr_clean_node_mask(tmpkt, &addq); pfr_destroy_kentries(&addq); if (flags & PFR_FLAG_FEEDBACK) - pfr_reset_feedback(addr, size, flags); + pfr_reset_feedback(addr, size); pfr_destroy_ktable(tmpkt, 0); return (rv); } @@ -491,17 +563,26 @@ pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfr_kentry *p; struct pfr_addr ad; int i, xmatch = 0; +#ifdef __FreeBSD__ + int ec; +#endif ACCEPT_FLAGS(PFR_FLAG_REPLACE); - if (pfr_validate_table(tbl, 0, 0)) + if (pfr_validate_table(tbl, 0)) return (EINVAL); kt = pfr_lookup_table(tbl); if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) return (ESRCH); for (i = 0; i < size; i++) { - if (COPYIN(addr+i, &ad, sizeof(ad))) +#ifdef __FreeBSD__ + PF_COPYIN(addr+i, &ad, sizeof(ad), ec); + if (ec) + return (EFAULT); +#else + if (copyin(addr+i, &ad, sizeof(ad))) return (EFAULT); +#endif if (pfr_validate_addr(&ad)) return (EINVAL); if (ADDR_NETWORK(&ad)) @@ -513,8 +594,14 @@ pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, (p->pfrke_not ? PFR_FB_NOTMATCH : PFR_FB_MATCH); if (p != NULL && !p->pfrke_not) xmatch++; - if (COPYOUT(&ad, addr+i, sizeof(ad))) +#ifdef __FreeBSD__ + PF_COPYOUT(&ad, addr+i, sizeof(ad), ec); + if (ec) return (EFAULT); +#else + if (copyout(&ad, addr+i, sizeof(ad))) + return (EFAULT); +#endif } if (nmatch != NULL) *nmatch = xmatch; @@ -530,7 +617,7 @@ pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size, int rv; ACCEPT_FLAGS(0); - if (pfr_validate_table(tbl, 0, 0)) + if (pfr_validate_table(tbl, 0)) return (EINVAL); kt = pfr_lookup_table(tbl); if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) @@ -544,10 +631,18 @@ pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size, w.pfrw_op = PFRW_GET_ADDRS; 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); @@ -568,10 +663,17 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, struct pfr_walktree w; struct pfr_kentryworkq workq; int rv, s; +#ifdef __FreeBSD__ + /* + * XXX Is it OK under LP64 environments? + */ + long tzero = (long)time_second; +#else long tzero = time.tv_sec; +#endif ACCEPT_FLAGS(PFR_FLAG_ATOMIC); /* XXX PFR_FLAG_CLSTATS disabled */ - if (pfr_validate_table(tbl, 0, 0)) + if (pfr_validate_table(tbl, 0)) return (EINVAL); kt = pfr_lookup_table(tbl); if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) @@ -585,12 +687,20 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, w.pfrw_op = PFRW_GET_ASTATS; w.pfrw_astats = addr; w.pfrw_free = kt->pfrkt_cnt; - 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); @@ -618,25 +728,40 @@ pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfr_kentry *p; struct pfr_addr ad; int i, rv, s, xzero = 0; +#ifdef __FreeBSD__ + int ec; +#endif ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); - if (pfr_validate_table(tbl, 0, 0)) + if (pfr_validate_table(tbl, 0)) return (EINVAL); kt = pfr_lookup_table(tbl); if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) return (ESRCH); SLIST_INIT(&workq); for (i = 0; i < size; i++) { - if (COPYIN(addr+i, &ad, sizeof(ad))) +#ifdef __FreeBSD__ + PF_COPYIN(addr+i, &ad, sizeof(ad), ec); + if (ec) + senderr(EFAULT); +#else + if (copyin(addr+i, &ad, sizeof(ad))) senderr(EFAULT); +#endif if (pfr_validate_addr(&ad)) senderr(EINVAL); p = pfr_lookup_addr(kt, &ad, 1); if (flags & PFR_FLAG_FEEDBACK) { ad.pfra_fback = (p != NULL) ? PFR_FB_CLEARED : PFR_FB_NONE; - if (COPYOUT(&ad, addr+i, sizeof(ad))) +#ifdef __FreeBSD__ + PF_COPYOUT(&ad, addr+i, sizeof(ad), ec); + if (ec) + senderr(EFAULT); +#else + if (copyout(&ad, addr+i, sizeof(ad))) senderr(EFAULT); +#endif } if (p != NULL) { SLIST_INSERT_HEAD(&workq, p, pfrke_workq); @@ -656,7 +781,7 @@ pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size, return (0); _bad: if (flags & PFR_FLAG_FEEDBACK) - pfr_reset_feedback(addr, size, flags); + pfr_reset_feedback(addr, size); return (rv); } @@ -701,10 +826,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; @@ -717,9 +852,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"); } @@ -743,7 +886,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; @@ -833,10 +982,10 @@ void pfr_clean_node_mask(struct pfr_ktable *kt, struct pfr_kentryworkq *workq) { - struct pfr_kentry *p; + struct pfr_kentry *p; - SLIST_FOREACH(p, workq, pfrke_workq) - pfr_unroute_kentry(kt, p); + SLIST_FOREACH(p, workq, pfrke_workq) + pfr_unroute_kentry(kt, p); } void @@ -857,17 +1006,32 @@ pfr_clstats_kentries(struct pfr_kentryworkq *workq, long tzero, int negchange) } void -pfr_reset_feedback(struct pfr_addr *addr, int size, int flags) +pfr_reset_feedback(struct pfr_addr *addr, int size) { struct pfr_addr ad; int i; +#ifdef __FreeBSD__ + int ec; +#endif for (i = 0; i < size; i++) { - if (COPYIN(addr+i, &ad, sizeof(ad))) +#ifdef __FreeBSD__ + PF_COPYIN(addr+i, &ad, sizeof(ad), ec); + if (ec) + break; +#else + if (copyin(addr+i, &ad, sizeof(ad))) break; +#endif ad.pfra_fback = PFR_FB_NONE; - if (COPYOUT(&ad, addr+i, sizeof(ad))) +#ifdef __FreeBSD__ + PF_COPYOUT(&ad, addr+i, sizeof(ad), ec); + if (ec) break; +#else + if (copyout(&ad, addr+i, sizeof(ad))) + break; +#endif } } @@ -911,11 +1075,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); @@ -935,11 +1105,17 @@ 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); rn = rn_delete(&ke->pfrke_sa, &mask, head); } else rn = rn_delete(&ke->pfrke_sa, NULL, head); +#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100) + RADIX_NODE_HEAD_UNLOCK(head); +#endif splx(s); if (rn == NULL) { @@ -969,7 +1145,10 @@ pfr_walktree(struct radix_node *rn, void *arg) { struct pfr_kentry *ke = (struct pfr_kentry *)rn; struct pfr_walktree *w = arg; - int s, flags = w->pfrw_flags; + int s; +#ifdef __FreeBSD__ + int ec; +#endif switch (w->pfrw_op) { case PFRW_MARK: @@ -978,7 +1157,7 @@ pfr_walktree(struct radix_node *rn, void *arg) case PFRW_SWEEP: if (ke->pfrke_mark) break; - /* FALLTHROUGH */ + /* fall trough */ case PFRW_ENQUEUE: SLIST_INSERT_HEAD(w->pfrw_workq, ke, pfrke_workq); w->pfrw_cnt++; @@ -988,8 +1167,14 @@ pfr_walktree(struct radix_node *rn, void *arg) struct pfr_addr ad; pfr_copyout_addr(&ad, ke); +#ifdef __FreeBSD__ + PF_COPYOUT(&ad, w->pfrw_addr, sizeof(ad), ec); + if (ec) + return (EFAULT); +#else if (copyout(&ad, w->pfrw_addr, sizeof(ad))) return (EFAULT); +#endif w->pfrw_addr++; } break; @@ -1007,8 +1192,14 @@ pfr_walktree(struct radix_node *rn, void *arg) splx(s); as.pfras_tzero = ke->pfrke_tzero; - if (COPYOUT(&as, w->pfrw_astats, sizeof(as))) +#ifdef __FreeBSD__ + PF_COPYOUT(&as, w->pfrw_astats, sizeof(as), ec); + if (ec) return (EFAULT); +#else + if (copyout(&as, w->pfrw_astats, sizeof(as))) + return (EFAULT); +#endif w->pfrw_astats++; } break; @@ -1020,25 +1211,6 @@ pfr_walktree(struct radix_node *rn, void *arg) return (1); /* finish search */ } break; - case PFRW_DYNADDR_UPDATE: - if (ke->pfrke_af == AF_INET) { - if (w->pfrw_dyn->pfid_acnt4++ > 0) - break; - pfr_prepare_network(&pfr_mask, AF_INET, ke->pfrke_net); - w->pfrw_dyn->pfid_addr4 = *SUNION2PF( - &ke->pfrke_sa, AF_INET); - w->pfrw_dyn->pfid_mask4 = *SUNION2PF( - &pfr_mask, AF_INET); - } else { - if (w->pfrw_dyn->pfid_acnt6++ > 0) - break; - pfr_prepare_network(&pfr_mask, AF_INET6, ke->pfrke_net); - w->pfrw_dyn->pfid_addr6 = *SUNION2PF( - &ke->pfrke_sa, AF_INET6); - w->pfrw_dyn->pfid_mask6 = *SUNION2PF( - &pfr_mask, AF_INET6); - } - break; } return (0); } @@ -1058,8 +1230,6 @@ pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags) RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { if (pfr_skip_table(filter, p, flags)) continue; - if (!strcmp(p->pfrkt_anchor, PF_RESERVED_ANCHOR)) - continue; if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE)) continue; p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_ACTIVE; @@ -1084,16 +1254,29 @@ 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; +#ifdef __FreeBSD__ + int ec; + /* + * XXX Is it OK under LP64 environments? + */ + long tzero = (long)time_second; +#else long tzero = time.tv_sec; +#endif ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); SLIST_INIT(&addq); SLIST_INIT(&changeq); for (i = 0; i < size; i++) { - if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t))) +#ifdef __FreeBSD__ + PF_COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), ec); + if (ec) + senderr(EFAULT); +#else + if (copyin(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t))) senderr(EFAULT); - if (pfr_validate_table(&key.pfrkt_t, PFR_TFLAG_USRMASK, - flags & PFR_FLAG_USERIOCTL)) +#endif + if (pfr_validate_table(&key.pfrkt_t, PFR_TFLAG_USRMASK)) senderr(EINVAL); key.pfrkt_flags |= PFR_TFLAG_ACTIVE; p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); @@ -1165,14 +1348,22 @@ 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; +#ifdef __FreeBSD__ + int ec; +#endif ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); SLIST_INIT(&workq); for (i = 0; i < size; i++) { - if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t))) +#ifdef __FreeBSD__ + PF_COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), ec); + if (ec) + return (EFAULT); +#else + if (copyin(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t))) return (EFAULT); - if (pfr_validate_table(&key.pfrkt_t, 0, - flags & PFR_FLAG_USERIOCTL)) +#endif + if (pfr_validate_table(&key.pfrkt_t, 0)) return (EINVAL); p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) { @@ -1205,6 +1396,9 @@ pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size, { struct pfr_ktable *p; int n, nn; +#ifdef __FreeBSD__ + int ec; +#endif ACCEPT_FLAGS(PFR_FLAG_ALLRSETS); n = nn = pfr_table_count(filter, flags); @@ -1219,8 +1413,14 @@ pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size, continue; if (n-- <= 0) continue; - if (COPYOUT(&p->pfrkt_t, tbl++, sizeof(*tbl))) +#ifdef __FreeBSD__ + PF_COPYOUT(&p->pfrkt_t, tbl++, sizeof(*tbl), ec); + if (ec) return (EFAULT); +#else + if (copyout(&p->pfrkt_t, tbl++, sizeof(*tbl))) + return (EFAULT); +#endif } if (n) { printf("pfr_get_tables: corruption detected (%d).\n", n); @@ -1237,7 +1437,15 @@ 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; +#ifdef __FreeBSD__ + int ec; + /* + * XXX Is it OK under LP64 environments? + */ + long tzero = (long)time_second; +#else long tzero = time.tv_sec; +#endif ACCEPT_FLAGS(PFR_FLAG_ATOMIC|PFR_FLAG_ALLRSETS); /* XXX PFR_FLAG_CLSTATS disabled */ @@ -1258,10 +1466,18 @@ pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, continue; if (!(flags & PFR_FLAG_ATOMIC)) s = splsoftnet(); - if (COPYOUT(&p->pfrkt_ts, tbl++, sizeof(*tbl))) { +#ifdef __FreeBSD__ + PF_COPYOUT(&p->pfrkt_ts, tbl++, sizeof(*tbl), ec); + if (ec) { + splx(s); + return (EFAULT); + } +#else + if (copyout(&p->pfrkt_ts, tbl++, sizeof(*tbl))) { splx(s); return (EFAULT); } +#endif if (!(flags & PFR_FLAG_ATOMIC)) splx(s); SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); @@ -1285,14 +1501,28 @@ 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; +#ifdef __FreeBSD__ + int ec; + /* + * XXX Is it OK under LP64 environments? + */ + long tzero = (long)time_second; +#else long tzero = time.tv_sec; +#endif ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_ADDRSTOO); SLIST_INIT(&workq); for (i = 0; i < size; i++) { - if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t))) +#ifdef __FreeBSD__ + PF_COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), ec); + if (ec) + return (EFAULT); +#else + if (copyin(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t))) return (EFAULT); - if (pfr_validate_table(&key.pfrkt_t, 0, 0)) +#endif + if (pfr_validate_table(&key.pfrkt_t, 0)) return (EINVAL); p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); if (p != NULL) { @@ -1319,6 +1549,9 @@ 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; +#ifdef __FreeBSD__ + int ec; +#endif ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); if ((setflag & ~PFR_TFLAG_USRMASK) || @@ -1327,10 +1560,15 @@ pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag, return (EINVAL); SLIST_INIT(&workq); for (i = 0; i < size; i++) { - if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t))) +#ifdef __FreeBSD__ + PF_COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), ec); + if (ec) + return (EFAULT); +#else + if (copyin(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t))) return (EFAULT); - if (pfr_validate_table(&key.pfrkt_t, 0, - flags & PFR_FLAG_USERIOCTL)) +#endif + if (pfr_validate_table(&key.pfrkt_t, 0)) return (EINVAL); p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) { @@ -1410,12 +1648,14 @@ pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfr_addr ad; struct pf_ruleset *rs; int i, rv, xadd = 0, xaddr = 0; +#ifdef __FreeBSD__ + int ec; +#endif ACCEPT_FLAGS(PFR_FLAG_DUMMY|PFR_FLAG_ADDRSTOO); if (size && !(flags & PFR_FLAG_ADDRSTOO)) return (EINVAL); - if (pfr_validate_table(tbl, PFR_TFLAG_USRMASK, - flags & PFR_FLAG_USERIOCTL)) + if (pfr_validate_table(tbl, PFR_TFLAG_USRMASK)) return (EINVAL); rs = pf_find_ruleset(tbl->pfrt_anchor, tbl->pfrt_ruleset); if (rs == NULL || !rs->topen || ticket != rs->tticket) @@ -1457,8 +1697,14 @@ _skip: } SLIST_INIT(&addrq); for (i = 0; i < size; i++) { - if (COPYIN(addr+i, &ad, sizeof(ad))) +#ifdef __FreeBSD__ + PF_COPYIN(addr+i, &ad, sizeof(ad), ec); + if (ec) senderr(EFAULT); +#else + if (copyin(addr+i, &ad, sizeof(ad))) + senderr(EFAULT); +#endif if (pfr_validate_addr(&ad)) senderr(EINVAL); if (pfr_lookup_addr(shadow, &ad, 1) != NULL) @@ -1500,37 +1746,6 @@ _bad: } int -pfr_ina_rollback(struct pfr_table *trs, u_int32_t ticket, int *ndel, int flags) -{ - struct pfr_ktableworkq workq; - struct pfr_ktable *p; - struct pf_ruleset *rs; - int xdel = 0; - - ACCEPT_FLAGS(PFR_FLAG_DUMMY); - rs = pf_find_ruleset(trs->pfrt_anchor, trs->pfrt_ruleset); - if (rs == NULL || !rs->topen || ticket != rs->tticket) - return (0); - SLIST_INIT(&workq); - RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { - if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) || - pfr_skip_table(trs, p, 0)) - continue; - p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE; - SLIST_INSERT_HEAD(&workq, p, pfrkt_workq); - xdel++; - } - if (!(flags & PFR_FLAG_DUMMY)) { - pfr_setflags_ktables(&workq); - rs->topen = 0; - pf_remove_if_empty_ruleset(rs); - } - if (ndel != NULL) - *ndel = xdel; - return (0); -} - -int pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd, int *nchange, int flags) { @@ -1538,7 +1753,14 @@ pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd, struct pfr_ktableworkq workq; struct pf_ruleset *rs; int s, xadd = 0, xchange = 0; +#ifdef __FreeBSD__ + /* + * XXX Is it OK under LP64 environments? + */ + long tzero = (long)time_second; +#else long tzero = time.tv_sec; +#endif ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); rs = pf_find_ruleset(trs->pfrt_anchor, trs->pfrt_ruleset); @@ -1635,14 +1857,12 @@ pfr_commit_ktable(struct pfr_ktable *kt, long tzero) } int -pfr_validate_table(struct pfr_table *tbl, int allowedflags, int no_reserved) +pfr_validate_table(struct pfr_table *tbl, int allowedflags) { int i; if (!tbl->pfrt_name[0]) return (-1); - if (no_reserved && !strcmp(tbl->pfrt_anchor, PF_RESERVED_ANCHOR)) - return (-1); if (tbl->pfrt_name[PF_TABLE_NAME_SIZE-1]) return (-1); for (i = strlen(tbl->pfrt_name); i < PF_TABLE_NAME_SIZE; i++) @@ -1835,10 +2055,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) { @@ -1860,16 +2091,15 @@ pfr_ktable_compare(struct pfr_ktable *p, struct pfr_ktable *q) if ((d = strncmp(p->pfrkt_anchor, q->pfrkt_anchor, PF_ANCHOR_NAME_SIZE))) return (d); - return (strncmp(p->pfrkt_ruleset, q->pfrkt_ruleset, - PF_RULESET_NAME_SIZE)); + return strncmp(p->pfrkt_ruleset, q->pfrkt_ruleset, + PF_RULESET_NAME_SIZE); } struct pfr_ktable * pfr_lookup_table(struct pfr_table *tbl) { /* struct pfr_ktable start like a struct pfr_table */ - return (RB_FIND(pfr_ktablehead, &pfr_ktables, - (struct pfr_ktable *)tbl)); + return RB_FIND(pfr_ktablehead, &pfr_ktables, (struct pfr_ktable *)tbl); } int @@ -1881,7 +2111,7 @@ pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af) if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) kt = kt->pfrkt_root; if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) - return (0); + return 0; switch (af) { case AF_INET: @@ -1958,7 +2188,14 @@ pfr_attach_table(struct pf_ruleset *rs, char *name) } kt = pfr_lookup_table(&tbl); if (kt == NULL) { +#ifdef __FreeBSD__ + /* + * XXX Is it OK under LP64 environments? + */ + kt = pfr_create_ktable(&tbl, (long)time_second, 1); +#else kt = pfr_create_ktable(&tbl, time.tv_sec, 1); +#endif if (kt == NULL) return (NULL); if (ac != NULL) { @@ -1979,7 +2216,7 @@ pfr_attach_table(struct pf_ruleset *rs, char *name) } if (!kt->pfrkt_refcnt[PFR_REFCNT_RULE]++) pfr_setflags_ktable(kt, kt->pfrkt_flags|PFR_TFLAG_REFERENCED); - return (kt); + return kt; } void @@ -1992,6 +2229,7 @@ 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) @@ -2045,7 +2283,7 @@ _next_block: } for (;;) { /* we don't want to use a nested block */ - ke2 = (struct pfr_kentry *)(af == AF_INET ? + ke2 = (struct pfr_kentry *)(af == AF_INET ? rn_match(&pfr_sin, kt->pfrkt_ip4) : rn_match(&pfr_sin6, kt->pfrkt_ip6)); /* no need to check KENTRY_RNF_ROOT() here */ @@ -2075,38 +2313,26 @@ pfr_kentry_byidx(struct pfr_ktable *kt, int idx, int af) { struct pfr_walktree w; - bzero(&w, sizeof(w)); - w.pfrw_op = PFRW_POOL_GET; - w.pfrw_cnt = idx; + bzero(&w, sizeof(w)); + w.pfrw_op = PFRW_POOL_GET; + w.pfrw_cnt = idx; - switch (af) { + switch(af) { 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); - return (w.pfrw_kentry); +#endif + return w.pfrw_kentry; 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); - return (w.pfrw_kentry); +#endif + return w.pfrw_kentry; default: - return (NULL); + return NULL; } } - -void -pfr_dynaddr_update(struct pfr_ktable *kt, struct pfi_dynaddr *dyn) -{ - struct pfr_walktree w; - int s; - - bzero(&w, sizeof(w)); - w.pfrw_op = PFRW_DYNADDR_UPDATE; - w.pfrw_dyn = dyn; - - s = splsoftnet(); - dyn->pfid_acnt4 = 0; - dyn->pfid_acnt6 = 0; - if (!dyn->pfid_af || dyn->pfid_af == AF_INET) - rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w); - if (!dyn->pfid_af || dyn->pfid_af == AF_INET6) - rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w); - splx(s); -} diff --git a/sys/contrib/pf/net/pfvar.h b/sys/contrib/pf/net/pfvar.h index d3dda46..9012227 100644 --- a/sys/contrib/pf/net/pfvar.h +++ b/sys/contrib/pf/net/pfvar.h @@ -1,4 +1,5 @@ -/* $OpenBSD: pfvar.h,v 1.187 2004/03/22 04:54:18 mcbride Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: pfvar.h,v 1.170 2003/08/22 21:50:34 david Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -38,7 +39,26 @@ #include <sys/tree.h> #include <net/radix.h> +#ifdef __FreeBSD__ +#include <vm/uma.h> +#else #include <netinet/ip_ipsp.h> +#endif + +#ifdef __FreeBSD__ +#include <netinet/in.h> +/* + * XXX + * If we include <netipsec/keydb.h>, we need _KERNEL definition. + * This makes pfctl compilation difficult. + */ +union sockaddr_union { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; +}; +#endif + #include <netinet/tcp_fsm.h> struct ip; @@ -47,7 +67,6 @@ struct ip; #define PF_TCPS_PROXY_DST ((TCP_NSTATES)+1) enum { PF_INOUT, PF_IN, PF_OUT }; -enum { PF_LAN_EXT, PF_EXT_GWY, PF_ID }; enum { PF_PASS, PF_DROP, PF_SCRUB, PF_NAT, PF_NONAT, PF_BINAT, PF_NOBINAT, PF_RDR, PF_NORDR, PF_SYNPROXY_DROP }; enum { PF_RULESET_SCRUB, PF_RULESET_FILTER, PF_RULESET_NAT, @@ -68,17 +87,16 @@ enum { PFTM_TCP_FIRST_PACKET, PFTM_TCP_OPENING, PFTM_TCP_ESTABLISHED, PFTM_ICMP_FIRST_PACKET, PFTM_ICMP_ERROR_REPLY, PFTM_OTHER_FIRST_PACKET, PFTM_OTHER_SINGLE, PFTM_OTHER_MULTIPLE, PFTM_FRAG, PFTM_INTERVAL, - PFTM_ADAPTIVE_START, PFTM_ADAPTIVE_END, PFTM_SRC_NODE, - PFTM_MAX, PFTM_PURGE, PFTM_UNTIL_PACKET }; + PFTM_ADAPTIVE_START, PFTM_ADAPTIVE_END, PFTM_MAX, + PFTM_PURGE, PFTM_UNTIL_PACKET }; enum { PF_NOPFROUTE, PF_FASTROUTE, PF_ROUTETO, PF_DUPTO, PF_REPLYTO }; -enum { PF_LIMIT_STATES, PF_LIMIT_SRC_NODES, PF_LIMIT_FRAGS, PF_LIMIT_MAX }; +enum { PF_LIMIT_STATES, 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 }; #define PF_POOL_TYPEMASK 0x0f -#define PF_POOL_STICKYADDR 0x20 #define PF_WSCALE_FLAG 0x80 #define PF_WSCALE_MASK 0x0f @@ -99,12 +117,6 @@ struct pf_addr { #define PF_TABLE_NAME_SIZE 32 -#define PFI_AFLAG_NETWORK 0x01 -#define PFI_AFLAG_BROADCAST 0x02 -#define PFI_AFLAG_PEER 0x04 -#define PFI_AFLAG_MODEMASK 0x07 -#define PFI_AFLAG_NOALIAS 0x08 - struct pf_addr_wrap { union { struct { @@ -115,36 +127,93 @@ struct pf_addr_wrap { char tblname[PF_TABLE_NAME_SIZE]; } v; union { - struct pfi_dynaddr *dyn; + struct pf_addr_dyn *dyn; struct pfr_ktable *tbl; - int dyncnt; int tblcnt; } p; u_int8_t type; /* PF_ADDR_* */ - u_int8_t iflags; /* PFI_AFLAG_* */ }; #ifdef _KERNEL -struct pfi_dynaddr { - 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_* */ +struct pf_addr_dyn { + char ifname[IFNAMSIZ]; + struct ifnet *ifp; + struct pf_addr *addr; + sa_family_t af; +#ifdef __FreeBSD__ + eventhandler_tag hook_cookie; +#else + void *hook_cookie; +#endif + u_int8_t undefined; }; /* * 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 +#endif + #ifdef INET #ifndef INET6 #define PF_INET_ONLY @@ -281,7 +350,10 @@ struct pfi_dynaddr { ((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)->p.dyn->undefined || \ + (!PF_AZERO(&(aw)->v.a.mask, (af)) && \ + !PF_MATCHA(0, &(aw)->v.a.addr, \ + &(aw)->v.a.mask, (x), (af))))) || \ ((aw)->type == PF_ADDR_ADDRMASK && \ !PF_AZERO(&(aw)->v.a.mask, (af)) && \ !PF_MATCHA(0, &(aw)->v.a.addr, \ @@ -310,7 +382,7 @@ struct pf_pooladdr { struct pf_addr_wrap addr; TAILQ_ENTRY(pf_pooladdr) entries; char ifname[IFNAMSIZ]; - struct pfi_kif *kif; + struct ifnet *ifp; }; TAILQ_HEAD(pf_palist, pf_pooladdr); @@ -459,6 +531,7 @@ struct pf_rule { union pf_rule_ptr skip[PF_SKIP_COUNT]; #define PF_RULE_LABEL_SIZE 64 char label[PF_RULE_LABEL_SIZE]; + u_int32_t timeout[PFTM_MAX]; #define PF_QNAME_SIZE 16 char ifname[IFNAMSIZ]; char qname[PF_QNAME_SIZE]; @@ -476,17 +549,12 @@ struct pf_rule { u_int64_t packets; u_int64_t bytes; - struct pfi_kif *kif; + struct ifnet *ifp; struct pf_anchor *anchor; pf_osfp_t os_fingerprint; - - u_int32_t timeout[PFTM_MAX]; u_int32_t states; u_int32_t max_states; - u_int32_t src_nodes; - u_int32_t max_src_nodes; - u_int32_t max_src_states; u_int32_t qid; u_int32_t pqid; u_int32_t rt_listid; @@ -533,9 +601,6 @@ struct pf_rule { #define PFRULE_FRAGMENT 0x0002 #define PFRULE_RETURNICMP 0x0004 #define PFRULE_RETURN 0x0008 -#define PFRULE_NOSYNC 0x0010 -#define PFRULE_SRCTRACK 0x0020 /* track source states */ -#define PFRULE_RULESRCTRACK 0x0040 /* per rule */ /* scrub flags */ #define PFRULE_NODF 0x0100 @@ -544,28 +609,8 @@ struct pf_rule { #define PFRULE_RANDOMID 0x0800 #define PFRULE_REASSEMBLE_TCP 0x1000 -/* rule flags again */ -#define PFRULE_IFBOUND 0x00010000 /* if-bound */ -#define PFRULE_GRBOUND 0x00020000 /* group-bound */ - #define PFSTATE_HIWAT 10000 /* default state table size */ -struct pf_src_node { - RB_ENTRY(pf_src_node) entry; - struct pf_addr addr; - struct pf_addr raddr; - union pf_rule_ptr rule; - struct pfi_kif *kif; - u_int32_t bytes; - u_int32_t packets; - u_int32_t states; - u_int32_t creation; - u_int32_t expire; - sa_family_t af; - u_int8_t ruletype; -}; - -#define PFSNODE_HIWAT 10000 /* default source node table size */ struct pf_state_scrub { u_int16_t pfss_flags; @@ -592,20 +637,7 @@ struct pf_state_peer { struct pf_state_scrub *scrub; /* state is scrubbed */ }; -TAILQ_HEAD(pf_state_queue, pf_state); - struct pf_state { - u_int64_t id; - 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_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; @@ -615,25 +647,27 @@ struct pf_state { union pf_rule_ptr anchor; union pf_rule_ptr nat_rule; struct pf_addr rt_addr; - struct pfi_kif *rt_kif; - struct pf_src_node *src_node; - struct pf_src_node *nat_src_node; + struct ifnet *rt_ifp; 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; 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 - u_int8_t pad; + u_int8_t pad[2]; +}; + +struct pf_tree_node { + RB_ENTRY(pf_tree_node) entry; + struct pf_state *state; + struct pf_addr addr[2]; + u_int16_t port[2]; + sa_family_t af; + u_int8_t proto; }; TAILQ_HEAD(pf_rulequeue, pf_rule); @@ -649,7 +683,6 @@ struct pf_ruleset { struct { struct pf_rulequeue *ptr; u_int32_t ticket; - int open; } active, inactive; } rules[PF_RULESET_MAX]; struct pf_anchor *anchor; @@ -669,9 +702,6 @@ struct pf_anchor { TAILQ_HEAD(pf_anchorqueue, pf_anchor); -#define PF_RESERVED_ANCHOR "_pf" -#define PF_INTERFACE_RULESET "_if" - #define PFR_TFLAG_PERSIST 0x00000001 #define PFR_TFLAG_CONST 0x00000002 #define PFR_TFLAG_ACTIVE 0x00000004 @@ -758,13 +788,12 @@ struct pfr_ktable { struct pfr_ktable *pfrkt_shadow; struct pfr_ktable *pfrkt_root; struct pf_ruleset *pfrkt_rs; - long pfrkt_larg; int pfrkt_nflags; }; #define pfrkt_t pfrkt_ts.pfrts_t #define pfrkt_name pfrkt_t.pfrt_name -#define pfrkt_anchor pfrkt_t.pfrt_anchor -#define pfrkt_ruleset pfrkt_t.pfrt_ruleset +#define pfrkt_anchor pfrkt_t.pfrt_anchor +#define pfrkt_ruleset pfrkt_t.pfrt_ruleset #define pfrkt_flags pfrkt_t.pfrt_flags #define pfrkt_cnt pfrkt_ts.pfrts_cnt #define pfrkt_refcnt pfrkt_ts.pfrts_refcnt @@ -774,60 +803,6 @@ struct pfr_ktable { #define pfrkt_nomatch pfrkt_ts.pfrts_nomatch #define pfrkt_tzero pfrkt_ts.pfrts_tzero -RB_HEAD(pf_state_tree_lan_ext, pf_state); -RB_PROTOTYPE(pf_state_tree_lan_ext, pf_state, - u.s.entry_lan_ext, pf_state_compare_lan_ext); - -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); - -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 { - struct pfi_if pfik_if; - RB_ENTRY(pfi_kif) pfik_tree; - 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; - int pfik_states; - int pfik_rules; -}; -#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 */ - struct pf_pdesc { u_int64_t tot_len; /* Make Mickey money */ union { @@ -839,9 +814,6 @@ struct pf_pdesc { #endif /* INET6 */ void *any; } hdr; - struct pf_addr baddr; /* address before translation */ - struct pf_addr naddr; /* address after translation */ - struct pf_rule *nat_rule; /* nat/rdr rule applied to packet */ struct pf_addr *src; struct pf_addr *dst; u_int16_t *ip_sum; @@ -910,10 +882,6 @@ struct pf_pdesc { #define FCNT_STATE_REMOVALS 2 #define FCNT_MAX 3 -#define SCNT_SRC_NODE_SEARCH 0 -#define SCNT_SRC_NODE_INSERT 1 -#define SCNT_SRC_NODE_REMOVALS 2 -#define SCNT_MAX 3 #define ACTION_SET(a, x) \ do { \ @@ -932,16 +900,12 @@ struct pf_pdesc { struct pf_status { u_int64_t counters[PFRES_MAX]; u_int64_t fcounters[FCNT_MAX]; - u_int64_t scounters[SCNT_MAX]; u_int64_t pcounters[2][2][3]; u_int64_t bcounters[2][2]; - u_int64_t stateid; u_int32_t running; u_int32_t states; - u_int32_t src_nodes; u_int32_t since; u_int32_t debug; - u_int32_t hostid; char ifname[IFNAMSIZ]; }; @@ -1073,7 +1037,6 @@ struct pfioc_state_kill { int psk_proto; struct pf_rule_addr psk_src; struct pf_rule_addr psk_dst; - char psk_ifname[IFNAMSIZ]; }; struct pfioc_states { @@ -1086,16 +1049,6 @@ struct pfioc_states { #define ps_states ps_u.psu_states }; -struct pfioc_src_nodes { - int psn_len; - union { - caddr_t psu_buf; - struct pf_src_node *psu_src_nodes; - } psn_u; -#define psn_buf psn_u.psu_buf -#define psn_src_nodes psn_u.psu_src_nodes -}; - struct pfioc_if { char ifname[IFNAMSIZ]; }; @@ -1136,19 +1089,6 @@ struct pfioc_ruleset { char name[PF_RULESET_NAME_SIZE]; }; -#define PF_RULESET_ALTQ (PF_RULESET_MAX) -#define PF_RULESET_TABLE (PF_RULESET_MAX+1) -struct pfioc_trans { - int size; /* number of elements */ - int esize; /* size of each element in bytes */ - struct pfioc_trans_e { - int rs_num; - char anchor[PF_ANCHOR_NAME_SIZE]; - char ruleset[PF_RULESET_NAME_SIZE]; - u_int32_t ticket; - } *array; -}; - #define PFR_FLAG_ATOMIC 0x00000001 #define PFR_FLAG_DUMMY 0x00000002 #define PFR_FLAG_FEEDBACK 0x00000004 @@ -1157,9 +1097,6 @@ struct pfioc_trans { #define PFR_FLAG_REPLACE 0x00000020 #define PFR_FLAG_ALLRSETS 0x00000040 #define PFR_FLAG_ALLMASK 0x0000007F -#ifdef _KERNEL -#define PFR_FLAG_USERIOCTL 0x10000000 -#endif struct pfioc_table { struct pfr_table pfrio_table; @@ -1181,20 +1118,6 @@ struct pfioc_table { #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; - int pfiio_esize; - int pfiio_size; - int pfiio_nzero; - int pfiio_flags; -}; - - /* * ioctl operations */ @@ -1207,7 +1130,7 @@ struct pfioc_iface { #define DIOCGETRULES _IOWR('D', 6, struct pfioc_rule) #define DIOCGETRULE _IOWR('D', 7, struct pfioc_rule) /* XXX cut 8 - 17 */ -#define DIOCCLRSTATES _IOWR('D', 18, struct pfioc_state_kill) +#define DIOCCLRSTATES _IO ('D', 18) #define DIOCGETSTATE _IOWR('D', 19, struct pfioc_state) #define DIOCSETSTATUSIF _IOWR('D', 20, struct pfioc_if) #define DIOCGETSTATUS _IOWR('D', 21, struct pf_status) @@ -1263,38 +1186,30 @@ struct pfioc_iface { #define DIOCOSFPFLUSH _IO('D', 78) #define DIOCOSFPADD _IOWR('D', 79, struct pf_osfp_ioctl) #define DIOCOSFPGET _IOWR('D', 80, struct pf_osfp_ioctl) -#define DIOCXBEGIN _IOWR('D', 81, struct pfioc_trans) -#define DIOCXCOMMIT _IOWR('D', 82, struct pfioc_trans) -#define DIOCXROLLBACK _IOWR('D', 83, struct pfioc_trans) -#define DIOCGETSRCNODES _IOWR('D', 84, struct pfioc_src_nodes) -#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) +#ifdef __FreeBSD__ +struct pf_ifspeed { + char ifname[IFNAMSIZ]; + u_int32_t baudrate; +}; +#define DIOCGIFSPEED _IOWR('D', 81, struct pf_ifspeed) +#endif #ifdef _KERNEL -RB_HEAD(pf_src_tree, pf_src_node); -RB_PROTOTYPE(pf_src_tree, pf_src_node, entry, pf_src_compare); -extern struct pf_src_tree tree_src_tracking; - -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_updates; - -extern struct pf_anchorqueue pf_anchors; -extern struct pf_ruleset pf_main_ruleset; +RB_HEAD(pf_state_tree, pf_tree_node); +RB_PROTOTYPE(pf_state_tree, pf_tree_node, entry, pf_state_compare); +extern struct pf_state_tree tree_lan_ext, tree_ext_gwy; + +extern struct pf_anchorqueue pf_anchors; +extern struct pf_ruleset pf_main_ruleset; TAILQ_HEAD(pf_poolqueue, pf_pool); -extern struct pf_poolqueue pf_pools[2]; +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 struct pf_altqqueue pf_altqs[2]; +extern struct pf_palist pf_pabuf; + extern u_int32_t ticket_altqs_active; extern u_int32_t ticket_altqs_inactive; -extern int altqs_inactive_open; extern u_int32_t ticket_pabuf; extern struct pf_altqqueue *pf_altqs_active; extern struct pf_altqqueue *pf_altqs_inactive; @@ -1304,32 +1219,37 @@ extern int pf_tbladdr_setup(struct pf_ruleset *, struct pf_addr_wrap *); extern void pf_tbladdr_remove(struct pf_addr_wrap *); extern void pf_tbladdr_copyout(struct pf_addr_wrap *); +extern int pf_dynaddr_setup(struct pf_addr_wrap *, + sa_family_t); +extern void pf_dynaddr_copyout(struct pf_addr_wrap *); +extern void pf_dynaddr_remove(struct pf_addr_wrap *); extern void pf_calc_skip_steps(struct pf_rulequeue *); +extern void pf_rule_set_qid(struct pf_rulequeue *); +extern u_int32_t pf_qname_to_qid(char *); extern void pf_update_anchor_rules(void); -extern struct pool pf_src_tree_pl, pf_rule_pl; +#ifdef __FreeBSD__ +extern uma_zone_t pf_tree_pl, pf_rule_pl, pf_addr_pl; +extern uma_zone_t pf_state_pl, pf_altq_pl, pf_pooladdr_pl; +extern uma_zone_t pfr_ktable_pl, pfr_kentry_pl; +extern uma_zone_t pf_cache_pl, pf_cent_pl; +extern uma_zone_t pf_state_scrub_pl; +#else +extern struct pool pf_tree_pl, pf_rule_pl, pf_addr_pl; extern struct pool pf_state_pl, pf_altq_pl, pf_pooladdr_pl; extern struct pool pf_state_scrub_pl; +#endif extern void pf_purge_timeout(void *); -extern void pf_purge_expired_src_nodes(void); extern void pf_purge_expired_states(void); -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 *); -extern struct pf_state *pf_find_state_all(struct pf_state *key, - u_int8_t tree, int *more); +extern int pf_insert_state(struct pf_state *); +extern struct pf_state *pf_find_state(struct pf_state_tree *, + struct pf_tree_node *); extern struct pf_anchor *pf_find_anchor(const char *); extern struct pf_ruleset *pf_find_ruleset(char *, char *); -extern struct pf_ruleset *pf_find_or_create_ruleset( - char[PF_ANCHOR_NAME_SIZE], - char[PF_RULESET_NAME_SIZE]); +extern struct pf_ruleset *pf_find_or_create_ruleset(char *, char *); extern void pf_remove_if_empty_ruleset( struct pf_ruleset *); -extern struct ifnet *sync_ifp; +extern struct ifnet *status_ifp; extern struct pf_rule pf_default_rule; extern void pf_addrcpy(struct pf_addr *, struct pf_addr *, u_int8_t); @@ -1350,7 +1270,7 @@ void pf_addr_inc(struct pf_addr *, sa_family_t); 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, +int pflog_packet(struct ifnet *, struct mbuf *, sa_family_t, u_int8_t, 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); @@ -1360,9 +1280,9 @@ int pf_match_uid(u_int8_t, uid_t, uid_t, uid_t); int pf_match_gid(u_int8_t, gid_t, gid_t, gid_t); void pf_normalize_init(void); -int pf_normalize_ip(struct mbuf **, int, struct pfi_kif *, u_short *); -int pf_normalize_ip6(struct mbuf **, int, struct pfi_kif *, u_short *); -int pf_normalize_tcp(int, struct pfi_kif *, struct mbuf *, int, int, void *, +int pf_normalize_ip(struct mbuf **, int, struct ifnet *, u_short *); +int pf_normalize_ip6(struct mbuf **, int, struct ifnet *, u_short *); +int pf_normalize_tcp(int, struct ifnet *, struct mbuf *, int, int, void *, struct pf_pdesc *); void pf_normalize_tcp_cleanup(struct pf_state *); int pf_normalize_tcp_init(struct mbuf *, int, struct pf_pdesc *, @@ -1380,7 +1300,6 @@ void pfr_update_stats(struct pfr_ktable *, struct pf_addr *, sa_family_t, u_int64_t, int, int, int); int pfr_pool_get(struct pfr_ktable *, int *, struct pf_addr *, struct pf_addr **, struct pf_addr **, sa_family_t); -void pfr_dynaddr_update(struct pfr_ktable *, struct pfi_dynaddr *); struct pfr_ktable * pfr_attach_table(struct pf_ruleset *, char *); void pfr_detach_table(struct pfr_ktable *); @@ -1405,43 +1324,22 @@ int pfr_clr_astats(struct pfr_table *, struct pfr_addr *, int, int *, int pfr_tst_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int); int pfr_ina_begin(struct pfr_table *, u_int32_t *, int *, int); -int pfr_ina_rollback(struct pfr_table *, u_int32_t, int *, int); 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); -void pfi_initialize(void); -void pfi_attach_clone(struct if_clone *); -void pfi_attach_ifnet(struct ifnet *); -void pfi_detach_ifnet(struct ifnet *); -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_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 *, int); -int pfi_get_ifaces(const char *, struct pfi_if *, int *, int); -int pfi_match_addr(struct pfi_dynaddr *, struct pf_addr *, - sa_family_t); - -extern struct pfi_statehead pfi_statehead; - u_int16_t pf_tagname2tag(char *); void pf_tag2tagname(u_int16_t, char *); 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; +#endif struct pf_pool_limit { void *pp; @@ -1449,6 +1347,38 @@ struct pf_pool_limit { }; extern struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX]; +#ifdef __FreeBSD__ +struct pf_frent { + LIST_ENTRY(pf_frent) fr_next; + struct ip *fr_ip; + struct mbuf *fr_m; +}; + +struct pf_frcache { + LIST_ENTRY(pf_frcache) fr_next; + uint16_t fr_off; + uint16_t fr_end; +}; + +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 */ /* The fingerprint functions can be linked into userland programs (tcpdump) */ @@ -1462,7 +1392,12 @@ struct pf_osfp_enlist * 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..ca2256f 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 $ */ @@ -72,6 +73,39 @@ #include <netinet/ip.h> #include <netinet/ip_var.h> +#if defined(__FreeBSD__) && defined(__i386__) +/* + * Copied from FreeBSD 5.0 sys/i386/i386/in_cksum.c + * XXX + * Currently support I386 processor only. + * In the long run, we need an optimized cksum routines for each Tier1 + * architecture. Due to the lack of available hardware except I386 I + * can't support other processors now. For those users which use Sparc64, + * Alpha processors can use more optimized version in FreeBSD. + * See sys/$ARCH/$ARCH/in_cksum.c where $ARCH=`uname -p` + */ + +/* + * These asm statements require __volatile because they pass information + * via the condition codes. GCC does not currently provide a way to specify + * the condition codes as an input or output operand. + * + * The LOAD macro below is effectively a prefetch into cache. GCC will + * load the value into a register but will not use it. Since modern CPUs + * reorder operations, this will generally take place in parallel with + * other calculations. + */ +#define ADD(n) __asm __volatile \ + ("addl %1, %0" : "+r" (sum) : \ + "g" (((const u_int32_t *)w)[n / 4])) +#define ADDC(n) __asm __volatile \ + ("adcl %1, %0" : "+r" (sum) : \ + "g" (((const u_int32_t *)w)[n / 4])) +#define LOAD(n) __asm __volatile \ + ("" : : "r" (((const u_int32_t *)w)[n / 4])) +#define MOP __asm __volatile \ + ("adcl $0, %0" : "+r" (sum)) +#endif /* * Checksum routine for Internet Protocol family headers (Portable Version). * This is only for IPv4 pseudo header checksum. @@ -86,6 +120,11 @@ #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);} +#if defined(__FreeBSD__) +int +in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len); +#endif + int in4_cksum(m, nxt, off, len) struct mbuf *m; @@ -158,6 +197,134 @@ in4_cksum(m, nxt, off, len) if (len < mlen) mlen = len; len -= mlen; +#if defined(__FreeBSD__) && defined(__i386__) + /* + * Force to long boundary so we do longword aligned + * memory operations + */ + if (3 & (int) w) { + REDUCE; + if ((1 & (int) w) && (mlen > 0)) { + sum <<= 8; + s_util.c[0] = *(char *)w; + w = (u_short *)((char *)w + 1); + mlen--; + byte_swapped = 1; + } + if ((2 & (int) w) && (mlen >= 2)) { + sum += *w++; + mlen -= 2; + } + } + /* + * Advance to a 486 cache line boundary. + */ + if (4 & (int) w && mlen >= 4) { + ADD(0); + MOP; + w += 2; + mlen -= 4; + } + if (8 & (int) w && mlen >= 8) { + ADD(0); + ADDC(4); + MOP; + w += 4; + mlen -= 8; + } + /* + * Do as much of the checksum as possible 32 bits at at time. + * In fact, this loop is unrolled to make overhead from + * branches &c small. + */ + mlen -= 1; + while ((mlen -= 32) >= 0) { + /* + * Add with carry 16 words and fold in the last + * carry by adding a 0 with carry. + * + * The early ADD(16) and the LOAD(32) are to load + * the next 2 cache lines in advance on 486's. The + * 486 has a penalty of 2 clock cycles for loading + * a cache line, plus whatever time the external + * memory takes to load the first word(s) addressed. + * These penalties are unavoidable. Subsequent + * accesses to a cache line being loaded (and to + * other external memory?) are delayed until the + * whole load finishes. These penalties are mostly + * avoided by not accessing external memory for + * 8 cycles after the ADD(16) and 12 cycles after + * the LOAD(32). The loop terminates when mlen + * is initially 33 (not 32) to guaranteed that + * the LOAD(32) is within bounds. + */ + ADD(16); + ADDC(0); + ADDC(4); + ADDC(8); + ADDC(12); + LOAD(32); + ADDC(20); + ADDC(24); + ADDC(28); + MOP; + w += 16; + } + mlen += 32 + 1; + if (mlen >= 32) { + ADD(16); + ADDC(0); + ADDC(4); + ADDC(8); + ADDC(12); + ADDC(20); + ADDC(24); + ADDC(28); + MOP; + w += 16; + mlen -= 32; + } + if (mlen >= 16) { + ADD(0); + ADDC(4); + ADDC(8); + ADDC(12); + MOP; + w += 8; + mlen -= 16; + } + if (mlen >= 8) { + ADD(0); + ADDC(4); + MOP; + w += 4; + mlen -= 8; + } + if (mlen == 0 && byte_swapped == 0) + continue; /* worth 1% maybe ?? */ + REDUCE; + while ((mlen -= 2) >= 0) { + sum += *w++; + } + if (byte_swapped) { + REDUCE; + sum <<= 8; + byte_swapped = 0; + if (mlen == -1) { + s_util.c[1] = *(char *)w; + sum += s_util.s; + mlen = 0; + } else + mlen = -1; + } else if (mlen == -1) + /* + * This mbuf has odd number of bytes. + * There could be a word split betwen + * this mbuf and the next mbuf. + * Save the last byte (to prepend to next mbuf). + */ + s_util.c[0] = *(char *)w; +#else /* * Force to even boundary. */ @@ -204,6 +371,7 @@ in4_cksum(m, nxt, off, len) mlen = -1; } else if (mlen == -1) s_util.c[0] = *(u_int8_t *)w; +#endif } if (len) printf("cksum4: out of data\n"); |