aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Laier <mlaier@FreeBSD.org>2005-05-03 16:34:36 +0000
committerMax Laier <mlaier@FreeBSD.org>2005-05-03 16:34:36 +0000
commitf0d663ded81d0c3870cc52237084ec88468f909b (patch)
tree5c5c8efcde274d9bc07e7db215af08514c9d0a77
parent61ba182027cd9c23aaec075380e20e0e75ef5374 (diff)
downloadsrc-f0d663ded81d0c3870cc52237084ec88468f909b.tar.gz
src-f0d663ded81d0c3870cc52237084ec88468f909b.zip
Import pf from OpenBSD 3.7 (OPENBSD_3_7 as of today)vendor/pf-sys/3.7
Notes
Notes: svn path=/vendor-sys/pf/dist/; revision=145834 svn path=/vendor-sys/pf/3.7/; revision=145835; tag=vendor/pf-sys/3.7
-rw-r--r--sys/contrib/pf/net/if_pflog.c8
-rw-r--r--sys/contrib/pf/net/if_pflog.h9
-rw-r--r--sys/contrib/pf/net/if_pfsync.c306
-rw-r--r--sys/contrib/pf/net/if_pfsync.h59
-rw-r--r--sys/contrib/pf/net/pf.c1215
-rw-r--r--sys/contrib/pf/net/pf_if.c135
-rw-r--r--sys/contrib/pf/net/pf_ioctl.c914
-rw-r--r--sys/contrib/pf/net/pf_norm.c371
-rw-r--r--sys/contrib/pf/net/pf_osfp.c6
-rw-r--r--sys/contrib/pf/net/pf_table.c250
-rw-r--r--sys/contrib/pf/net/pfvar.h223
11 files changed, 2403 insertions, 1093 deletions
diff --git a/sys/contrib/pf/net/if_pflog.c b/sys/contrib/pf/net/if_pflog.c
index 3b93226a439e..41e1e6564713 100644
--- a/sys/contrib/pf/net/if_pflog.c
+++ b/sys/contrib/pf/net/if_pflog.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_pflog.c,v 1.11 2003/12/31 11:18:25 cedric Exp $ */
+/* $OpenBSD: if_pflog.c,v 1.12 2004/05/19 17:50:51 dhartmei Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
* Angelos D. Keromytis (kermit@csd.uch.gr) and
@@ -197,11 +197,9 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
} else {
hdr.rulenr = htonl(am->nr);
hdr.subrulenr = htonl(rm->nr);
- if (ruleset != NULL)
- memcpy(hdr.ruleset, ruleset->name,
+ if (ruleset != NULL && ruleset->anchor != NULL)
+ strlcpy(hdr.ruleset, ruleset->anchor->name,
sizeof(hdr.ruleset));
-
-
}
hdr.dir = dir;
diff --git a/sys/contrib/pf/net/if_pflog.h b/sys/contrib/pf/net/if_pflog.h
index e4e603e37303..7a43b10c215e 100644
--- a/sys/contrib/pf/net/if_pflog.h
+++ b/sys/contrib/pf/net/if_pflog.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_pflog.h,v 1.10 2004/03/19 04:52:04 frantzen Exp $ */
+/* $OpenBSD: if_pflog.h,v 1.11 2004/05/19 17:50:51 dhartmei Exp $ */
/*
* Copyright 2001 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -31,10 +31,7 @@ struct pflog_softc {
struct ifnet sc_if; /* the interface */
};
-/* XXX keep in sync with pfvar.h */
-#ifndef PF_RULESET_NAME_SIZE
-#define PF_RULESET_NAME_SIZE 16
-#endif
+#define PFLOG_RULESET_NAME_SIZE 16
struct pfloghdr {
u_int8_t length;
@@ -42,7 +39,7 @@ struct pfloghdr {
u_int8_t action;
u_int8_t reason;
char ifname[IFNAMSIZ];
- char ruleset[PF_RULESET_NAME_SIZE];
+ char ruleset[PFLOG_RULESET_NAME_SIZE];
u_int32_t rulenr;
u_int32_t subrulenr;
u_int8_t dir;
diff --git a/sys/contrib/pf/net/if_pfsync.c b/sys/contrib/pf/net/if_pfsync.c
index e4840ff32d97..d0f56d096a73 100644
--- a/sys/contrib/pf/net/if_pfsync.c
+++ b/sys/contrib/pf/net/if_pfsync.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_pfsync.c,v 1.26 2004/03/28 18:14:20 mcbride Exp $ */
+/* $OpenBSD: if_pfsync.c,v 1.46 2005/02/20 15:58:38 mcbride Exp $ */
/*
* Copyright (c) 2002 Michael Shalayeff
@@ -37,11 +37,14 @@
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/timeout.h>
+#include <sys/kernel.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/route.h>
#include <net/bpf.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_seq.h>
#ifdef INET
#include <netinet/in.h>
@@ -58,6 +61,11 @@
#include <netinet6/nd6.h>
#endif /* INET6 */
+#include "carp.h"
+#if NCARP > 0
+extern int carp_suppress_preempt;
+#endif
+
#include <net/pfvar.h>
#include <net/if_pfsync.h>
@@ -72,7 +80,6 @@ int pfsyncdebug;
#endif
struct pfsync_softc pfsyncif;
-int pfsync_sync_ok;
struct pfsyncstats pfsyncstats;
void pfsyncattach(int);
@@ -91,10 +98,8 @@ void pfsync_send_bus(struct pfsync_softc *, u_int8_t);
void pfsync_bulk_update(void *);
void pfsync_bulkfail(void *);
+int pfsync_sync_ok;
extern int ifqmaxlen;
-extern struct timeval time;
-extern struct timeval mono_time;
-extern int hz;
void
pfsyncattach(int npfsync)
@@ -108,6 +113,7 @@ pfsyncattach(int npfsync)
pfsyncif.sc_statep.s = NULL;
pfsyncif.sc_statep_net.s = NULL;
pfsyncif.sc_maxupdates = 128;
+ pfsyncif.sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
pfsyncif.sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
pfsyncif.sc_ureq_received = 0;
pfsyncif.sc_ureq_sent = 0;
@@ -193,6 +199,9 @@ pfsync_insert_net_state(struct pfsync_state *sp)
st->rule.ptr = r;
/* XXX get pointers to nat_rule and anchor */
+ /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */
+ r->states++;
+
/* fill in the rest of the state entry */
pf_state_host_ntoh(&sp->lan, &st->lan);
pf_state_host_ntoh(&sp->gwy, &st->gwy);
@@ -202,8 +211,8 @@ pfsync_insert_net_state(struct pfsync_state *sp)
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->creation = time_second - ntohl(sp->creation);
+ st->expire = ntohl(sp->expire) + time_second;
st->af = sp->af;
st->proto = sp->proto;
@@ -214,11 +223,13 @@ pfsync_insert_net_state(struct pfsync_state *sp)
bcopy(sp->id, &st->id, sizeof(st->id));
st->creatorid = sp->creatorid;
- st->sync_flags = sp->sync_flags | PFSTATE_FROMSYNC;
+ st->sync_flags = PFSTATE_FROMSYNC;
if (pf_insert_state(kif, st)) {
pfi_maybe_destroy(kif);
+ /* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */
+ r->states--;
pool_put(&pf_state_pl, st);
return (EINVAL);
}
@@ -241,7 +252,7 @@ pfsync_input(struct mbuf *m, ...)
struct pfsync_state_bus *bus;
struct in_addr src;
struct mbuf *mp;
- int iplen, action, error, i, s, count, offp;
+ int iplen, action, error, i, s, count, offp, sfail, stale = 0;
pfsyncstats.pfsyncs_ipackets++;
@@ -297,6 +308,7 @@ pfsync_input(struct mbuf *m, ...)
switch (action) {
case PFSYNC_ACT_CLR: {
+ struct pf_state *nexts;
struct pfi_kif *kif;
u_int32_t creatorid;
if ((mp = m_pulldown(m, iplen + sizeof(*ph),
@@ -309,9 +321,13 @@ pfsync_input(struct mbuf *m, ...)
s = splsoftnet();
if (cp->ifname[0] == '\0') {
- RB_FOREACH(st, pf_state_tree_id, &tree_id) {
- if (st->creatorid == creatorid)
+ for (st = RB_MIN(pf_state_tree_id, &tree_id);
+ st; st = nexts) {
+ nexts = RB_NEXT(pf_state_tree_id, &tree_id, st);
+ if (st->creatorid == creatorid) {
st->timeout = PFTM_PURGE;
+ pf_purge_expired_state(st);
+ }
}
} else {
kif = pfi_lookup_if(cp->ifname);
@@ -322,13 +338,16 @@ pfsync_input(struct mbuf *m, ...)
splx(s);
goto done;
}
- RB_FOREACH(st, pf_state_tree_lan_ext,
- &kif->pfik_lan_ext) {
- if (st->creatorid == creatorid)
+ for (st = RB_MIN(pf_state_tree_lan_ext,
+ &kif->pfik_lan_ext); st; st = nexts) {
+ nexts = RB_NEXT(pf_state_tree_lan_ext,
+ &kif->pfik_lan_ext, st);
+ if (st->creatorid == creatorid) {
st->timeout = PFTM_PURGE;
+ pf_purge_expired_state(st);
+ }
}
}
- pf_purge_expired_states();
splx(s);
break;
@@ -376,6 +395,8 @@ pfsync_input(struct mbuf *m, ...)
s = splsoftnet();
for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
i < count; i++, sp++) {
+ int flags = PFSYNC_FLAG_STALE;
+
/* check for invalid values */
if (sp->timeout >= PFTM_MAX ||
sp->src.state > PF_TCPS_PROXY_DST ||
@@ -397,12 +418,73 @@ pfsync_input(struct mbuf *m, ...)
pfsyncstats.pfsyncs_badstate++;
continue;
}
+ sfail = 0;
+ if (st->proto == IPPROTO_TCP) {
+ /*
+ * The state should never go backwards except
+ * for syn-proxy states. Neither should the
+ * sequence window slide backwards.
+ */
+ if (st->src.state > sp->src.state &&
+ (st->src.state < PF_TCPS_PROXY_SRC ||
+ sp->src.state >= PF_TCPS_PROXY_SRC))
+ sfail = 1;
+ else if (SEQ_GT(st->src.seqlo,
+ ntohl(sp->src.seqlo)))
+ sfail = 3;
+ else if (st->dst.state > sp->dst.state) {
+ /* There might still be useful
+ * information about the src state here,
+ * so import that part of the update,
+ * then "fail" so we send the updated
+ * state back to the peer who is missing
+ * our what we know. */
+ pf_state_peer_ntoh(&sp->src, &st->src);
+ /* XXX do anything with timeouts? */
+ sfail = 7;
+ flags = 0;
+ } else if (st->dst.state >= TCPS_SYN_SENT &&
+ SEQ_GT(st->dst.seqlo, ntohl(sp->dst.seqlo)))
+ sfail = 4;
+ } else {
+ /*
+ * Non-TCP protocol state machine always go
+ * forwards
+ */
+ if (st->src.state > sp->src.state)
+ sfail = 5;
+ else if ( st->dst.state > sp->dst.state)
+ sfail = 6;
+ }
+ if (sfail) {
+ if (pf_status.debug >= PF_DEBUG_MISC)
+ printf("pfsync: %s stale update "
+ "(%d) id: %016llx "
+ "creatorid: %08x\n",
+ (sfail < 7 ? "ignoring"
+ : "partial"), sfail,
+ betoh64(st->id),
+ ntohl(st->creatorid));
+ pfsyncstats.pfsyncs_badstate++;
+
+ if (!(sp->sync_flags & PFSTATE_STALE)) {
+ /* we have a better state, send it */
+ if (sc->sc_mbuf != NULL && !stale)
+ pfsync_sendout(sc);
+ stale++;
+ if (!st->sync_flags)
+ pfsync_pack_state(
+ PFSYNC_ACT_UPD, st, flags);
+ }
+ 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->expire = ntohl(sp->expire) + time_second;
st->timeout = sp->timeout;
-
}
+ if (stale && sc->sc_mbuf != NULL)
+ pfsync_sendout(sc);
splx(s);
break;
/*
@@ -427,15 +509,10 @@ pfsync_input(struct mbuf *m, ...)
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_state(st);
}
- pf_purge_expired_states();
splx(s);
break;
case PFSYNC_ACT_UPD_C: {
@@ -468,17 +545,71 @@ pfsync_input(struct mbuf *m, ...)
st = pf_find_state_byid(&key);
if (st == NULL) {
/* We don't have this state. Ask for it. */
- pfsync_request_update(up, &src);
+ error = pfsync_request_update(up, &src);
+ if (error == ENOMEM) {
+ splx(s);
+ goto done;
+ }
update_requested = 1;
pfsyncstats.pfsyncs_badstate++;
continue;
}
+ sfail = 0;
+ if (st->proto == IPPROTO_TCP) {
+ /*
+ * The state should never go backwards except
+ * for syn-proxy states. Neither should the
+ * sequence window slide backwards.
+ */
+ if (st->src.state > up->src.state &&
+ (st->src.state < PF_TCPS_PROXY_SRC ||
+ up->src.state >= PF_TCPS_PROXY_SRC))
+ sfail = 1;
+ else if (st->dst.state > up->dst.state)
+ sfail = 2;
+ else if (SEQ_GT(st->src.seqlo,
+ ntohl(up->src.seqlo)))
+ sfail = 3;
+ else if (st->dst.state >= TCPS_SYN_SENT &&
+ SEQ_GT(st->dst.seqlo, ntohl(up->dst.seqlo)))
+ sfail = 4;
+ } else {
+ /*
+ * Non-TCP protocol state machine always go
+ * forwards
+ */
+ if (st->src.state > up->src.state)
+ sfail = 5;
+ else if (st->dst.state > up->dst.state)
+ sfail = 6;
+ }
+ if (sfail) {
+ if (pf_status.debug >= PF_DEBUG_MISC)
+ printf("pfsync: ignoring stale update "
+ "(%d) id: %016llx "
+ "creatorid: %08x\n", sfail,
+ betoh64(st->id),
+ ntohl(st->creatorid));
+ pfsyncstats.pfsyncs_badstate++;
+
+ /* we have a better state, send it out */
+ if ((!stale || update_requested) &&
+ sc->sc_mbuf != NULL) {
+ pfsync_sendout(sc);
+ update_requested = 0;
+ }
+ stale++;
+ if (!st->sync_flags)
+ pfsync_pack_state(PFSYNC_ACT_UPD, st,
+ PFSYNC_FLAG_STALE);
+ 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->expire = ntohl(up->expire) + time_second;
st->timeout = up->timeout;
}
- if (update_requested)
+ if ((update_requested || stale) && sc->sc_mbuf)
pfsync_sendout(sc);
splx(s);
break;
@@ -501,15 +632,10 @@ pfsync_input(struct mbuf *m, ...)
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_state(st);
}
- pf_purge_expired_states();
splx(s);
break;
case PFSYNC_ACT_INS_F:
@@ -524,7 +650,6 @@ pfsync_input(struct mbuf *m, ...)
}
s = splsoftnet();
- /* XXX send existing. pfsync_pack_state should handle this. */
if (sc->sc_mbuf != NULL)
pfsync_sendout(sc);
for (i = 0,
@@ -534,7 +659,7 @@ pfsync_input(struct mbuf *m, ...)
key.creatorid = rup->creatorid;
if (key.id == 0 && key.creatorid == 0) {
- sc->sc_ureq_received = mono_time.tv_sec;
+ sc->sc_ureq_received = time_uptime;
if (pf_status.debug >= PF_DEBUG_MISC)
printf("pfsync: received "
"bulk update request\n");
@@ -546,7 +671,9 @@ pfsync_input(struct mbuf *m, ...)
pfsyncstats.pfsyncs_badstate++;
continue;
}
- pfsync_pack_state(PFSYNC_ACT_UPD, st, 0);
+ if (!st->sync_flags)
+ pfsync_pack_state(PFSYNC_ACT_UPD,
+ st, 0);
}
}
if (sc->sc_mbuf != NULL)
@@ -574,12 +701,16 @@ pfsync_input(struct mbuf *m, ...)
"update start\n");
break;
case PFSYNC_BUS_END:
- if (mono_time.tv_sec - ntohl(bus->endtime) >=
+ if (time_uptime - 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);
+#if NCARP > 0
+ if (!pfsync_sync_ok)
+ carp_suppress_preempt--;
+#endif
pfsync_sync_ok = 1;
if (pf_status.debug >= PF_DEBUG_MISC)
printf("pfsync: received valid "
@@ -643,8 +774,9 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
case SIOCGETPFSYNC:
bzero(&pfsyncr, sizeof(pfsyncr));
if (sc->sc_sync_ifp)
- strlcpy(pfsyncr.pfsyncr_syncif,
+ strlcpy(pfsyncr.pfsyncr_syncdev,
sc->sc_sync_ifp->if_xname, IFNAMSIZ);
+ pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer;
pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates;
if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))))
return (error);
@@ -655,11 +787,17 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr))))
return (error);
+ if (pfsyncr.pfsyncr_syncpeer.s_addr == 0)
+ sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
+ else
+ sc->sc_sync_peer.s_addr =
+ pfsyncr.pfsyncr_syncpeer.s_addr;
+
if (pfsyncr.pfsyncr_maxupdates > 255)
return (EINVAL);
sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
- if (pfsyncr.pfsyncr_syncif[0] == 0) {
+ if (pfsyncr.pfsyncr_syncdev[0] == 0) {
sc->sc_sync_ifp = NULL;
if (sc->sc_mbuf_net != NULL) {
/* Don't keep stale pfsync packets around. */
@@ -669,12 +807,15 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
sc->sc_statep_net.s = NULL;
splx(s);
}
+ if (imo->imo_num_memberships > 0) {
+ in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
+ imo->imo_multicast_ifp = NULL;
+ }
break;
}
- if ((sifp = ifunit(pfsyncr.pfsyncr_syncif)) == NULL)
+
+ if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL)
return (EINVAL);
- else if (sifp == sc->sc_sync_ifp)
- break;
s = splnet();
if (sifp->if_mtu < sc->sc_if.if_mtu ||
@@ -691,12 +832,21 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
imo->imo_multicast_ifp = NULL;
}
- if (sc->sc_sync_ifp) {
+ if (sc->sc_sync_ifp &&
+ sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
struct in_addr addr;
+ if (!(sc->sc_sync_ifp->if_flags & IFF_MULTICAST)) {
+ sc->sc_sync_ifp = NULL;
+ splx(s);
+ return (EADDRNOTAVAIL);
+ }
+
addr.s_addr = INADDR_PFSYNC_GROUP;
+
if ((imo->imo_membership[0] =
in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) {
+ sc->sc_sync_ifp = NULL;
splx(s);
return (ENOBUFS);
}
@@ -704,14 +854,25 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
imo->imo_multicast_ifp = sc->sc_sync_ifp;
imo->imo_multicast_ttl = PFSYNC_DFLTTL;
imo->imo_multicast_loop = 0;
+ }
+ if (sc->sc_sync_ifp ||
+ sc->sc_sendaddr.s_addr != INADDR_PFSYNC_GROUP) {
/* Request a full state table update. */
- sc->sc_ureq_sent = mono_time.tv_sec;
+ sc->sc_ureq_sent = time_uptime;
+#if NCARP > 0
+ if (pfsync_sync_ok)
+ carp_suppress_preempt++;
+#endif
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);
+ error = pfsync_request_update(NULL, NULL);
+ if (error == ENOMEM) {
+ splx(s);
+ return (ENOMEM);
+ }
pfsync_sendout(sc);
}
splx(s);
@@ -808,7 +969,7 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
}
int
-pfsync_pack_state(u_int8_t action, struct pf_state *st, int compress)
+pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
{
struct ifnet *ifp = &pfsyncif.sc_if;
struct pfsync_softc *sc = ifp->if_softc;
@@ -825,7 +986,8 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int compress)
* 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) {
+ if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL &&
+ sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
/* Don't leave any stale pfsync packets hanging around. */
if (sc->sc_mbuf != NULL) {
m_freem(sc->sc_mbuf);
@@ -879,9 +1041,9 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int compress)
}
}
- secs = time.tv_sec;
+ secs = time_second;
- st->pfsync_time = mono_time.tv_sec;
+ st->pfsync_time = time_uptime;
TAILQ_REMOVE(&state_updates, st, u.s.entry_updates);
TAILQ_INSERT_TAIL(&state_updates, st, u.s.entry_updates);
@@ -924,7 +1086,8 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int compress)
sp->allow_opts = st->allow_opts;
sp->timeout = st->timeout;
- sp->sync_flags = st->sync_flags & PFSTATE_NOSYNC;
+ if (flags & PFSYNC_FLAG_STALE)
+ sp->sync_flags |= PFSTATE_STALE;
}
pf_state_peer_hton(&st->src, &sp->src);
@@ -936,7 +1099,7 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int compress)
sp->expire = htonl(st->expire - secs);
/* do we need to build "compressed" actions for network transfer? */
- if (sc->sc_sync_ifp && compress) {
+ if (sc->sc_sync_ifp && flags & PFSYNC_FLAG_COMPRESS) {
switch (action) {
case PFSYNC_ACT_UPD:
newaction = PFSYNC_ACT_UPD_C;
@@ -1010,24 +1173,20 @@ pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src)
struct pfsync_header *h;
struct pfsync_softc *sc = ifp->if_softc;
struct pfsync_state_upd_req *rup;
- int s, ret;
+ int ret = 0;
if (sc->sc_mbuf == NULL) {
if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
- (void *)&sc->sc_statep.s)) == NULL) {
- splx(s);
+ (void *)&sc->sc_statep.s)) == NULL)
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);
+ (void *)&sc->sc_statep.s)) == NULL)
return (ENOMEM);
- }
h = mtod(sc->sc_mbuf, struct pfsync_header *);
}
}
@@ -1087,6 +1246,7 @@ pfsync_timeout(void *v)
splx(s);
}
+/* This must be called in splnet() */
void
pfsync_send_bus(struct pfsync_softc *sc, u_int8_t status)
{
@@ -1102,7 +1262,7 @@ pfsync_send_bus(struct pfsync_softc *sc, u_int8_t status)
bus = sc->sc_statep.b;
bus->creatorid = pf_status.hostid;
bus->status = status;
- bus->endtime = htonl(mono_time.tv_sec - sc->sc_ureq_received);
+ bus->endtime = htonl(time_uptime - sc->sc_ureq_received);
pfsync_sendout(sc);
}
}
@@ -1136,7 +1296,7 @@ pfsync_bulk_update(void *v)
/* 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;
+ state->pfsync_time = time_uptime;
TAILQ_REMOVE(&state_updates, state, u.s.entry_updates);
TAILQ_INSERT_TAIL(&state_updates, state,
u.s.entry_updates);
@@ -1154,16 +1314,28 @@ void
pfsync_bulkfail(void *v)
{
struct pfsync_softc *sc = v;
+ int s, error;
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);
+ s = splnet();
+ error = pfsync_request_update(NULL, NULL);
+ if (error == ENOMEM) {
+ if (pf_status.debug >= PF_DEBUG_MISC)
+ printf("pfsync: cannot allocate mbufs for "
+ "bulk update\n");
+ } else
+ pfsync_sendout(sc);
+ splx(s);
} else {
/* Pretend like the transfer was ok */
sc->sc_ureq_sent = 0;
sc->sc_bulk_tries = 0;
+#if NCARP > 0
+ if (!pfsync_sync_ok)
+ carp_suppress_preempt--;
+#endif
pfsync_sync_ok = 1;
if (pf_status.debug >= PF_DEBUG_MISC)
printf("pfsync: failed to receive "
@@ -1172,6 +1344,7 @@ pfsync_bulkfail(void *v)
}
}
+/* This must be called in splnet() */
int
pfsync_sendout(sc)
struct pfsync_softc *sc;
@@ -1199,9 +1372,8 @@ pfsync_sendout(sc)
sc->sc_statep_net.s = NULL;
}
- if (sc->sc_sync_ifp) {
+ if (sc->sc_sync_ifp || sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) {
struct ip *ip;
- struct ifaddr *ifa;
struct sockaddr sa;
M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
@@ -1221,16 +1393,12 @@ pfsync_sendout(sc)
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;
+ ip->ip_src.s_addr = INADDR_ANY;
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;
+ sc->sc_sendaddr.s_addr = sc->sc_sync_peer.s_addr;
pfsyncstats.pfsyncs_opackets++;
diff --git a/sys/contrib/pf/net/if_pfsync.h b/sys/contrib/pf/net/if_pfsync.h
index b3705c8dd2a2..ddd049a81fda 100644
--- a/sys/contrib/pf/net/if_pfsync.h
+++ b/sys/contrib/pf/net/if_pfsync.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_pfsync.h,v 1.13 2004/03/22 04:54:17 mcbride Exp $ */
+/* $OpenBSD: if_pfsync.h,v 1.19 2005/01/20 17:47:38 mcbride Exp $ */
/*
* Copyright (c) 2001 Michael Shalayeff
@@ -85,6 +85,9 @@ struct pfsync_state {
u_int8_t updates;
} __packed;
+#define PFSYNC_FLAG_COMPRESS 0x01
+#define PFSYNC_FLAG_STALE 0x02
+
struct pfsync_state_upd {
u_int32_t id[2];
struct pfsync_state_peer src;
@@ -150,9 +153,10 @@ struct pfsync_softc {
struct timeout sc_tmo;
struct timeout sc_bulk_tmo;
struct timeout sc_bulkfail_tmo;
+ struct in_addr sc_sync_peer;
struct in_addr sc_sendaddr;
- struct mbuf *sc_mbuf; /* current cummulative mbuf */
- struct mbuf *sc_mbuf_net; /* current cummulative mbuf */
+ struct mbuf *sc_mbuf; /* current cumulative mbuf */
+ struct mbuf *sc_mbuf_net; /* current cumulative mbuf */
union sc_statep sc_statep;
union sc_statep sc_statep_net;
u_int32_t sc_ureq_received;
@@ -184,7 +188,7 @@ struct pfsync_header {
} __packed;
#define PFSYNC_BULKPACKETS 1 /* # of packets per timeout */
-#define PFSYNC_MAX_BULKTRIES 12
+#define PFSYNC_MAX_BULKTRIES 12
#define PFSYNC_HDRLEN sizeof(struct pfsync_header)
#define PFSYNC_ACTIONS \
"CLR ST", "INS ST", "UPD ST", "DEL ST", \
@@ -194,33 +198,34 @@ struct pfsync_header {
#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 */
+ u_int64_t pfsyncs_ipackets; /* total input packets, IPv4 */
+ u_int64_t pfsyncs_ipackets6; /* total input packets, IPv6 */
+ u_int64_t pfsyncs_badif; /* not the right interface */
+ u_int64_t pfsyncs_badttl; /* TTL is not PFSYNC_DFLTTL */
+ u_int64_t pfsyncs_hdrops; /* packets shorter than hdr */
+ u_int64_t pfsyncs_badver; /* bad (incl unsupp) version */
+ u_int64_t pfsyncs_badact; /* bad action */
+ u_int64_t pfsyncs_badlen; /* data length does not match */
+ u_int64_t pfsyncs_badauth; /* bad authentication */
+ u_int64_t pfsyncs_stale; /* stale state */
+ u_int64_t pfsyncs_badval; /* bad values */
+ u_int64_t pfsyncs_badstate; /* insert/lookup failed */
+
+ u_int64_t pfsyncs_opackets; /* total output packets, IPv4 */
+ u_int64_t pfsyncs_opackets6; /* total output packets, IPv6 */
+ u_int64_t pfsyncs_onomem; /* no memory for an mbuf */
+ u_int64_t pfsyncs_oerrors; /* ip output error */
};
/*
* Configuration structure for SIOCSETPFSYNC SIOCGETPFSYNC
*/
struct pfsyncreq {
- char pfsyncr_syncif[IFNAMSIZ];
- int pfsyncr_maxupdates;
- int pfsyncr_authlevel;
+ char pfsyncr_syncdev[IFNAMSIZ];
+ struct in_addr pfsyncr_syncpeer;
+ int pfsyncr_maxupdates;
+ int pfsyncr_authlevel;
};
-#define SIOCSETPFSYNC _IOW('i', 247, struct ifreq)
-#define SIOCGETPFSYNC _IOWR('i', 248, struct ifreq)
#define pf_state_peer_hton(s,d) do { \
@@ -267,12 +272,14 @@ int pfsync_pack_state(u_int8_t, struct pf_state *, int);
} while (0)
#define pfsync_update_state(st) do { \
if (!st->sync_flags) \
- pfsync_pack_state(PFSYNC_ACT_UPD, (st), 1); \
+ pfsync_pack_state(PFSYNC_ACT_UPD, (st), \
+ PFSYNC_FLAG_COMPRESS); \
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); \
+ pfsync_pack_state(PFSYNC_ACT_DEL, (st), \
+ PFSYNC_FLAG_COMPRESS); \
st->sync_flags &= ~PFSTATE_FROMSYNC; \
} while (0)
#endif
diff --git a/sys/contrib/pf/net/pf.c b/sys/contrib/pf/net/pf.c
index a2db3d48ebf7..dc263d198af2 100644
--- a/sys/contrib/pf/net/pf.c
+++ b/sys/contrib/pf/net/pf.c
@@ -1,5 +1,4 @@
-/* $OpenBSD: pf.c,v 1.433.2.2 2004/07/17 03:22:34 brad Exp $ */
-/* add $OpenBSD: pf.c,v 1.448 2004/05/11 07:34:11 dhartmei Exp $ */
+/* $OpenBSD: pf.c,v 1.483 2005/03/15 17:38:43 dhartmei Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -69,6 +68,7 @@
#include <netinet/tcp_var.h>
#include <netinet/udp_var.h>
#include <netinet/icmp_var.h>
+#include <netinet/if_ether.h>
#include <dev/rndvar.h>
#include <net/pfvar.h>
@@ -92,7 +92,7 @@
* Global variables
*/
-struct pf_anchorqueue pf_anchors;
+struct pf_anchor_global pf_anchors;
struct pf_ruleset pf_main_ruleset;
struct pf_altqqueue pf_altqs[2];
struct pf_palist pf_pabuf;
@@ -107,12 +107,22 @@ u_int32_t ticket_pabuf;
struct timeout pf_expire_to; /* expire timeout */
+struct pf_anchor_stackframe {
+ struct pf_ruleset *rs;
+ struct pf_rule *r;
+ struct pf_anchor_node *parent;
+ struct pf_anchor *child;
+} pf_anchor_stack[64];
+
struct pool pf_src_tree_pl, pf_rule_pl;
struct pool pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
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);
+
+void pf_init_threshold(struct pf_threshold *, u_int32_t,
+ u_int32_t);
+void pf_add_threshold(struct pf_threshold *);
+int pf_check_threshold(struct pf_threshold *);
void pf_change_ap(struct pf_addr *, u_int16_t *,
u_int16_t *, u_int16_t *, struct pf_addr *,
@@ -128,7 +138,8 @@ void pf_change_icmp(struct pf_addr *, u_int16_t *,
void pf_send_tcp(const struct pf_rule *, sa_family_t,
const struct pf_addr *, const struct pf_addr *,
u_int16_t, u_int16_t, u_int32_t, u_int32_t,
- u_int8_t, u_int16_t, u_int16_t, u_int8_t);
+ u_int8_t, u_int16_t, u_int16_t, u_int8_t, int,
+ struct ether_header *, struct ifnet *);
void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t,
sa_family_t, struct pf_rule *);
struct pf_rule *pf_match_translation(struct pf_pdesc *, struct mbuf *,
@@ -143,19 +154,19 @@ struct pf_rule *pf_get_translation(struct pf_pdesc *, struct mbuf *,
int pf_test_tcp(struct pf_rule **, struct pf_state **,
int, struct pfi_kif *, struct mbuf *, int,
void *, struct pf_pdesc *, struct pf_rule **,
- struct pf_ruleset **);
+ struct pf_ruleset **, struct ifqueue *);
int pf_test_udp(struct pf_rule **, struct pf_state **,
int, struct pfi_kif *, struct mbuf *, int,
void *, struct pf_pdesc *, struct pf_rule **,
- struct pf_ruleset **);
+ struct pf_ruleset **, struct ifqueue *);
int pf_test_icmp(struct pf_rule **, struct pf_state **,
int, struct pfi_kif *, struct mbuf *, int,
void *, struct pf_pdesc *, struct pf_rule **,
- struct pf_ruleset **);
+ struct pf_ruleset **, struct ifqueue *);
int pf_test_other(struct pf_rule **, struct pf_state **,
int, struct pfi_kif *, struct mbuf *, int, void *,
struct pf_pdesc *, struct pf_rule **,
- struct pf_ruleset **);
+ struct pf_ruleset **, struct ifqueue *);
int pf_test_fragment(struct pf_rule **, int,
struct pfi_kif *, struct mbuf *, void *,
struct pf_pdesc *, struct pf_rule **,
@@ -168,12 +179,12 @@ int pf_test_state_udp(struct pf_state **, int,
void *, struct pf_pdesc *);
int pf_test_state_icmp(struct pf_state **, int,
struct pfi_kif *, struct mbuf *, int,
- void *, struct pf_pdesc *);
+ void *, struct pf_pdesc *, u_short *);
int pf_test_state_other(struct pf_state **, int,
struct pfi_kif *, struct pf_pdesc *);
struct pf_tag *pf_get_tag(struct mbuf *);
int pf_match_tag(struct mbuf *, struct pf_rule *,
- struct pf_rule *, struct pf_tag *, int *);
+ struct pf_tag **, int *);
void pf_hash(struct pf_addr *, struct pf_addr *,
struct pf_poolhashkey *, sa_family_t);
int pf_map_addr(u_int8_t, struct pf_rule *,
@@ -204,6 +215,8 @@ int pf_addr_wrap_neq(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);
+int pf_src_connlimit(struct pf_state **);
+int pf_check_congestion(struct ifqueue *);
struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
{ &pf_state_pl, PFSTATE_HIWAT },
@@ -214,12 +227,12 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
#define STATE_LOOKUP() \
do { \
if (direction == PF_IN) \
- *state = pf_find_state_recurse( \
+ *state = pf_find_state_recurse( \
kif, &key, PF_EXT_GWY); \
else \
- *state = pf_find_state_recurse( \
+ *state = pf_find_state_recurse( \
kif, &key, PF_LAN_EXT); \
- if (*state == NULL) \
+ if (*state == NULL || (*state)->timeout == PFTM_PURGE) \
return (PF_DROP); \
if (direction == PF_OUT && \
(((*state)->rule.ptr->rt == PF_ROUTETO && \
@@ -243,6 +256,24 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
((r)->rule_flag & PFRULE_GRBOUND) ? (k)->pfik_parent : \
(k)->pfik_parent->pfik_parent)
+#define STATE_INC_COUNTERS(s) \
+ do { \
+ s->rule.ptr->states++; \
+ if (s->anchor.ptr != NULL) \
+ s->anchor.ptr->states++; \
+ if (s->nat_rule.ptr != NULL) \
+ s->nat_rule.ptr->states++; \
+ } while (0)
+
+#define STATE_DEC_COUNTERS(s) \
+ do { \
+ if (s->nat_rule.ptr != NULL) \
+ s->nat_rule.ptr->states--; \
+ if (s->anchor.ptr != NULL) \
+ s->anchor.ptr->states--; \
+ s->rule.ptr->states--; \
+ } while (0)
+
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 *);
@@ -250,6 +281,7 @@ static __inline int pf_state_compare_ext_gwy(struct pf_state *,
struct pf_state *);
static __inline int pf_state_compare_id(struct pf_state *,
struct pf_state *);
+static __inline int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
struct pf_src_tree tree_src_tracking;
@@ -263,6 +295,8 @@ RB_GENERATE(pf_state_tree_ext_gwy, pf_state,
u.s.entry_ext_gwy, pf_state_compare_ext_gwy);
RB_GENERATE(pf_state_tree_id, pf_state,
u.s.entry_id, pf_state_compare_id);
+RB_GENERATE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare);
+RB_GENERATE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare);
static __inline int
pf_src_compare(struct pf_src_node *a, struct pf_src_node *b)
@@ -459,6 +493,14 @@ pf_state_compare_id(struct pf_state *a, struct pf_state *b)
return (0);
}
+static __inline int
+pf_anchor_compare(struct pf_anchor *a, struct pf_anchor *b)
+{
+ int c = strcmp(a->path, b->path);
+
+ return (c ? (c < 0 ? -1 : 1) : 0);
+}
+
#ifdef INET6
void
pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af)
@@ -477,7 +519,7 @@ pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af)
break;
}
}
-#endif
+#endif /* INET6 */
struct pf_state *
pf_find_state_byid(struct pf_state *key)
@@ -553,6 +595,131 @@ pf_find_state_all(struct pf_state *key, u_int8_t tree, int *more)
}
}
+void
+pf_init_threshold(struct pf_threshold *threshold,
+ u_int32_t limit, u_int32_t seconds)
+{
+ threshold->limit = limit * PF_THRESHOLD_MULT;
+ threshold->seconds = seconds;
+ threshold->count = 0;
+ threshold->last = time_second;
+}
+
+void
+pf_add_threshold(struct pf_threshold *threshold)
+{
+ u_int32_t t = time_second, diff = t - threshold->last;
+
+ if (diff >= threshold->seconds)
+ threshold->count = 0;
+ else
+ threshold->count -= threshold->count * diff /
+ threshold->seconds;
+ threshold->count += PF_THRESHOLD_MULT;
+ threshold->last = t;
+}
+
+int
+pf_check_threshold(struct pf_threshold *threshold)
+{
+ return (threshold->count > threshold->limit);
+}
+
+int
+pf_src_connlimit(struct pf_state **state)
+{
+ struct pf_state *s;
+ int bad = 0;
+
+ (*state)->src_node->conn++;
+ pf_add_threshold(&(*state)->src_node->conn_rate);
+
+ if ((*state)->rule.ptr->max_src_conn &&
+ (*state)->rule.ptr->max_src_conn <
+ (*state)->src_node->conn) {
+ pf_status.lcounters[LCNT_SRCCONN]++;
+ bad++;
+ }
+
+ if ((*state)->rule.ptr->max_src_conn_rate.limit &&
+ pf_check_threshold(&(*state)->src_node->conn_rate)) {
+ pf_status.lcounters[LCNT_SRCCONNRATE]++;
+ bad++;
+ }
+
+ if (!bad)
+ return (0);
+
+ if ((*state)->rule.ptr->overload_tbl) {
+ struct pfr_addr p;
+ u_int32_t killed = 0;
+
+ pf_status.lcounters[LCNT_OVERLOAD_TABLE]++;
+ if (pf_status.debug >= PF_DEBUG_MISC) {
+ printf("pf_src_connlimit: blocking address ");
+ pf_print_host(&(*state)->src_node->addr, 0,
+ (*state)->af);
+ }
+
+ bzero(&p, sizeof(p));
+ p.pfra_af = (*state)->af;
+ switch ((*state)->af) {
+#ifdef INET
+ case AF_INET:
+ p.pfra_net = 32;
+ p.pfra_ip4addr = (*state)->src_node->addr.v4;
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ p.pfra_net = 128;
+ p.pfra_ip6addr = (*state)->src_node->addr.v6;
+ break;
+#endif /* INET6 */
+ }
+
+ pfr_insert_kentry((*state)->rule.ptr->overload_tbl,
+ &p, time_second);
+
+ /* kill existing states if that's required. */
+ if ((*state)->rule.ptr->flush) {
+ pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++;
+
+ RB_FOREACH(s, pf_state_tree_id, &tree_id) {
+ /*
+ * Kill states from this source. (Only those
+ * from the same rule if PF_FLUSH_GLOBAL is not
+ * set)
+ */
+ if (s->af == (*state)->af &&
+ (((*state)->direction == PF_OUT &&
+ PF_AEQ(&(*state)->src_node->addr,
+ &s->lan.addr, s->af)) ||
+ ((*state)->direction == PF_IN &&
+ PF_AEQ(&(*state)->src_node->addr,
+ &s->ext.addr, s->af))) &&
+ ((*state)->rule.ptr->flush &
+ PF_FLUSH_GLOBAL ||
+ (*state)->rule.ptr == s->rule.ptr)) {
+ s->timeout = PFTM_PURGE;
+ s->src.state = s->dst.state =
+ TCPS_CLOSED;
+ killed++;
+ }
+ }
+ if (pf_status.debug >= PF_DEBUG_MISC)
+ printf(", %u states killed", killed);
+ }
+ if (pf_status.debug >= PF_DEBUG_MISC)
+ printf("\n");
+ }
+
+ /* kill this state */
+ (*state)->timeout = PFTM_PURGE;
+ (*state)->src.state = (*state)->dst.state = TCPS_CLOSED;
+ return (1);
+}
+
int
pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
struct pf_addr *src, sa_family_t af)
@@ -574,9 +741,16 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
if (!rule->max_src_nodes ||
rule->src_nodes < rule->max_src_nodes)
(*sn) = pool_get(&pf_src_tree_pl, PR_NOWAIT);
+ else
+ pf_status.lcounters[LCNT_SRCNODES]++;
if ((*sn) == NULL)
return (-1);
bzero(*sn, sizeof(struct pf_src_node));
+
+ pf_init_threshold(&(*sn)->conn_rate,
+ rule->max_src_conn_rate.limit,
+ rule->max_src_conn_rate.seconds);
+
(*sn)->af = af;
if (rule->rule_flag & PFRULE_RULESRCTRACK ||
rule->rpool.opts & PF_POOL_STICKYADDR)
@@ -594,7 +768,7 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
pool_put(&pf_src_tree_pl, *sn);
return (-1);
}
- (*sn)->creation = time.tv_sec;
+ (*sn)->creation = time_second;
(*sn)->ruletype = rule->action;
if ((*sn)->rule.ptr != NULL)
(*sn)->rule.ptr->src_nodes++;
@@ -602,8 +776,10 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
pf_status.src_nodes++;
} else {
if (rule->max_src_states &&
- (*sn)->states >= rule->max_src_states)
+ (*sn)->states >= rule->max_src_states) {
+ pf_status.lcounters[LCNT_SRCSTATES]++;
return (-1);
+ }
}
return (0);
}
@@ -705,7 +881,7 @@ pf_state_expires(const struct pf_state *state)
/* handle all PFTM_* > PFTM_MAX here */
if (state->timeout == PFTM_PURGE)
- return (time.tv_sec);
+ return (time_second);
if (state->timeout == PFTM_UNTIL_PACKET)
return (0);
KASSERT(state->timeout < PFTM_MAX);
@@ -726,7 +902,7 @@ pf_state_expires(const struct pf_state *state)
return (state->expire + timeout * (end - states) /
(end - start));
else
- return (time.tv_sec);
+ return (time_second);
}
return (state->expire + timeout);
}
@@ -739,7 +915,7 @@ pf_purge_expired_src_nodes(void)
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->states <= 0 && cur->expire <= time_second) {
if (cur->rule.ptr != NULL) {
cur->rule.ptr->src_nodes--;
if (cur->rule.ptr->states <= 0 &&
@@ -760,12 +936,17 @@ pf_src_tree_remove_state(struct pf_state *s)
u_int32_t timeout;
if (s->src_node != NULL) {
+ if (s->proto == IPPROTO_TCP) {
+ if (s->src.state == PF_TCPS_PROXY_DST ||
+ s->timeout >= PFTM_TCP_ESTABLISHED)
+ --s->src_node->conn;
+ }
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;
+ s->src_node->expire = time_second + timeout;
}
}
if (s->nat_src_node != s->src_node && s->nat_src_node != NULL) {
@@ -774,13 +955,51 @@ pf_src_tree_remove_state(struct pf_state *s)
if (!timeout)
timeout =
pf_default_rule.timeout[PFTM_SRC_NODE];
- s->nat_src_node->expire = time.tv_sec + timeout;
+ s->nat_src_node->expire = time_second + timeout;
}
}
s->src_node = s->nat_src_node = NULL;
}
void
+pf_purge_expired_state(struct pf_state *cur)
+{
+ 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,
+ TH_RST|TH_ACK, 0, 0, 0, 1, NULL, NULL);
+ RB_REMOVE(pf_state_tree_ext_gwy,
+ &cur->u.s.kif->pfik_ext_gwy, cur);
+ RB_REMOVE(pf_state_tree_lan_ext,
+ &cur->u.s.kif->pfik_lan_ext, cur);
+ RB_REMOVE(pf_state_tree_id, &tree_id, cur);
+#if NPFSYNC
+ pfsync_delete_state(cur);
+#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);
+ if (cur->tag)
+ pf_tag_unref(cur->tag);
+ pool_put(&pf_state_pl, cur);
+ pf_status.fcounters[FCNT_STATE_REMOVALS]++;
+ pf_status.states--;
+}
+
+void
pf_purge_expired_states(void)
{
struct pf_state *cur, *next;
@@ -788,40 +1007,8 @@ pf_purge_expired_states(void)
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,
- 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);
-#if NPFSYNC
- pfsync_delete_state(cur);
-#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);
- pf_status.fcounters[FCNT_STATE_REMOVALS]++;
- pf_status.states--;
- }
+ if (pf_state_expires(cur) <= time_second)
+ pf_purge_expired_state(cur);
}
}
@@ -1011,14 +1198,14 @@ pf_calc_skip_steps(struct pf_rulequeue *rules)
PF_SET_SKIP_STEPS(PF_SKIP_AF);
if (cur->proto != prev->proto)
PF_SET_SKIP_STEPS(PF_SKIP_PROTO);
- if (cur->src.not != prev->src.not ||
+ if (cur->src.neg != prev->src.neg ||
pf_addr_wrap_neq(&cur->src.addr, &prev->src.addr))
PF_SET_SKIP_STEPS(PF_SKIP_SRC_ADDR);
if (cur->src.port[0] != prev->src.port[0] ||
cur->src.port[1] != prev->src.port[1] ||
cur->src.port_op != prev->src.port_op)
PF_SET_SKIP_STEPS(PF_SKIP_SRC_PORT);
- if (cur->dst.not != prev->dst.not ||
+ if (cur->dst.neg != prev->dst.neg ||
pf_addr_wrap_neq(&cur->dst.addr, &prev->dst.addr))
PF_SET_SKIP_STEPS(PF_SKIP_DST_ADDR);
if (cur->dst.port[0] != prev->dst.port[0] ||
@@ -1057,21 +1244,6 @@ pf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2)
}
}
-void
-pf_update_anchor_rules()
-{
- struct pf_rule *rule;
- int i;
-
- for (i = 0; i < PF_RULESET_MAX; ++i)
- TAILQ_FOREACH(rule, pf_main_ruleset.rules[i].active.ptr,
- entries)
- if (rule->anchorname[0])
- rule->anchor = pf_find_anchor(rule->anchorname);
- else
- rule->anchor = NULL;
-}
-
u_int16_t
pf_cksum_fixup(u_int16_t cksum, u_int16_t old, u_int16_t new, u_int8_t udp)
{
@@ -1256,10 +1428,10 @@ void
pf_send_tcp(const struct pf_rule *r, sa_family_t af,
const struct pf_addr *saddr, const struct pf_addr *daddr,
u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack,
- u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl)
+ u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, int tag,
+ struct ether_header *eh, struct ifnet *ifp)
{
struct mbuf *m;
- struct m_tag *mtag;
int len, tlen;
#ifdef INET
struct ip *h;
@@ -1289,17 +1461,22 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af,
}
/* create outgoing mbuf */
- mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
- if (mtag == NULL)
- return;
m = m_gethdr(M_DONTWAIT, MT_HEADER);
- if (m == NULL) {
- m_tag_free(mtag);
+ if (m == NULL)
return;
+ if (tag) {
+ struct m_tag *mtag;
+
+ mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
+ if (mtag == NULL) {
+ m_freem(m);
+ return;
+ }
+ m_tag_prepend(m, mtag);
}
- m_tag_prepend(m, mtag);
#ifdef ALTQ
if (r != NULL && r->qid) {
+ struct m_tag *mtag;
struct altq_tag *atag;
mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
@@ -1312,7 +1489,7 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af,
m_tag_prepend(m, mtag);
}
}
-#endif
+#endif /* ALTQ */
m->m_data += max_linkhdr;
m->m_pkthdr.len = m->m_len = len;
m->m_pkthdr.rcvif = NULL;
@@ -1377,8 +1554,28 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af,
h->ip_off = htons(ip_mtudisc ? IP_DF : 0);
h->ip_ttl = ttl ? ttl : ip_defttl;
h->ip_sum = 0;
- ip_output(m, (void *)NULL, (void *)NULL, 0, (void *)NULL,
- (void *)NULL);
+ if (eh == NULL) {
+ ip_output(m, (void *)NULL, (void *)NULL, 0,
+ (void *)NULL, (void *)NULL);
+ } else {
+ struct route ro;
+ struct rtentry rt;
+ struct ether_header *e = (void *)ro.ro_dst.sa_data;
+
+ if (ifp == NULL) {
+ m_freem(m);
+ return;
+ }
+ rt.rt_ifp = ifp;
+ ro.ro_rt = &rt;
+ ro.ro_dst.sa_len = sizeof(ro.ro_dst);
+ ro.ro_dst.sa_family = pseudo_AF_HDRCMPLT;
+ bcopy(eh->ether_dhost, e->ether_shost, ETHER_ADDR_LEN);
+ bcopy(eh->ether_shost, e->ether_dhost, ETHER_ADDR_LEN);
+ e->ether_type = eh->ether_type;
+ ip_output(m, (void *)NULL, &ro, IP_ROUTETOETHER,
+ (void *)NULL, (void *)NULL);
+ }
break;
#endif /* INET */
#ifdef INET6
@@ -1427,7 +1624,7 @@ pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
m_tag_prepend(m0, mtag);
}
}
-#endif
+#endif /* ALTQ */
switch (af) {
#ifdef INET
@@ -1552,17 +1749,14 @@ 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_tag **pftag, int *tag)
{
if (*tag == -1) { /* find mbuf tag */
- pftag = pf_get_tag(m);
- if (pftag != NULL)
- *tag = pftag->tag;
+ *pftag = pf_get_tag(m);
+ if (*pftag != NULL)
+ *tag = (*pftag)->tag;
else
*tag = 0;
- if (nat_rule != NULL && nat_rule->tag)
- *tag = nat_rule->tag;
}
return ((!r->match_tag_not && r->match_tag == *tag) ||
@@ -1589,36 +1783,66 @@ pf_tag_packet(struct mbuf *m, struct pf_tag *pftag, int tag)
return (0);
}
-#define PF_STEP_INTO_ANCHOR(r, a, s, n) \
- do { \
- if ((r) == NULL || (r)->anchor == NULL || \
- (s) != NULL || (a) != NULL) \
- panic("PF_STEP_INTO_ANCHOR"); \
- (a) = (r); \
- (s) = TAILQ_FIRST(&(r)->anchor->rulesets); \
- (r) = NULL; \
- while ((s) != NULL && ((r) = \
- TAILQ_FIRST((s)->rules[n].active.ptr)) == NULL) \
- (s) = TAILQ_NEXT((s), entries); \
- if ((r) == NULL) { \
- (r) = TAILQ_NEXT((a), entries); \
- (a) = NULL; \
- } \
- } while (0)
+static void
+pf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n,
+ struct pf_rule **r, struct pf_rule **a)
+{
+ struct pf_anchor_stackframe *f;
-#define PF_STEP_OUT_OF_ANCHOR(r, a, s, n) \
- do { \
- if ((r) != NULL || (a) == NULL || (s) == NULL) \
- panic("PF_STEP_OUT_OF_ANCHOR"); \
- (s) = TAILQ_NEXT((s), entries); \
- while ((s) != NULL && ((r) = \
- TAILQ_FIRST((s)->rules[n].active.ptr)) == NULL) \
- (s) = TAILQ_NEXT((s), entries); \
- if ((r) == NULL) { \
- (r) = TAILQ_NEXT((a), entries); \
- (a) = NULL; \
- } \
- } while (0)
+ if (*depth >= sizeof(pf_anchor_stack) /
+ sizeof(pf_anchor_stack[0])) {
+ printf("pf_step_into_anchor: stack overflow\n");
+ *r = TAILQ_NEXT(*r, entries);
+ return;
+ } else if (*depth == 0 && a != NULL)
+ *a = *r;
+ f = pf_anchor_stack + (*depth)++;
+ f->rs = *rs;
+ f->r = *r;
+ if ((*r)->anchor_wildcard) {
+ f->parent = &(*r)->anchor->children;
+ if ((f->child = RB_MIN(pf_anchor_node, f->parent)) ==
+ NULL) {
+ *r = NULL;
+ return;
+ }
+ *rs = &f->child->ruleset;
+ } else {
+ f->parent = NULL;
+ f->child = NULL;
+ *rs = &(*r)->anchor->ruleset;
+ }
+ *r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
+}
+
+static void
+pf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n,
+ struct pf_rule **r, struct pf_rule **a)
+{
+ struct pf_anchor_stackframe *f;
+
+ do {
+ if (*depth <= 0)
+ break;
+ f = pf_anchor_stack + *depth - 1;
+ if (f->parent != NULL && f->child != NULL) {
+ f->child = RB_NEXT(pf_anchor_node, f->parent, f->child);
+ if (f->child != NULL) {
+ *rs = &f->child->ruleset;
+ *r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
+ if (*r == NULL)
+ continue;
+ else
+ break;
+ }
+ }
+ (*depth)--;
+ if (*depth == 0 && a != NULL)
+ *a = NULL;
+ *rs = f->rs;
+ *r = TAILQ_NEXT(f->r, entries);
+ } while (*r == NULL);
+}
#ifdef INET6
void
@@ -1772,20 +1996,27 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
if (rpool->cur->addr.type == PF_ADDR_NOROUTE)
return (1);
if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
- if (af == AF_INET) {
+ switch (af) {
+#ifdef INET
+ case 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 {
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
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;
+ break;
+#endif /* INET6 */
}
} else if (rpool->cur->addr.type == PF_ADDR_TABLE) {
if ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN)
@@ -1807,25 +2038,29 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
switch (af) {
#ifdef INET
case AF_INET:
- rpool->counter.addr32[0] = arc4random();
+ rpool->counter.addr32[0] = htonl(arc4random());
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
if (rmask->addr32[3] != 0xffffffff)
- rpool->counter.addr32[3] = arc4random();
+ rpool->counter.addr32[3] =
+ htonl(arc4random());
else
break;
if (rmask->addr32[2] != 0xffffffff)
- rpool->counter.addr32[2] = arc4random();
+ rpool->counter.addr32[2] =
+ htonl(arc4random());
else
break;
if (rmask->addr32[1] != 0xffffffff)
- rpool->counter.addr32[1] = arc4random();
+ rpool->counter.addr32[1] =
+ htonl(arc4random());
else
break;
if (rmask->addr32[0] != 0xffffffff)
- rpool->counter.addr32[0] = arc4random();
+ rpool->counter.addr32[0] =
+ htonl(arc4random());
break;
#endif /* INET6 */
}
@@ -1886,6 +2121,8 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
get_addr:
PF_ACPY(naddr, &rpool->counter, af);
+ if (init_addr != NULL && PF_AZERO(init_addr, af))
+ PF_ACPY(init_addr, naddr, af);
PF_AINC(&rpool->counter, af);
break;
}
@@ -1928,7 +2165,7 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
* similar 2 portloop in in_pcbbind
*/
if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP)) {
- key.gwy.port = 0;
+ key.gwy.port = dport;
if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL)
return (0);
} else if (low == 0 && high == 0) {
@@ -1950,7 +2187,7 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
high = tmp;
}
/* low < high */
- cut = arc4random() % (1 + high - low) + low;
+ cut = htonl(arc4random()) % (1 + high - low) + low;
/* low <= cut <= high */
for (tmp = cut; tmp <= high; ++(tmp)) {
key.gwy.port = htons(tmp);
@@ -1992,8 +2229,11 @@ 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,
struct pf_addr *daddr, u_int16_t dport, int rs_num)
{
- struct pf_rule *r, *rm = NULL, *anchorrule = NULL;
+ struct pf_rule *r, *rm = NULL;
struct pf_ruleset *ruleset = NULL;
+ struct pf_tag *pftag = NULL;
+ int tag = -1;
+ int asd = 0;
r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr);
while (r && rm == NULL) {
@@ -2019,7 +2259,7 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
r = r->skip[PF_SKIP_AF].ptr;
else if (r->proto && r->proto != pd->proto)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&src->addr, saddr, pd->af, src->not))
+ else if (PF_MISMATCHAW(&src->addr, saddr, pd->af, src->neg))
r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR :
PF_SKIP_DST_ADDR].ptr;
else if (src->port_op && !pf_match_port(src->port_op,
@@ -2027,7 +2267,7 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT :
PF_SKIP_DST_PORT].ptr;
else if (dst != NULL &&
- PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->not))
+ PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af, 0))
r = TAILQ_NEXT(r, entries);
@@ -2035,20 +2275,25 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
!pf_match_port(dst->port_op, dst->port[0],
dst->port[1], dport))
r = r->skip[PF_SKIP_DST_PORT].ptr;
+ else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
+ r = TAILQ_NEXT(r, entries);
else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto !=
IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m,
off, pd->hdr.tcp), r->os_fingerprint)))
r = TAILQ_NEXT(r, entries);
- else if (r->anchorname[0] && r->anchor == NULL)
- r = TAILQ_NEXT(r, entries);
- else if (r->anchor == NULL)
+ else {
+ if (r->tag)
+ tag = r->tag;
+ if (r->anchor == NULL) {
rm = r;
- else
- PF_STEP_INTO_ANCHOR(r, anchorrule, ruleset, rs_num);
- if (r == NULL && anchorrule != NULL)
- PF_STEP_OUT_OF_ANCHOR(r, anchorrule, ruleset,
- rs_num);
+ } else
+ pf_step_into_anchor(&asd, &ruleset, rs_num, &r, NULL);
+ }
+ if (r == NULL)
+ pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r, NULL);
}
+ if (pf_tag_packet(m, pftag, tag))
+ return (NULL);
if (rm != NULL && (rm->action == PF_NONAT ||
rm->action == PF_NORDR || rm->action == PF_NOBINAT))
return (NULL);
@@ -2100,7 +2345,9 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
switch (direction) {
case PF_OUT:
if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){
- if (pd->af == AF_INET) {
+ switch (pd->af) {
+#ifdef INET
+ case AF_INET:
if (r->rpool.cur->addr.p.dyn->
pfid_acnt4 < 1)
return (NULL);
@@ -2110,7 +2357,10 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
&r->rpool.cur->addr.p.dyn->
pfid_mask4,
saddr, AF_INET);
- } else {
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
if (r->rpool.cur->addr.p.dyn->
pfid_acnt6 < 1)
return (NULL);
@@ -2120,6 +2370,8 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
&r->rpool.cur->addr.p.dyn->
pfid_mask6,
saddr, AF_INET6);
+ break;
+#endif /* INET6 */
}
} else
PF_POOLMASK(naddr,
@@ -2128,8 +2380,10 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
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.type == PF_ADDR_DYNIFTL) {
+ switch (pd->af) {
+#ifdef INET
+ case AF_INET:
if (r->src.addr.p.dyn->
pfid_acnt4 < 1)
return (NULL);
@@ -2139,7 +2393,10 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
&r->src.addr.p.dyn->
pfid_mask4,
daddr, AF_INET);
- } else {
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
if (r->src.addr.p.dyn->
pfid_acnt6 < 1)
return (NULL);
@@ -2149,6 +2406,8 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
&r->src.addr.p.dyn->
pfid_mask6,
daddr, AF_INET6);
+ break;
+#endif /* INET6 */
}
} else
PF_POOLMASK(naddr,
@@ -2159,7 +2418,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(pd->af, r, saddr, naddr, NULL, sn))
return (NULL);
if (r->rpool.proxy_port[1]) {
@@ -2224,6 +2483,7 @@ pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd)
daddr = pd->src;
}
switch (pd->af) {
+#ifdef INET
case AF_INET:
inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport);
if (inp == NULL) {
@@ -2232,6 +2492,7 @@ pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd)
return (0);
}
break;
+#endif /* INET */
#ifdef INET6
case AF_INET6:
inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6,
@@ -2316,6 +2577,7 @@ 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);
+ NTOHS(mss);
/* FALLTHROUGH */
default:
optlen = opt[1];
@@ -2410,7 +2672,8 @@ 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 pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm)
+ struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
+ struct ifqueue *ifq)
{
struct pf_rule *nr = NULL;
struct pf_addr *saddr = pd->src, *daddr = pd->dst;
@@ -2428,6 +2691,12 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
struct pf_tag *pftag = NULL;
int tag = -1;
u_int16_t mss = tcp_mssdflt;
+ int asd = 0;
+
+ if (pf_check_congestion(ifq)) {
+ REASON_SET(&reason, PFRES_CONGEST);
+ return (PF_DROP);
+ }
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
@@ -2472,12 +2741,12 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
r = r->skip[PF_SKIP_AF].ptr;
else if (r->proto && r->proto != IPPROTO_TCP)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.not))
+ else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
else if (r->src.port_op && !pf_match_port(r->src.port_op,
r->src.port[0], r->src.port[1], th->th_sport))
r = r->skip[PF_SKIP_SRC_PORT].ptr;
- else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.not))
+ else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
r->dst.port[0], r->dst.port[1], th->th_dport))
@@ -2498,9 +2767,9 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
!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->prob && r->prob <= arc4random())
r = TAILQ_NEXT(r, entries);
- else if (r->anchorname[0] && r->anchor == NULL)
+ else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
r = TAILQ_NEXT(r, entries);
else if (r->os_fingerprint != PF_OSFP_ANY && !pf_osfp_match(
pf_osfp_fingerprint(pd, m, off, th), r->os_fingerprint))
@@ -2516,12 +2785,12 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
break;
r = TAILQ_NEXT(r, entries);
} else
- PF_STEP_INTO_ANCHOR(r, a, ruleset,
- PF_RULESET_FILTER);
+ pf_step_into_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
- if (r == NULL && a != NULL)
- PF_STEP_OUT_OF_ANCHOR(r, a, ruleset,
- PF_RULESET_FILTER);
+ if (r == NULL)
+ pf_step_out_of_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
r = *rm;
a = *am;
@@ -2563,7 +2832,7 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
pf_send_tcp(r, af, pd->dst,
pd->src, th->th_dport, th->th_sport,
ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0,
- r->return_ttl);
+ r->return_ttl, 1, pd->eh, kif->pfik_ifp);
} else if ((af == AF_INET) && r->return_icmp)
pf_send_icmp(m, r->return_icmp >> 8,
r->return_icmp & 255, af, r);
@@ -2590,21 +2859,29 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
len = pd->tot_len - off - (th->th_off << 2);
/* check maximums */
- if (r->max_states && (r->states >= r->max_states))
+ if (r->max_states && (r->states >= r->max_states)) {
+ pf_status.lcounters[LCNT_STATES]++;
+ REASON_SET(&reason, PFRES_MAXSTATES);
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)
+ pf_insert_src_node(&sn, r, saddr, af) != 0) {
+ REASON_SET(&reason, PFRES_SRCLIMIT);
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)))
+ (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
+ REASON_SET(&reason, PFRES_SRCLIMIT);
goto cleanup;
+ }
s = pool_get(&pf_state_pl, PR_NOWAIT);
if (s == NULL) {
+ REASON_SET(&reason, PFRES_MEMORY);
cleanup:
if (sn != NULL && sn->states == 0 && sn->expire == 0) {
RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
@@ -2619,18 +2896,13 @@ cleanup:
pf_status.src_nodes--;
pool_put(&pf_src_tree_pl, nsn);
}
- REASON_SET(&reason, PFRES_MEMORY);
return (PF_DROP);
}
bzero(s, sizeof(*s));
- r->states++;
- if (a != NULL)
- a->states++;
s->rule.ptr = r;
s->nat_rule.ptr = nr;
- if (s->nat_rule.ptr != NULL)
- s->nat_rule.ptr->states++;
s->anchor.ptr = a;
+ STATE_INC_COUNTERS(s);
s->allow_opts = r->allow_opts;
s->log = r->log & 2;
s->proto = IPPROTO_TCP;
@@ -2667,7 +2939,7 @@ cleanup:
if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
r->keep_state == PF_STATE_MODULATE) {
/* Generate sequence number modulator */
- while ((s->src.seqdiff = arc4random()) == 0)
+ while ((s->src.seqdiff = htonl(arc4random())) == 0)
;
pf_change_a(&th->th_seq, &th->th_sum,
htonl(s->src.seqlo + s->src.seqdiff), 0);
@@ -2692,8 +2964,8 @@ cleanup:
s->dst.max_win = 1;
s->src.state = TCPS_SYN_SENT;
s->dst.state = TCPS_CLOSED;
- s->creation = time.tv_sec;
- s->expire = time.tv_sec;
+ s->creation = time_second;
+ s->expire = time_second;
s->timeout = PFTM_TCP_FIRST_PACKET;
pf_set_rt_ifp(s, saddr);
if (sn != NULL) {
@@ -2709,25 +2981,35 @@ cleanup:
off, pd, th, &s->src, &s->dst)) {
REASON_SET(&reason, PFRES_MEMORY);
pf_src_tree_remove_state(s);
+ STATE_DEC_COUNTERS(s);
pool_put(&pf_state_pl, s);
return (PF_DROP);
}
if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub &&
- pf_normalize_tcp_stateful(m, off, pd, &reason, th, &s->src,
- &s->dst, &rewrite)) {
+ pf_normalize_tcp_stateful(m, off, pd, &reason, th, s,
+ &s->src, &s->dst, &rewrite)) {
+ /* This really shouldn't happen!!! */
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_normalize_tcp_stateful failed on first pkt"));
pf_normalize_tcp_cleanup(s);
pf_src_tree_remove_state(s);
+ STATE_DEC_COUNTERS(s);
pool_put(&pf_state_pl, s);
return (PF_DROP);
}
if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
pf_normalize_tcp_cleanup(s);
- REASON_SET(&reason, PFRES_MEMORY);
+ REASON_SET(&reason, PFRES_STATEINS);
pf_src_tree_remove_state(s);
+ STATE_DEC_COUNTERS(s);
pool_put(&pf_state_pl, s);
return (PF_DROP);
} else
*sm = s;
+ if (tag > 0) {
+ pf_tag_ref(tag);
+ s->tag = tag;
+ }
if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
r->keep_state == PF_STATE_SYNPROXY) {
s->src.state = PF_TCPS_PROXY_SRC;
@@ -2742,7 +3024,7 @@ cleanup:
bport, 0, af);
}
}
- s->src.seqhi = arc4random();
+ s->src.seqhi = htonl(arc4random());
/* Find mss option */
mss = pf_get_mss(m, off, th->th_off, af);
mss = pf_calc_mss(saddr, af, mss);
@@ -2750,7 +3032,8 @@ cleanup:
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_SYN|TH_ACK, 0, s->src.mss, 0, 1, NULL, NULL);
+ REASON_SET(&reason, PFRES_SYNPROXY);
return (PF_SYNPROXY_DROP);
}
}
@@ -2765,7 +3048,8 @@ cleanup:
int
pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
struct pfi_kif *kif, struct mbuf *m, int off, void *h,
- struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm)
+ struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
+ struct ifqueue *ifq)
{
struct pf_rule *nr = NULL;
struct pf_addr *saddr = pd->src, *daddr = pd->dst;
@@ -2782,6 +3066,12 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
int rewrite = 0;
struct pf_tag *pftag = NULL;
int tag = -1;
+ int asd = 0;
+
+ if (pf_check_congestion(ifq)) {
+ REASON_SET(&reason, PFRES_CONGEST);
+ return (PF_DROP);
+ }
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
@@ -2826,12 +3116,12 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
r = r->skip[PF_SKIP_AF].ptr;
else if (r->proto && r->proto != IPPROTO_UDP)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.not))
+ else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
else if (r->src.port_op && !pf_match_port(r->src.port_op,
r->src.port[0], r->src.port[1], uh->uh_sport))
r = r->skip[PF_SKIP_SRC_PORT].ptr;
- else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.not))
+ else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
r->dst.port[0], r->dst.port[1], uh->uh_dport))
@@ -2850,9 +3140,9 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
!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->prob && r->prob <= arc4random())
r = TAILQ_NEXT(r, entries);
- else if (r->anchorname[0] && r->anchor == NULL)
+ else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
r = TAILQ_NEXT(r, entries);
else if (r->os_fingerprint != PF_OSFP_ANY)
r = TAILQ_NEXT(r, entries);
@@ -2867,12 +3157,12 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
break;
r = TAILQ_NEXT(r, entries);
} else
- PF_STEP_INTO_ANCHOR(r, a, ruleset,
- PF_RULESET_FILTER);
+ pf_step_into_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
- if (r == NULL && a != NULL)
- PF_STEP_OUT_OF_ANCHOR(r, a, ruleset,
- PF_RULESET_FILTER);
+ if (r == NULL)
+ pf_step_out_of_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
r = *rm;
a = *am;
@@ -2923,21 +3213,29 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
struct pf_src_node *sn = NULL;
/* check maximums */
- if (r->max_states && (r->states >= r->max_states))
+ if (r->max_states && (r->states >= r->max_states)) {
+ pf_status.lcounters[LCNT_STATES]++;
+ REASON_SET(&reason, PFRES_MAXSTATES);
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)
+ pf_insert_src_node(&sn, r, saddr, af) != 0) {
+ REASON_SET(&reason, PFRES_SRCLIMIT);
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)))
+ (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
+ REASON_SET(&reason, PFRES_SRCLIMIT);
goto cleanup;
+ }
s = pool_get(&pf_state_pl, PR_NOWAIT);
if (s == NULL) {
+ REASON_SET(&reason, PFRES_MEMORY);
cleanup:
if (sn != NULL && sn->states == 0 && sn->expire == 0) {
RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
@@ -2952,18 +3250,13 @@ cleanup:
pf_status.src_nodes--;
pool_put(&pf_src_tree_pl, nsn);
}
- REASON_SET(&reason, PFRES_MEMORY);
return (PF_DROP);
}
bzero(s, sizeof(*s));
- r->states++;
- if (a != NULL)
- a->states++;
s->rule.ptr = r;
s->nat_rule.ptr = nr;
- if (s->nat_rule.ptr != NULL)
- s->nat_rule.ptr->states++;
s->anchor.ptr = a;
+ STATE_INC_COUNTERS(s);
s->allow_opts = r->allow_opts;
s->log = r->log & 2;
s->proto = IPPROTO_UDP;
@@ -2996,8 +3289,8 @@ cleanup:
}
s->src.state = PFUDPS_SINGLE;
s->dst.state = PFUDPS_NO_TRAFFIC;
- s->creation = time.tv_sec;
- s->expire = time.tv_sec;
+ s->creation = time_second;
+ s->expire = time_second;
s->timeout = PFTM_UDP_FIRST_PACKET;
pf_set_rt_ifp(s, saddr);
if (sn != NULL) {
@@ -3010,12 +3303,17 @@ cleanup:
s->nat_src_node->states++;
}
if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
- REASON_SET(&reason, PFRES_MEMORY);
+ REASON_SET(&reason, PFRES_STATEINS);
pf_src_tree_remove_state(s);
+ STATE_DEC_COUNTERS(s);
pool_put(&pf_state_pl, s);
return (PF_DROP);
} else
*sm = s;
+ if (tag > 0) {
+ pf_tag_ref(tag);
+ s->tag = tag;
+ }
}
/* copy back packet headers if we performed NAT operations */
@@ -3028,7 +3326,8 @@ cleanup:
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 pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm)
+ struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
+ struct ifqueue *ifq)
{
struct pf_rule *nr = NULL;
struct pf_addr *saddr = pd->src, *daddr = pd->dst;
@@ -3045,6 +3344,12 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
#ifdef INET6
int rewrite = 0;
#endif /* INET6 */
+ int asd = 0;
+
+ if (pf_check_congestion(ifq)) {
+ REASON_SET(&reason, PFRES_CONGEST);
+ return (PF_DROP);
+ }
switch (pd->proto) {
#ifdef INET
@@ -3081,7 +3386,7 @@ 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) {
+ saddr, icmpid, daddr, icmpid, &pd->naddr, NULL)) != NULL) {
PF_ACPY(&pd->baddr, saddr, af);
switch (af) {
#ifdef INET
@@ -3105,7 +3410,7 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
} 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) {
+ saddr, icmpid, daddr, icmpid, &pd->naddr, NULL)) != NULL) {
PF_ACPY(&pd->baddr, daddr, af);
switch (af) {
#ifdef INET
@@ -3139,9 +3444,9 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
r = r->skip[PF_SKIP_AF].ptr;
else if (r->proto && r->proto != pd->proto)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.not))
+ else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
- else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.not))
+ else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (r->type && r->type != icmptype + 1)
r = TAILQ_NEXT(r, entries);
@@ -3151,9 +3456,9 @@ 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->prob && r->prob <= arc4random())
r = TAILQ_NEXT(r, entries);
- else if (r->anchorname[0] && r->anchor == NULL)
+ else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
r = TAILQ_NEXT(r, entries);
else if (r->os_fingerprint != PF_OSFP_ANY)
r = TAILQ_NEXT(r, entries);
@@ -3168,12 +3473,12 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
break;
r = TAILQ_NEXT(r, entries);
} else
- PF_STEP_INTO_ANCHOR(r, a, ruleset,
- PF_RULESET_FILTER);
+ pf_step_into_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
- if (r == NULL && a != NULL)
- PF_STEP_OUT_OF_ANCHOR(r, a, ruleset,
- PF_RULESET_FILTER);
+ if (r == NULL)
+ pf_step_out_of_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
r = *rm;
a = *am;
@@ -3204,21 +3509,29 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
struct pf_src_node *sn = NULL;
/* check maximums */
- if (r->max_states && (r->states >= r->max_states))
+ if (r->max_states && (r->states >= r->max_states)) {
+ pf_status.lcounters[LCNT_STATES]++;
+ REASON_SET(&reason, PFRES_MAXSTATES);
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)
+ pf_insert_src_node(&sn, r, saddr, af) != 0) {
+ REASON_SET(&reason, PFRES_SRCLIMIT);
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)))
+ (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
+ REASON_SET(&reason, PFRES_SRCLIMIT);
goto cleanup;
+ }
s = pool_get(&pf_state_pl, PR_NOWAIT);
if (s == NULL) {
+ REASON_SET(&reason, PFRES_MEMORY);
cleanup:
if (sn != NULL && sn->states == 0 && sn->expire == 0) {
RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
@@ -3233,18 +3546,13 @@ cleanup:
pf_status.src_nodes--;
pool_put(&pf_src_tree_pl, nsn);
}
- REASON_SET(&reason, PFRES_MEMORY);
return (PF_DROP);
}
bzero(s, sizeof(*s));
- r->states++;
- if (a != NULL)
- a->states++;
s->rule.ptr = r;
s->nat_rule.ptr = nr;
- if (s->nat_rule.ptr != NULL)
- s->nat_rule.ptr->states++;
s->anchor.ptr = a;
+ STATE_INC_COUNTERS(s);
s->allow_opts = r->allow_opts;
s->log = r->log & 2;
s->proto = pd->proto;
@@ -3271,8 +3579,8 @@ cleanup:
PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
s->gwy.port = icmpid;
}
- s->creation = time.tv_sec;
- s->expire = time.tv_sec;
+ s->creation = time_second;
+ s->expire = time_second;
s->timeout = PFTM_ICMP_FIRST_PACKET;
pf_set_rt_ifp(s, saddr);
if (sn != NULL) {
@@ -3285,12 +3593,17 @@ cleanup:
s->nat_src_node->states++;
}
if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
- REASON_SET(&reason, PFRES_MEMORY);
+ REASON_SET(&reason, PFRES_STATEINS);
pf_src_tree_remove_state(s);
+ STATE_DEC_COUNTERS(s);
pool_put(&pf_state_pl, s);
return (PF_DROP);
} else
*sm = s;
+ if (tag > 0) {
+ pf_tag_ref(tag);
+ s->tag = tag;
+ }
}
#ifdef INET6
@@ -3306,7 +3619,7 @@ 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 pf_rule **am, struct pf_ruleset **rsm)
+ struct pf_rule **am, struct pf_ruleset **rsm, struct ifqueue *ifq)
{
struct pf_rule *nr = NULL;
struct pf_rule *r, *a = NULL;
@@ -3317,6 +3630,12 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
u_short reason;
struct pf_tag *pftag = NULL;
int tag = -1;
+ int asd = 0;
+
+ if (pf_check_congestion(ifq)) {
+ REASON_SET(&reason, PFRES_CONGEST);
+ return (PF_DROP);
+ }
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
@@ -3377,17 +3696,17 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
r = r->skip[PF_SKIP_AF].ptr;
else if (r->proto && r->proto != pd->proto)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.not))
+ else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
- else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.not))
+ else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (r->tos && !(r->tos & pd->tos))
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->prob && r->prob <= arc4random())
r = TAILQ_NEXT(r, entries);
- else if (r->anchorname[0] && r->anchor == NULL)
+ else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
r = TAILQ_NEXT(r, entries);
else if (r->os_fingerprint != PF_OSFP_ANY)
r = TAILQ_NEXT(r, entries);
@@ -3402,12 +3721,12 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
break;
r = TAILQ_NEXT(r, entries);
} else
- PF_STEP_INTO_ANCHOR(r, a, ruleset,
- PF_RULESET_FILTER);
+ pf_step_into_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
- if (r == NULL && a != NULL)
- PF_STEP_OUT_OF_ANCHOR(r, a, ruleset,
- PF_RULESET_FILTER);
+ if (r == NULL)
+ pf_step_out_of_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
r = *rm;
a = *am;
@@ -3466,21 +3785,29 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
struct pf_src_node *sn = NULL;
/* check maximums */
- if (r->max_states && (r->states >= r->max_states))
+ if (r->max_states && (r->states >= r->max_states)) {
+ pf_status.lcounters[LCNT_STATES]++;
+ REASON_SET(&reason, PFRES_MAXSTATES);
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)
+ pf_insert_src_node(&sn, r, saddr, af) != 0) {
+ REASON_SET(&reason, PFRES_SRCLIMIT);
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)))
+ (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
+ REASON_SET(&reason, PFRES_SRCLIMIT);
goto cleanup;
+ }
s = pool_get(&pf_state_pl, PR_NOWAIT);
if (s == NULL) {
+ REASON_SET(&reason, PFRES_MEMORY);
cleanup:
if (sn != NULL && sn->states == 0 && sn->expire == 0) {
RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
@@ -3495,18 +3822,13 @@ cleanup:
pf_status.src_nodes--;
pool_put(&pf_src_tree_pl, nsn);
}
- REASON_SET(&reason, PFRES_MEMORY);
return (PF_DROP);
}
bzero(s, sizeof(*s));
- r->states++;
- if (a != NULL)
- a->states++;
s->rule.ptr = r;
s->nat_rule.ptr = nr;
- if (s->nat_rule.ptr != NULL)
- s->nat_rule.ptr->states++;
s->anchor.ptr = a;
+ STATE_INC_COUNTERS(s);
s->allow_opts = r->allow_opts;
s->log = r->log & 2;
s->proto = pd->proto;
@@ -3529,8 +3851,8 @@ cleanup:
}
s->src.state = PFOTHERS_SINGLE;
s->dst.state = PFOTHERS_NO_TRAFFIC;
- s->creation = time.tv_sec;
- s->expire = time.tv_sec;
+ s->creation = time_second;
+ s->expire = time_second;
s->timeout = PFTM_OTHER_FIRST_PACKET;
pf_set_rt_ifp(s, saddr);
if (sn != NULL) {
@@ -3543,12 +3865,17 @@ cleanup:
s->nat_src_node->states++;
}
if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
- REASON_SET(&reason, PFRES_MEMORY);
+ REASON_SET(&reason, PFRES_STATEINS);
pf_src_tree_remove_state(s);
+ STATE_DEC_COUNTERS(s);
pool_put(&pf_state_pl, s);
return (PF_DROP);
} else
*sm = s;
+ if (tag > 0) {
+ pf_tag_ref(tag);
+ s->tag = tag;
+ }
}
return (PF_PASS);
@@ -3565,6 +3892,7 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
u_short reason;
struct pf_tag *pftag = NULL;
int tag = -1;
+ int asd = 0;
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
while (r != NULL) {
@@ -3578,9 +3906,9 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
r = r->skip[PF_SKIP_AF].ptr;
else if (r->proto && r->proto != pd->proto)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.not))
+ else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
- else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.not))
+ else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (r->tos && !(r->tos & pd->tos))
r = TAILQ_NEXT(r, entries);
@@ -3588,9 +3916,9 @@ 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->prob && r->prob <= arc4random())
r = TAILQ_NEXT(r, entries);
- else if (r->anchorname[0] && r->anchor == NULL)
+ else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
r = TAILQ_NEXT(r, entries);
else {
if (r->anchor == NULL) {
@@ -3601,12 +3929,12 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
break;
r = TAILQ_NEXT(r, entries);
} else
- PF_STEP_INTO_ANCHOR(r, a, ruleset,
- PF_RULESET_FILTER);
+ pf_step_into_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
- if (r == NULL && a != NULL)
- PF_STEP_OUT_OF_ANCHOR(r, a, ruleset,
- PF_RULESET_FILTER);
+ if (r == NULL)
+ pf_step_out_of_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
r = *rm;
a = *am;
@@ -3636,7 +3964,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
struct pf_state key;
struct tcphdr *th = pd->hdr.tcp;
u_int16_t win = ntohs(th->th_win);
- u_int32_t ack, end, seq;
+ u_int32_t ack, end, seq, orig_seq;
u_int8_t sws, dws;
int ackskew;
int copyback = 0;
@@ -3667,21 +3995,32 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
}
if ((*state)->src.state == PF_TCPS_PROXY_SRC) {
- if (direction != (*state)->direction)
+ if (direction != (*state)->direction) {
+ REASON_SET(reason, PFRES_SYNPROXY);
return (PF_SYNPROXY_DROP);
+ }
if (th->th_flags & TH_SYN) {
- if (ntohl(th->th_seq) != (*state)->src.seqlo)
+ if (ntohl(th->th_seq) != (*state)->src.seqlo) {
+ REASON_SET(reason, PFRES_SYNPROXY);
return (PF_DROP);
+ }
pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
pd->src, th->th_dport, th->th_sport,
(*state)->src.seqhi, ntohl(th->th_seq) + 1,
- TH_SYN|TH_ACK, 0, (*state)->src.mss, 0);
+ TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1,
+ NULL, NULL);
+ REASON_SET(reason, PFRES_SYNPROXY);
return (PF_SYNPROXY_DROP);
} else if (!(th->th_flags & TH_ACK) ||
(ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
- (ntohl(th->th_seq) != (*state)->src.seqlo + 1))
+ (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
+ REASON_SET(reason, PFRES_SYNPROXY);
return (PF_DROP);
- else
+ } else if ((*state)->src_node != NULL &&
+ pf_src_connlimit(state)) {
+ REASON_SET(reason, PFRES_SRCLIMIT);
+ return (PF_DROP);
+ } else
(*state)->src.state = PF_TCPS_PROXY_DST;
}
if ((*state)->src.state == PF_TCPS_PROXY_DST) {
@@ -3697,31 +4036,37 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
if (direction == (*state)->direction) {
if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) ||
(ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
- (ntohl(th->th_seq) != (*state)->src.seqlo + 1))
+ (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
+ REASON_SET(reason, PFRES_SYNPROXY);
return (PF_DROP);
+ }
(*state)->src.max_win = MAX(ntohs(th->th_win), 1);
if ((*state)->dst.seqhi == 1)
- (*state)->dst.seqhi = arc4random();
+ (*state)->dst.seqhi = htonl(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)->src.mss, 0, 0, NULL, NULL);
+ REASON_SET(reason, PFRES_SYNPROXY);
return (PF_SYNPROXY_DROP);
} else if (((th->th_flags & (TH_SYN|TH_ACK)) !=
(TH_SYN|TH_ACK)) ||
- (ntohl(th->th_ack) != (*state)->dst.seqhi + 1))
+ (ntohl(th->th_ack) != (*state)->dst.seqhi + 1)) {
+ REASON_SET(reason, PFRES_SYNPROXY);
return (PF_DROP);
- else {
+ } else {
(*state)->dst.max_win = MAX(ntohs(th->th_win), 1);
(*state)->dst.seqlo = ntohl(th->th_seq);
pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
pd->src, th->th_dport, th->th_sport,
ntohl(th->th_ack), ntohl(th->th_seq) + 1,
- TH_ACK, (*state)->src.max_win, 0, 0);
+ TH_ACK, (*state)->src.max_win, 0, 0, 0,
+ NULL, NULL);
pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
&dst->addr, src->port, dst->port,
(*state)->src.seqhi + 1, (*state)->src.seqlo + 1,
- TH_ACK, (*state)->dst.max_win, 0, 0);
+ TH_ACK, (*state)->dst.max_win, 0, 0, 1,
+ NULL, NULL);
(*state)->src.seqdiff = (*state)->dst.seqhi -
(*state)->src.seqlo;
(*state)->dst.seqdiff = (*state)->src.seqhi -
@@ -3733,6 +4078,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
(*state)->src.wscale = (*state)->dst.wscale = 0;
(*state)->src.state = (*state)->dst.state =
TCPS_ESTABLISHED;
+ REASON_SET(reason, PFRES_SYNPROXY);
return (PF_SYNPROXY_DROP);
}
}
@@ -3749,7 +4095,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
* tcp_filtering.ps
*/
- seq = ntohl(th->th_seq);
+ orig_seq = seq = ntohl(th->th_seq);
if (src->seqlo == 0) {
/* First packet from this end. Set its state */
@@ -3763,7 +4109,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
/* Deferred generation of sequence number modulator */
if (dst->seqdiff && !src->seqdiff) {
- while ((src->seqdiff = arc4random()) == 0)
+ while ((src->seqdiff = htonl(arc4random())) == 0)
;
ack = ntohl(th->th_ack) - dst->seqdiff;
pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
@@ -3859,8 +4205,17 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
/* Retrans: not more than one window back */
(ackskew >= -MAXACKWINDOW) &&
/* Acking not more than one reassembled fragment backwards */
- (ackskew <= (MAXACKWINDOW << sws))) {
+ (ackskew <= (MAXACKWINDOW << sws)) &&
/* Acking not more than one window forward */
+ ((th->th_flags & TH_RST) == 0 || orig_seq == src->seqlo ||
+ (pd->flags & PFDESC_IP_REAS) == 0)) {
+ /* Require an exact sequence match on resets when possible */
+
+ if (dst->scrub || src->scrub) {
+ if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
+ *state, src, dst, &copyback))
+ return (PF_DROP);
+ }
/* update max window */
if (src->max_win < win)
@@ -3881,16 +4236,22 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
if (src->state < TCPS_CLOSING)
src->state = TCPS_CLOSING;
if (th->th_flags & TH_ACK) {
- if (dst->state == TCPS_SYN_SENT)
+ if (dst->state == TCPS_SYN_SENT) {
dst->state = TCPS_ESTABLISHED;
- else if (dst->state == TCPS_CLOSING)
+ if (src->state == TCPS_ESTABLISHED &&
+ (*state)->src_node != NULL &&
+ pf_src_connlimit(state)) {
+ REASON_SET(reason, PFRES_SRCLIMIT);
+ return (PF_DROP);
+ }
+ } else if (dst->state == TCPS_CLOSING)
dst->state = TCPS_FIN_WAIT_2;
}
if (th->th_flags & TH_RST)
src->state = dst->state = TCPS_TIME_WAIT;
/* update expire time */
- (*state)->expire = time.tv_sec;
+ (*state)->expire = time_second;
if (src->state >= TCPS_FIN_WAIT_2 &&
dst->state >= TCPS_FIN_WAIT_2)
(*state)->timeout = PFTM_TCP_CLOSED;
@@ -3946,6 +4307,12 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
(*state)->packets[0], (*state)->packets[1]);
}
+ if (dst->scrub || src->scrub) {
+ if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
+ *state, src, dst, &copyback))
+ return (PF_DROP);
+ }
+
/* update max window */
if (src->max_win < win)
src->max_win = win;
@@ -3973,19 +4340,13 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
if ((*state)->dst.state == TCPS_SYN_SENT &&
(*state)->src.state == TCPS_SYN_SENT) {
/* Send RST for state mismatches during handshake */
- if (!(th->th_flags & TH_RST)) {
- u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
-
- if (th->th_flags & TH_SYN)
- ack++;
- if (th->th_flags & TH_FIN)
- ack++;
+ if (!(th->th_flags & TH_RST))
pf_send_tcp((*state)->rule.ptr, pd->af,
pd->dst, pd->src, th->th_dport,
- th->th_sport, ntohl(th->th_ack), ack,
- TH_RST|TH_ACK, 0, 0,
- (*state)->rule.ptr->return_ttl);
- }
+ th->th_sport, ntohl(th->th_ack), 0,
+ TH_RST, 0, 0,
+ (*state)->rule.ptr->return_ttl, 1,
+ pd->eh, kif->pfik_ifp);
src->seqlo = 0;
src->seqhi = 1;
src->max_win = 1;
@@ -4007,15 +4368,10 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) ?' ' :'5',
SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW) ?' ' :'6');
}
+ REASON_SET(reason, PFRES_BADSTATE);
return (PF_DROP);
}
- if (dst->scrub || src->scrub) {
- if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
- src, dst, &copyback))
- return (PF_DROP);
- }
-
/* Any packets which have gotten here are to be passed */
/* translate source/destination address, if necessary */
@@ -4076,7 +4432,7 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
dst->state = PFUDPS_MULTIPLE;
/* update expire time */
- (*state)->expire = time.tv_sec;
+ (*state)->expire = time_second;
if (src->state == PFUDPS_MULTIPLE && dst->state == PFUDPS_MULTIPLE)
(*state)->timeout = PFTM_UDP_MULTIPLE;
else
@@ -4100,7 +4456,7 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
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)
+ struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason)
{
struct pf_addr *saddr = pd->src, *daddr = pd->dst;
u_int16_t icmpid, *icmpsum;
@@ -4161,7 +4517,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
STATE_LOOKUP();
- (*state)->expire = time.tv_sec;
+ (*state)->expire = time_second;
(*state)->timeout = PFTM_ICMP_ERROR_REPLY;
/* translate source/destination address, if necessary */
@@ -4236,7 +4592,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
ipoff2 = off + ICMP_MINLEN;
if (!pf_pull_hdr(m, ipoff2, &h2, sizeof(h2),
- NULL, NULL, pd2.af)) {
+ NULL, reason, pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: ICMP error message too short "
"(ip)\n"));
@@ -4246,8 +4602,10 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
* ICMP error messages don't refer to non-first
* fragments
*/
- if (h2.ip_off & htons(IP_OFFMASK))
+ if (h2.ip_off & htons(IP_OFFMASK)) {
+ REASON_SET(reason, PFRES_FRAG);
return (PF_DROP);
+ }
/* offset of protocol header that follows h2 */
off2 = ipoff2 + (h2.ip_hl << 2);
@@ -4263,7 +4621,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
ipoff2 = off + sizeof(struct icmp6_hdr);
if (!pf_pull_hdr(m, ipoff2, &h2_6, sizeof(h2_6),
- NULL, NULL, pd2.af)) {
+ NULL, reason, pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: ICMP error message too short "
"(ip6)\n"));
@@ -4281,6 +4639,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
* ICMPv6 error messages for
* non-first fragments
*/
+ REASON_SET(reason, PFRES_FRAG);
return (PF_DROP);
case IPPROTO_AH:
case IPPROTO_HOPOPTS:
@@ -4290,7 +4649,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
struct ip6_ext opt6;
if (!pf_pull_hdr(m, off2, &opt6,
- sizeof(opt6), NULL, NULL, pd2.af)) {
+ sizeof(opt6), NULL, reason,
+ pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: ICMPv6 short opt\n"));
return (PF_DROP);
@@ -4326,7 +4686,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
* expected. Don't access any TCP header fields after
* th_seq, an ackskew test is not possible.
*/
- if (!pf_pull_hdr(m, off2, &th, 8, NULL, NULL, pd2.af)) {
+ if (!pf_pull_hdr(m, off2, &th, 8, NULL, reason,
+ pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: ICMP error message too short "
"(tcp)\n"));
@@ -4383,6 +4744,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
pf_print_state(*state);
printf(" seq=%u\n", seq);
}
+ REASON_SET(reason, PFRES_BADSTATE);
return (PF_DROP);
}
@@ -4434,7 +4796,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
struct pf_state key;
if (!pf_pull_hdr(m, off2, &uh, sizeof(uh),
- NULL, NULL, pd2.af)) {
+ NULL, reason, pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: ICMP error message too short "
"(udp)\n"));
@@ -4501,7 +4863,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
struct pf_state key;
if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN,
- NULL, NULL, pd2.af)) {
+ NULL, reason, pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: ICMP error message too short i"
"(icmp)\n"));
@@ -4553,7 +4915,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
struct pf_state key;
if (!pf_pull_hdr(m, off2, &iih,
- sizeof(struct icmp6_hdr), NULL, NULL, pd2.af)) {
+ sizeof(struct icmp6_hdr), NULL, reason, pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: ICMP error message too short "
"(icmp6)\n"));
@@ -4699,7 +5061,7 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
dst->state = PFOTHERS_MULTIPLE;
/* update expire time */
- (*state)->expire = time.tv_sec;
+ (*state)->expire = time_second;
if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE)
(*state)->timeout = PFTM_OTHER_MULTIPLE;
else
@@ -4797,18 +5159,80 @@ int
pf_routable(struct pf_addr *addr, sa_family_t af)
{
struct sockaddr_in *dst;
+#ifdef INET6
+ struct sockaddr_in6 *dst6;
+ struct route_in6 ro;
+#else
struct route ro;
+#endif
+
+ bzero(&ro, sizeof(ro));
+ switch (af) {
+ case AF_INET:
+ dst = satosin(&ro.ro_dst);
+ dst->sin_family = AF_INET;
+ dst->sin_len = sizeof(*dst);
+ dst->sin_addr = addr->v4;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
+ dst6->sin6_family = AF_INET6;
+ dst6->sin6_len = sizeof(*dst6);
+ dst6->sin6_addr = addr->v6;
+ break;
+#endif /* INET6 */
+ default:
+ return (0);
+ }
+
+ rtalloc_noclone((struct route *)&ro, NO_CLONING);
+
+ if (ro.ro_rt != NULL) {
+ RTFREE(ro.ro_rt);
+ return (1);
+ }
+
+ return (0);
+}
+
+int
+pf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw)
+{
+ struct sockaddr_in *dst;
+#ifdef INET6
+ struct sockaddr_in6 *dst6;
+ struct route_in6 ro;
+#else
+ struct route ro;
+#endif
int ret = 0;
bzero(&ro, sizeof(ro));
- dst = satosin(&ro.ro_dst);
- dst->sin_family = af;
- dst->sin_len = sizeof(*dst);
- dst->sin_addr = addr->v4;
- rtalloc_noclone(&ro, NO_CLONING);
+ switch (af) {
+ case AF_INET:
+ dst = satosin(&ro.ro_dst);
+ dst->sin_family = AF_INET;
+ dst->sin_len = sizeof(*dst);
+ dst->sin_addr = addr->v4;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
+ dst6->sin6_family = AF_INET6;
+ dst6->sin6_len = sizeof(*dst6);
+ dst6->sin6_addr = addr->v6;
+ break;
+#endif /* INET6 */
+ default:
+ return (0);
+ }
+
+ rtalloc_noclone((struct route *)&ro, NO_CLONING);
if (ro.ro_rt != NULL) {
- ret = 1;
+ if (ro.ro_rt->rt_labelid == aw->v.rtlabel)
+ ret = 1;
RTFREE(ro.ro_rt);
}
@@ -4856,17 +5280,18 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
if (r->rt == PF_DUPTO) {
if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
return;
- if ((mtag = m_tag_copy(mtag)) == NULL)
- goto bad;
- m_tag_prepend(m0, mtag);
} else {
if ((r->rt == PF_REPLYTO) == (r->direction == dir))
return;
m0 = *m;
}
- if (m0->m_len < sizeof(struct ip))
- panic("pf_route: m0->m_len < sizeof(struct ip)");
+ if (m0->m_len < sizeof(struct ip)) {
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_route: m0->m_len < sizeof(struct ip)\n"));
+ goto bad;
+ }
+
ip = mtod(m0, struct ip *);
ro = &iproute;
@@ -4889,8 +5314,11 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
if (ro->ro_rt->rt_flags & RTF_GATEWAY)
dst = satosin(ro->ro_rt->rt_gateway);
} else {
- if (TAILQ_EMPTY(&r->rpool.list))
- panic("pf_route: TAILQ_EMPTY(&r->rpool.list)");
+ if (TAILQ_EMPTY(&r->rpool.list)) {
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_route: TAILQ_EMPTY(&r->rpool.list)\n"));
+ goto bad;
+ }
if (s == NULL) {
pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src,
&naddr, NULL, &sn);
@@ -4909,12 +5337,15 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
goto bad;
if (oifp != ifp) {
- if (pf_test(PF_OUT, ifp, &m0) != PF_PASS)
+ if (pf_test(PF_OUT, ifp, &m0, NULL) != PF_PASS)
goto bad;
else if (m0 == NULL)
goto done;
- if (m0->m_len < sizeof(struct ip))
- panic("pf_route: m0->m_len < sizeof(struct ip)");
+ if (m0->m_len < sizeof(struct ip)) {
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_route: m0->m_len < sizeof(struct ip)\n"));
+ goto bad;
+ }
ip = mtod(m0, struct ip *);
}
@@ -5053,17 +5484,17 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
if (r->rt == PF_DUPTO) {
if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
return;
- if ((mtag = m_tag_copy(mtag)) == NULL)
- goto bad;
- m_tag_prepend(m0, mtag);
} else {
if ((r->rt == PF_REPLYTO) == (r->direction == dir))
return;
m0 = *m;
}
- if (m0->m_len < sizeof(struct ip6_hdr))
- panic("pf_route6: m0->m_len < sizeof(struct ip6_hdr)");
+ if (m0->m_len < sizeof(struct ip6_hdr)) {
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
+ goto bad;
+ }
ip6 = mtod(m0, struct ip6_hdr *);
ro = &ip6route;
@@ -5083,8 +5514,11 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
return;
}
- if (TAILQ_EMPTY(&r->rpool.list))
- panic("pf_route6: TAILQ_EMPTY(&r->rpool.list)");
+ if (TAILQ_EMPTY(&r->rpool.list)) {
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_route6: TAILQ_EMPTY(&r->rpool.list)\n"));
+ goto bad;
+ }
if (s == NULL) {
pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src,
&naddr, NULL, &sn);
@@ -5102,12 +5536,15 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
goto bad;
if (oifp != ifp) {
- if (pf_test6(PF_OUT, ifp, &m0) != PF_PASS)
+ if (pf_test6(PF_OUT, ifp, &m0, NULL) != PF_PASS)
goto bad;
else if (m0 == NULL)
goto done;
- if (m0->m_len < sizeof(struct ip6_hdr))
- panic("pf_route6: m0->m_len < sizeof(struct ip6_hdr)");
+ if (m0->m_len < sizeof(struct ip6_hdr)) {
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
+ goto bad;
+ }
ip6 = mtod(m0, struct ip6_hdr *);
}
@@ -5178,7 +5615,8 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p,
return (1);
if (m->m_pkthdr.len < off + len)
return (1);
- switch (af) {
+ switch (af) {
+#ifdef INET
case AF_INET:
if (p == IPPROTO_ICMP) {
if (m->m_len < off)
@@ -5194,6 +5632,7 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p,
sum = in4_cksum(m, p, off, len);
}
break;
+#endif /* INET */
#ifdef INET6
case AF_INET6:
if (m->m_len < sizeof(struct ip6_hdr))
@@ -5244,7 +5683,8 @@ pf_add_mbuf_tag(struct mbuf *m, u_int tag)
#ifdef INET
int
-pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
+pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
+ struct ether_header *eh)
{
struct pfi_kif *kif;
u_short action, reason = 0, log = 0;
@@ -5260,14 +5700,22 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
(m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL))
return (PF_PASS);
+ if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
+ ifp = ifp->if_carpdev;
+
kif = pfi_index2kif[ifp->if_index];
- if (kif == NULL)
+ if (kif == NULL) {
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_test: kif == NULL, if_xname %s\n", ifp->if_xname));
return (PF_DROP);
+ }
+ if (kif->pfik_flags & PFI_IFLAG_SKIP)
+ return (PF_PASS);
#ifdef DIAGNOSTIC
if ((m->m_flags & M_PKTHDR) == 0)
panic("non-M_PKTHDR is passed to pf_test");
-#endif
+#endif /* DIAGNOSTIC */
memset(&pd, 0, sizeof(pd));
if (m->m_pkthdr.len < (int)sizeof(*h)) {
@@ -5278,7 +5726,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, kif, &reason, &pd) != PF_PASS) {
action = PF_DROP;
goto done;
}
@@ -5301,6 +5749,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
pd.af = AF_INET;
pd.tos = h->ip_tos;
pd.tot_len = ntohs(h->ip_len);
+ pd.eh = eh;
/* handle fragments that didn't get reassembled by normalization */
if (h->ip_off & htons(IP_MF | IP_OFFMASK)) {
@@ -5336,13 +5785,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
if (action == PF_PASS) {
#if NPFSYNC
pfsync_update_state(s);
-#endif
+#endif /* NPFSYNC */
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);
+ m, off, h, &pd, &a, &ruleset, &ipintrq);
break;
}
@@ -5370,13 +5819,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
if (action == PF_PASS) {
#if NPFSYNC
pfsync_update_state(s);
-#endif
+#endif /* NPFSYNC */
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);
+ m, off, h, &pd, &a, &ruleset, &ipintrq);
break;
}
@@ -5394,17 +5843,18 @@ 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, kif, m, off, h, &pd,
+ &reason);
if (action == PF_PASS) {
#if NPFSYNC
pfsync_update_state(s);
-#endif
+#endif /* NPFSYNC */
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
action = pf_test_icmp(&r, &s, dir, kif,
- m, off, h, &pd, &a, &ruleset);
+ m, off, h, &pd, &a, &ruleset, &ipintrq);
break;
}
@@ -5413,13 +5863,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
if (action == PF_PASS) {
#if NPFSYNC
pfsync_update_state(s);
-#endif
+#endif /* NPFSYNC */
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);
+ &pd, &a, &ruleset, &ipintrq);
break;
}
@@ -5427,12 +5877,15 @@ done:
if (action == PF_PASS && h->ip_hl > 5 &&
!((s && s->allow_opts) || r->allow_opts)) {
action = PF_DROP;
- REASON_SET(&reason, PFRES_SHORT);
+ REASON_SET(&reason, PFRES_IPOPTIONS);
log = 1;
DPFPRINTF(PF_DEBUG_MISC,
("pf: dropping packet with ip options\n"));
}
+ if (s && s->tag)
+ pf_tag_packet(m, pf_get_tag(m), s->tag);
+
#ifdef ALTQ
if (action == PF_PASS && r->qid) {
struct m_tag *mtag;
@@ -5451,7 +5904,7 @@ done:
m_tag_prepend(m, mtag);
}
}
-#endif
+#endif /* ALTQ */
/*
* connections redirected to loopback should not match sockets
@@ -5526,12 +5979,12 @@ done:
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);
+ tr->src.neg);
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);
+ tr->dst.neg);
}
@@ -5549,7 +6002,8 @@ done:
#ifdef INET6
int
-pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
+pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
+ struct ether_header *eh)
{
struct pfi_kif *kif;
u_short action, reason = 0, log = 0;
@@ -5565,14 +6019,22 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
(m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL))
return (PF_PASS);
+ if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
+ ifp = ifp->if_carpdev;
+
kif = pfi_index2kif[ifp->if_index];
- if (kif == NULL)
+ if (kif == NULL) {
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_test6: kif == NULL, if_xname %s\n", ifp->if_xname));
return (PF_DROP);
+ }
+ if (kif->pfik_flags & PFI_IFLAG_SKIP)
+ return (PF_PASS);
#ifdef DIAGNOSTIC
if ((m->m_flags & M_PKTHDR) == 0)
- panic("non-M_PKTHDR is passed to pf_test");
-#endif
+ panic("non-M_PKTHDR is passed to pf_test6");
+#endif /* DIAGNOSTIC */
memset(&pd, 0, sizeof(pd));
if (m->m_pkthdr.len < (int)sizeof(*h)) {
@@ -5583,7 +6045,7 @@ 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, kif, &reason, &pd) != PF_PASS) {
action = PF_DROP;
goto done;
}
@@ -5597,6 +6059,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
pd.af = AF_INET6;
pd.tos = 0;
pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr);
+ pd.eh = eh;
off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr);
pd.proto = h->ip6_nxt;
@@ -5616,11 +6079,10 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
struct ip6_ext opt6;
if (!pf_pull_hdr(m, off, &opt6, sizeof(opt6),
- NULL, NULL, pd.af)) {
+ NULL, &reason, pd.af)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: IPv6 short opt\n"));
action = PF_DROP;
- REASON_SET(&reason, PFRES_SHORT);
log = 1;
goto done;
}
@@ -5650,8 +6112,10 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
goto done;
}
if (dir == PF_IN && pf_check_proto_cksum(m, off,
- ntohs(h->ip6_plen), IPPROTO_TCP, AF_INET6)) {
+ ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
+ IPPROTO_TCP, AF_INET6)) {
action = PF_DROP;
+ REASON_SET(&reason, PFRES_PROTCKSUM);
goto done;
}
pd.p_len = pd.tot_len - off - (th.th_off << 2);
@@ -5663,13 +6127,13 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
if (action == PF_PASS) {
#if NPFSYNC
pfsync_update_state(s);
-#endif
+#endif /* NPFSYNC */
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);
+ m, off, h, &pd, &a, &ruleset, &ip6intrq);
break;
}
@@ -5683,8 +6147,10 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
goto done;
}
if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
- off, ntohs(h->ip6_plen), IPPROTO_UDP, AF_INET6)) {
+ off, ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
+ IPPROTO_UDP, AF_INET6)) {
action = PF_DROP;
+ REASON_SET(&reason, PFRES_PROTCKSUM);
goto done;
}
if (uh.uh_dport == 0 ||
@@ -5697,13 +6163,13 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
if (action == PF_PASS) {
#if NPFSYNC
pfsync_update_state(s);
-#endif
+#endif /* NPFSYNC */
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);
+ m, off, h, &pd, &a, &ruleset, &ip6intrq);
break;
}
@@ -5717,40 +6183,48 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
goto done;
}
if (dir == PF_IN && pf_check_proto_cksum(m, off,
- ntohs(h->ip6_plen), IPPROTO_ICMPV6, AF_INET6)) {
+ ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
+ IPPROTO_ICMPV6, AF_INET6)) {
action = PF_DROP;
+ REASON_SET(&reason, PFRES_PROTCKSUM);
goto done;
}
action = pf_test_state_icmp(&s, dir, kif,
- m, off, h, &pd);
+ m, off, h, &pd, &reason);
if (action == PF_PASS) {
#if NPFSYNC
pfsync_update_state(s);
-#endif
+#endif /* NPFSYNC */
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
action = pf_test_icmp(&r, &s, dir, kif,
- m, off, h, &pd, &a, &ruleset);
+ m, off, h, &pd, &a, &ruleset, &ip6intrq);
break;
}
default:
action = pf_test_state_other(&s, dir, kif, &pd);
if (action == PF_PASS) {
+#if NPFSYNC
+ pfsync_update_state(s);
+#endif /* NPFSYNC */
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);
+ &pd, &a, &ruleset, &ip6intrq);
break;
}
done:
/* XXX handle IPv6 options, if not allowed. not implemented. */
+ if (s && s->tag)
+ pf_tag_packet(m, pf_get_tag(m), s->tag);
+
#ifdef ALTQ
if (action == PF_PASS && r->qid) {
struct m_tag *mtag;
@@ -5769,7 +6243,7 @@ done:
m_tag_prepend(m, mtag);
}
}
-#endif
+#endif /* ALTQ */
if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
@@ -5839,12 +6313,12 @@ done:
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);
+ tr->src.neg);
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);
+ tr->dst.neg);
}
@@ -5859,3 +6333,12 @@ done:
return (action);
}
#endif /* INET6 */
+
+int
+pf_check_congestion(struct ifqueue *ifq)
+{
+ if (ifq->ifq_congestion)
+ return (1);
+ else
+ return (0);
+}
diff --git a/sys/contrib/pf/net/pf_if.c b/sys/contrib/pf/net/pf_if.c
index a3d5f4175f01..26ce0ee731e6 100644
--- a/sys/contrib/pf/net/pf_if.c
+++ b/sys/contrib/pf/net/pf_if.c
@@ -1,5 +1,4 @@
-/* $OpenBSD: pf_if.c,v 1.11 2004/03/15 11:38:23 cedric Exp $ */
-/* add $OpenBSD: pf_if.c,v 1.19 2004/08/11 12:06:44 henning Exp $ */
+/* $OpenBSD: pf_if.c,v 1.23 2004/12/22 17:17:55 dhartmei Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -43,7 +42,6 @@
#include <net/if.h>
#include <net/if_types.h>
-#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
@@ -77,10 +75,6 @@ long pfi_update = 1;
struct pfr_addr *pfi_buffer;
int pfi_buffer_cnt;
int pfi_buffer_max;
-char pfi_reserved_anchor[PF_ANCHOR_NAME_SIZE] =
- PF_RESERVED_ANCHOR;
-char pfi_interface_ruleset[PF_RULESET_NAME_SIZE] =
- PF_INTERFACE_RULESET;
void pfi_dynaddr_update(void *);
void pfi_kifaddr_update(void *);
@@ -91,7 +85,6 @@ void pfi_address_add(struct sockaddr *, int, int);
int pfi_if_compare(struct pfi_kif *, struct pfi_kif *);
struct pfi_kif *pfi_if_create(const char *, struct pfi_kif *, int);
void pfi_copy_group(char *, const char *, int);
-void pfi_dynamic_drivers(void);
void pfi_newgroup(const char *, int);
int pfi_skip_if(const char *, struct pfi_kif *, int);
int pfi_unmask(void *);
@@ -100,7 +93,6 @@ void pfi_dohooks(struct pfi_kif *);
RB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
-#define PFI_DYNAMIC_BUSES { "pcmcia", "cardbus", "uhub" }
#define PFI_BUFFER_MAX 0x10000
#define PFI_MTYPE M_IFADDR
@@ -117,7 +109,6 @@ pfi_initialize(void)
pfi_buffer = malloc(pfi_buffer_max * sizeof(*pfi_buffer),
PFI_MTYPE, M_WAITOK);
pfi_self = pfi_if_create("self", NULL, PFI_IFLAG_GROUP);
- pfi_dynamic_drivers();
}
void
@@ -230,7 +221,12 @@ pfi_lookup_create(const char *name)
if (p == NULL) {
pfi_copy_group(key.pfik_name, name, sizeof(key.pfik_name));
q = pfi_lookup_if(key.pfik_name);
- if (q != NULL)
+ if (q == NULL) {
+ pfi_newgroup(key.pfik_name, PFI_IFLAG_DYNAMIC);
+ q = pfi_lookup_if(key.pfik_name);
+ }
+ p = pfi_lookup_if(name);
+ if (p == NULL && q != NULL)
p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE);
}
splx(s);
@@ -316,8 +312,7 @@ pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af)
if (dyn->pfid_net != 128)
snprintf(tblname + strlen(tblname),
sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net);
- ruleset = pf_find_or_create_ruleset(pfi_reserved_anchor,
- pfi_interface_ruleset);
+ ruleset = pf_find_or_create_ruleset(PF_RESERVED_ANCHOR);
if (ruleset == NULL)
senderr(1);
@@ -354,11 +349,14 @@ void
pfi_dynaddr_update(void *p)
{
struct pfi_dynaddr *dyn = (struct pfi_dynaddr *)p;
- struct pfi_kif *kif = dyn->pfid_kif;
- struct pfr_ktable *kt = dyn->pfid_kt;
+ struct pfi_kif *kif;
+ struct pfr_ktable *kt;
- if (dyn == NULL || kif == NULL || kt == NULL)
+ if (dyn == NULL || dyn->pfid_kif == NULL || dyn->pfid_kt == NULL)
panic("pfi_dynaddr_update");
+
+ kif = dyn->pfid_kif;
+ kt = dyn->pfid_kt;
if (kt->pfrkt_larg != pfi_update) {
/* this table needs to be brought up-to-date */
pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags);
@@ -412,8 +410,6 @@ pfi_instance_add(struct ifnet *ifp, int net, int flags)
af = ia->ifa_addr->sa_family;
if (af != AF_INET && af != AF_INET6)
continue;
- if (!(ia->ifa_flags & IFA_ROUTE))
- continue;
if ((flags & PFI_AFLAG_BROADCAST) && af == AF_INET6)
continue;
if ((flags & PFI_AFLAG_BROADCAST) &&
@@ -434,14 +430,14 @@ pfi_instance_add(struct ifnet *ifp, int net, int flags)
}
if (af == AF_INET)
got4 = 1;
- else
+ else if (af == AF_INET6)
got6 = 1;
net2 = net;
if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) {
if (af == AF_INET) {
net2 = pfi_unmask(&((struct sockaddr_in *)
ia->ifa_netmask)->sin_addr);
- } else {
+ } else if (af == AF_INET6) {
net2 = pfi_unmask(&((struct sockaddr_in6 *)
ia->ifa_netmask)->sin6_addr);
}
@@ -574,7 +570,7 @@ pfi_if_create(const char *name, struct pfi_kif *q, int flags)
RB_INIT(&p->pfik_ext_gwy);
p->pfik_flags = flags;
p->pfik_parent = q;
- p->pfik_tzero = time.tv_sec;
+ p->pfik_tzero = time_second;
RB_INSERT(pfi_ifhead, &pfi_ifs, p);
if (q != NULL) {
@@ -629,46 +625,6 @@ pfi_copy_group(char *p, const char *q, int m)
}
void
-pfi_dynamic_drivers(void)
-{
- char *buses[] = PFI_DYNAMIC_BUSES;
- int nbuses = sizeof(buses)/sizeof(buses[0]);
- int enabled[sizeof(buses)/sizeof(buses[0])];
- struct device *dev;
- struct cfdata *cf;
- struct cfdriver *drv;
- short *p;
- int i;
-
- bzero(enabled, sizeof(enabled));
- TAILQ_FOREACH(dev, &alldevs, dv_list) {
- if (!(dev->dv_flags & DVF_ACTIVE))
- continue;
- for (i = 0; i < nbuses; i++)
- if (!enabled[i] && !strcmp(buses[i],
- dev->dv_cfdata->cf_driver->cd_name))
- enabled[i] = 1;
- }
- for (cf = cfdata; cf->cf_driver; cf++) {
- if (cf->cf_driver->cd_class != DV_IFNET)
- continue;
- for (p = cf->cf_parents; p && *p >= 0; p++) {
- if ((drv = cfdata[*p].cf_driver) == NULL)
- continue;
- for (i = 0; i < nbuses; i++)
- if (enabled[i] &&
- !strcmp(drv->cd_name, buses[i]))
- break;
- if (i < nbuses) {
- pfi_newgroup(cf->cf_driver->cd_name,
- PFI_IFLAG_DYNAMIC);
- break;
- }
- }
- }
-}
-
-void
pfi_newgroup(const char *name, int flags)
{
struct pfi_kif *p;
@@ -714,10 +670,10 @@ pfi_clr_istats(const char *name, int *nzero, int flags)
{
struct pfi_kif *p;
int n = 0, s;
- long tzero = time.tv_sec;
+ long tzero = time_second;
- s = splsoftnet();
ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE);
+ s = splsoftnet();
RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
if (pfi_skip_if(name, p, flags))
continue;
@@ -733,6 +689,44 @@ pfi_clr_istats(const char *name, int *nzero, int flags)
}
int
+pfi_set_flags(const char *name, int flags)
+{
+ struct pfi_kif *p;
+ int s;
+
+ if (flags & ~PFI_IFLAG_SETABLE_MASK)
+ return (EINVAL);
+
+ s = splsoftnet();
+ RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
+ if (pfi_skip_if(name, p, PFI_FLAG_GROUP|PFI_FLAG_INSTANCE))
+ continue;
+ p->pfik_flags |= flags;
+ }
+ splx(s);
+ return (0);
+}
+
+int
+pfi_clear_flags(const char *name, int flags)
+{
+ struct pfi_kif *p;
+ int s;
+
+ if (flags & ~PFI_IFLAG_SETABLE_MASK)
+ return (EINVAL);
+
+ s = splsoftnet();
+ RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
+ if (pfi_skip_if(name, p, PFI_FLAG_GROUP|PFI_FLAG_INSTANCE))
+ continue;
+ p->pfik_flags &= ~flags;
+ }
+ splx(s);
+ return (0);
+}
+
+int
pfi_get_ifaces(const char *name, struct pfi_if *buf, int *size, int flags)
{
struct pfi_kif *p;
@@ -745,7 +739,7 @@ pfi_get_ifaces(const char *name, struct pfi_if *buf, int *size, int flags)
continue;
if (*size > n++) {
if (!p->pfik_tzero)
- p->pfik_tzero = boottime.tv_sec;
+ p->pfik_tzero = time_second;
if (copyout(p, buf++, sizeof(*buf))) {
splx(s);
return (EFAULT);
@@ -820,7 +814,9 @@ pfi_dohooks(struct pfi_kif *p)
int
pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
{
- if (af == AF_INET) {
+ switch (af) {
+#ifdef INET
+ case AF_INET:
switch (dyn->pfid_acnt4) {
case 0:
return (0);
@@ -830,7 +826,10 @@ pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
default:
return (pfr_match_addr(dyn->pfid_kt, a, AF_INET));
}
- } else {
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
switch (dyn->pfid_acnt6) {
case 0:
return (0);
@@ -840,5 +839,9 @@ pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
default:
return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6));
}
+ break;
+#endif /* INET6 */
+ default:
+ return (0);
}
}
diff --git a/sys/contrib/pf/net/pf_ioctl.c b/sys/contrib/pf/net/pf_ioctl.c
index f6b7ee967dd9..f73c67b852fc 100644
--- a/sys/contrib/pf/net/pf_ioctl.c
+++ b/sys/contrib/pf/net/pf_ioctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_ioctl.c,v 1.112.2.2 2004/07/24 18:28:12 brad Exp $ */
+/* $OpenBSD: pf_ioctl.c,v 1.139 2005/03/03 07:13:39 dhartmei Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -80,10 +80,16 @@
void pfattach(int);
int pfopen(dev_t, int, int, struct proc *);
int pfclose(dev_t, int, int, struct proc *);
-struct pf_pool *pf_get_pool(char *, char *, u_int32_t,
- u_int8_t, u_int32_t, u_int8_t, u_int8_t, u_int8_t);
+struct pf_pool *pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t,
+ u_int8_t, u_int8_t, u_int8_t);
int pf_get_ruleset_number(u_int8_t);
void pf_init_ruleset(struct pf_ruleset *);
+int pf_anchor_setup(struct pf_rule *,
+ const struct pf_ruleset *, const char *);
+int pf_anchor_copyout(const struct pf_ruleset *,
+ const struct pf_rule *, struct pfioc_rule *);
+void pf_anchor_remove(struct pf_rule *);
+
void pf_mv_pool(struct pf_palist *, struct pf_palist *);
void pf_empty_pool(struct pf_palist *);
int pfioctl(dev_t, u_long, caddr_t, int, struct proc *);
@@ -91,14 +97,19 @@ int pfioctl(dev_t, u_long, caddr_t, int, struct proc *);
int pf_begin_altq(u_int32_t *);
int pf_rollback_altq(u_int32_t);
int pf_commit_altq(u_int32_t);
+int pf_enable_altq(struct pf_altq *);
+int pf_disable_altq(struct pf_altq *);
#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 *);
+int pf_begin_rules(u_int32_t *, int, const char *);
+int pf_rollback_rules(u_int32_t, int, char *);
+int pf_commit_rules(u_int32_t, int, char *);
extern struct timeout pf_expire_to;
struct pf_rule pf_default_rule;
+#ifdef ALTQ
+static int pf_altq_running;
+#endif
#define TAGID_MAX 50000
TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags),
@@ -110,6 +121,9 @@ TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags),
static u_int16_t tagname2tag(struct pf_tags *, char *);
static void tag2tagname(struct pf_tags *, u_int16_t, char *);
static void tag_unref(struct pf_tags *, u_int16_t);
+int pf_rtlabel_add(struct pf_addr_wrap *);
+void pf_rtlabel_remove(struct pf_addr_wrap *);
+void pf_rtlabel_copyout(struct pf_addr_wrap *);
#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x
@@ -125,9 +139,9 @@ pfattach(int num)
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",
- NULL);
+ &pool_allocator_nointr);
pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0,
- "pfpooladdrpl", NULL);
+ "pfpooladdrpl", &pool_allocator_nointr);
pfr_initialize();
pfi_initialize();
pf_osfp_initialize();
@@ -136,7 +150,7 @@ pfattach(int num)
pf_pool_limits[PF_LIMIT_STATES].limit, NULL, 0);
RB_INIT(&tree_src_tracking);
- TAILQ_INIT(&pf_anchors);
+ RB_INIT(&pf_anchors);
pf_init_ruleset(&pf_main_ruleset);
TAILQ_INIT(&pf_altqs[0]);
TAILQ_INIT(&pf_altqs[1]);
@@ -151,23 +165,24 @@ pfattach(int num)
pf_default_rule.nr = -1;
/* initialize default timeouts */
- timeout[PFTM_TCP_FIRST_PACKET] = 120; /* First TCP packet */
- 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 */
- timeout[PFTM_TCP_CLOSED] = 90; /* Got a RST */
- timeout[PFTM_UDP_FIRST_PACKET] = 60; /* First UDP packet */
- timeout[PFTM_UDP_SINGLE] = 30; /* Unidirectional */
- timeout[PFTM_UDP_MULTIPLE] = 60; /* Bidirectional */
- timeout[PFTM_ICMP_FIRST_PACKET] = 20; /* First ICMP packet */
- timeout[PFTM_ICMP_ERROR_REPLY] = 10; /* Got error response */
- timeout[PFTM_OTHER_FIRST_PACKET] = 60; /* First packet */
- timeout[PFTM_OTHER_SINGLE] = 30; /* Unidirectional */
- 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[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
+ timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
+ timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
+ timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
+ timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
+ timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
+ timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
+ timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
+ timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
+ timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
+ timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
+ timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
+ timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
+ timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
+ timeout[PFTM_FRAG] = PFTM_FRAG_VAL;
+ timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
+ timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
+ timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
timeout_set(&pf_expire_to, pf_purge_timeout, &pf_expire_to);
timeout_add(&pf_expire_to, timeout[PFTM_INTERVAL] * hz);
@@ -197,15 +212,15 @@ pfclose(dev_t dev, int flags, int fmt, struct proc *p)
}
struct pf_pool *
-pf_get_pool(char *anchorname, char *rulesetname, u_int32_t ticket,
- u_int8_t rule_action, u_int32_t rule_number, u_int8_t r_last,
- u_int8_t active, u_int8_t check_ticket)
+pf_get_pool(char *anchor, u_int32_t ticket, 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;
struct pf_rule *rule;
int rs_num;
- ruleset = pf_find_ruleset(anchorname, rulesetname);
+ ruleset = pf_find_ruleset(anchor);
if (ruleset == NULL)
return (NULL);
rs_num = pf_get_ruleset_number(rule_action);
@@ -245,6 +260,7 @@ pf_get_ruleset_number(u_int8_t action)
{
switch (action) {
case PF_SCRUB:
+ case PF_NOSCRUB:
return (PF_RULESET_SCRUB);
break;
case PF_PASS:
@@ -284,118 +300,245 @@ pf_init_ruleset(struct pf_ruleset *ruleset)
}
struct pf_anchor *
-pf_find_anchor(const char *anchorname)
+pf_find_anchor(const char *path)
{
- struct pf_anchor *anchor;
- int n = -1;
+ static struct pf_anchor key;
- anchor = TAILQ_FIRST(&pf_anchors);
- while (anchor != NULL && (n = strcmp(anchor->name, anchorname)) < 0)
- anchor = TAILQ_NEXT(anchor, entries);
- if (n == 0)
- return (anchor);
- else
- return (NULL);
+ memset(&key, 0, sizeof(key));
+ strlcpy(key.path, path, sizeof(key.path));
+ return (RB_FIND(pf_anchor_global, &pf_anchors, &key));
}
struct pf_ruleset *
-pf_find_ruleset(char *anchorname, char *rulesetname)
+pf_find_ruleset(const char *path)
{
struct pf_anchor *anchor;
- struct pf_ruleset *ruleset;
- if (!anchorname[0] && !rulesetname[0])
+ while (*path == '/')
+ path++;
+ if (!*path)
return (&pf_main_ruleset);
- if (!anchorname[0] || !rulesetname[0])
- return (NULL);
- anchorname[PF_ANCHOR_NAME_SIZE-1] = 0;
- rulesetname[PF_RULESET_NAME_SIZE-1] = 0;
- anchor = pf_find_anchor(anchorname);
+ anchor = pf_find_anchor(path);
if (anchor == NULL)
return (NULL);
- ruleset = TAILQ_FIRST(&anchor->rulesets);
- while (ruleset != NULL && strcmp(ruleset->name, rulesetname) < 0)
- ruleset = TAILQ_NEXT(ruleset, entries);
- if (ruleset != NULL && !strcmp(ruleset->name, rulesetname))
- return (ruleset);
else
- return (NULL);
+ return (&anchor->ruleset);
}
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(const char *path)
{
- struct pf_anchor *anchor, *a;
- struct pf_ruleset *ruleset, *r;
+ static char p[MAXPATHLEN];
+ char *q, *r;
+ struct pf_ruleset *ruleset;
+ struct pf_anchor *anchor, *dup, *parent = NULL;
- if (!anchorname[0] && !rulesetname[0])
- return (&pf_main_ruleset);
- if (!anchorname[0] || !rulesetname[0])
+ while (*path == '/')
+ path++;
+ ruleset = pf_find_ruleset(path);
+ if (ruleset != NULL)
+ return (ruleset);
+ strlcpy(p, path, sizeof(p));
+ while (parent == NULL && (q = strrchr(p, '/')) != NULL) {
+ *q = 0;
+ if ((ruleset = pf_find_ruleset(p)) != NULL) {
+ parent = ruleset->anchor;
+ break;
+ }
+ }
+ if (q == NULL)
+ q = p;
+ else
+ q++;
+ strlcpy(p, path, sizeof(p));
+ if (!*q)
return (NULL);
- anchorname[PF_ANCHOR_NAME_SIZE-1] = 0;
- rulesetname[PF_RULESET_NAME_SIZE-1] = 0;
- a = TAILQ_FIRST(&pf_anchors);
- while (a != NULL && strcmp(a->name, anchorname) < 0)
- a = TAILQ_NEXT(a, entries);
- if (a != NULL && !strcmp(a->name, anchorname))
- anchor = a;
- else {
- anchor = (struct pf_anchor *)malloc(sizeof(struct pf_anchor),
- M_TEMP, M_NOWAIT);
+ while ((r = strchr(q, '/')) != NULL || *q) {
+ if (r != NULL)
+ *r = 0;
+ if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
+ (parent != NULL && strlen(parent->path) >=
+ MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1))
+ return (NULL);
+ anchor = (struct pf_anchor *)malloc(sizeof(*anchor), M_TEMP,
+ M_NOWAIT);
if (anchor == NULL)
return (NULL);
- memset(anchor, 0, sizeof(struct pf_anchor));
- bcopy(anchorname, anchor->name, sizeof(anchor->name));
- TAILQ_INIT(&anchor->rulesets);
- if (a != NULL)
- TAILQ_INSERT_BEFORE(a, anchor, entries);
- else
- TAILQ_INSERT_TAIL(&pf_anchors, anchor, entries);
- }
- r = TAILQ_FIRST(&anchor->rulesets);
- while (r != NULL && strcmp(r->name, rulesetname) < 0)
- r = TAILQ_NEXT(r, entries);
- if (r != NULL && !strcmp(r->name, rulesetname))
- return (r);
- ruleset = (struct pf_ruleset *)malloc(sizeof(struct pf_ruleset),
- M_TEMP, M_NOWAIT);
- if (ruleset != NULL) {
- pf_init_ruleset(ruleset);
- bcopy(rulesetname, ruleset->name, sizeof(ruleset->name));
- ruleset->anchor = anchor;
+ memset(anchor, 0, sizeof(*anchor));
+ RB_INIT(&anchor->children);
+ strlcpy(anchor->name, q, sizeof(anchor->name));
+ if (parent != NULL) {
+ strlcpy(anchor->path, parent->path,
+ sizeof(anchor->path));
+ strlcat(anchor->path, "/", sizeof(anchor->path));
+ }
+ strlcat(anchor->path, anchor->name, sizeof(anchor->path));
+ if ((dup = RB_INSERT(pf_anchor_global, &pf_anchors, anchor)) !=
+ NULL) {
+ printf("pf_find_or_create_ruleset: RB_INSERT1 "
+ "'%s' '%s' collides with '%s' '%s'\n",
+ anchor->path, anchor->name, dup->path, dup->name);
+ free(anchor, M_TEMP);
+ return (NULL);
+ }
+ if (parent != NULL) {
+ anchor->parent = parent;
+ if ((dup = RB_INSERT(pf_anchor_node, &parent->children,
+ anchor)) != NULL) {
+ printf("pf_find_or_create_ruleset: "
+ "RB_INSERT2 '%s' '%s' collides with "
+ "'%s' '%s'\n", anchor->path, anchor->name,
+ dup->path, dup->name);
+ RB_REMOVE(pf_anchor_global, &pf_anchors,
+ anchor);
+ free(anchor, M_TEMP);
+ return (NULL);
+ }
+ }
+ pf_init_ruleset(&anchor->ruleset);
+ anchor->ruleset.anchor = anchor;
+ parent = anchor;
if (r != NULL)
- TAILQ_INSERT_BEFORE(r, ruleset, entries);
+ q = r + 1;
else
- TAILQ_INSERT_TAIL(&anchor->rulesets, ruleset, entries);
+ *q = 0;
}
- return (ruleset);
+ return (&anchor->ruleset);
}
void
pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
{
- struct pf_anchor *anchor;
+ struct pf_anchor *parent;
int i;
- if (ruleset == NULL || ruleset->anchor == NULL || ruleset->tables > 0 ||
- ruleset->topen)
- return;
- for (i = 0; i < PF_RULESET_MAX; ++i)
- if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
- !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) ||
- ruleset->rules[i].inactive.open)
+ while (ruleset != NULL) {
+ if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL ||
+ !RB_EMPTY(&ruleset->anchor->children) ||
+ ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
+ ruleset->topen)
return;
+ for (i = 0; i < PF_RULESET_MAX; ++i)
+ if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
+ !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) ||
+ ruleset->rules[i].inactive.open)
+ return;
+ RB_REMOVE(pf_anchor_global, &pf_anchors, ruleset->anchor);
+ if ((parent = ruleset->anchor->parent) != NULL)
+ RB_REMOVE(pf_anchor_node, &parent->children,
+ ruleset->anchor);
+ free(ruleset->anchor, M_TEMP);
+ if (parent == NULL)
+ return;
+ ruleset = &parent->ruleset;
+ }
+}
- anchor = ruleset->anchor;
- TAILQ_REMOVE(&anchor->rulesets, ruleset, entries);
- free(ruleset, M_TEMP);
+int
+pf_anchor_setup(struct pf_rule *r, const struct pf_ruleset *s,
+ const char *name)
+{
+ static char *p, path[MAXPATHLEN];
+ struct pf_ruleset *ruleset;
- if (TAILQ_EMPTY(&anchor->rulesets)) {
- TAILQ_REMOVE(&pf_anchors, anchor, entries);
- free(anchor, M_TEMP);
- pf_update_anchor_rules();
+ r->anchor = NULL;
+ r->anchor_relative = 0;
+ r->anchor_wildcard = 0;
+ if (!name[0])
+ return (0);
+ if (name[0] == '/')
+ strlcpy(path, name + 1, sizeof(path));
+ else {
+ /* relative path */
+ r->anchor_relative = 1;
+ if (s->anchor == NULL || !s->anchor->path[0])
+ path[0] = 0;
+ else
+ strlcpy(path, s->anchor->path, sizeof(path));
+ while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
+ if (!path[0]) {
+ printf("pf_anchor_setup: .. beyond root\n");
+ return (1);
+ }
+ if ((p = strrchr(path, '/')) != NULL)
+ *p = 0;
+ else
+ path[0] = 0;
+ r->anchor_relative++;
+ name += 3;
+ }
+ if (path[0])
+ strlcat(path, "/", sizeof(path));
+ strlcat(path, name, sizeof(path));
+ }
+ if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
+ r->anchor_wildcard = 1;
+ *p = 0;
}
+ ruleset = pf_find_or_create_ruleset(path);
+ if (ruleset == NULL || ruleset->anchor == NULL) {
+ printf("pf_anchor_setup: ruleset\n");
+ return (1);
+ }
+ r->anchor = ruleset->anchor;
+ r->anchor->refcnt++;
+ return (0);
+}
+
+int
+pf_anchor_copyout(const struct pf_ruleset *rs, const struct pf_rule *r,
+ struct pfioc_rule *pr)
+{
+ pr->anchor_call[0] = 0;
+ if (r->anchor == NULL)
+ return (0);
+ if (!r->anchor_relative) {
+ strlcpy(pr->anchor_call, "/", sizeof(pr->anchor_call));
+ strlcat(pr->anchor_call, r->anchor->path,
+ sizeof(pr->anchor_call));
+ } else {
+ char a[MAXPATHLEN], b[MAXPATHLEN], *p;
+ int i;
+
+ if (rs->anchor == NULL)
+ a[0] = 0;
+ else
+ strlcpy(a, rs->anchor->path, sizeof(a));
+ strlcpy(b, r->anchor->path, sizeof(b));
+ for (i = 1; i < r->anchor_relative; ++i) {
+ if ((p = strrchr(a, '/')) == NULL)
+ p = a;
+ *p = 0;
+ strlcat(pr->anchor_call, "../",
+ sizeof(pr->anchor_call));
+ }
+ if (strncmp(a, b, strlen(a))) {
+ printf("pf_anchor_copyout: '%s' '%s'\n", a, b);
+ return (1);
+ }
+ if (strlen(b) > strlen(a))
+ strlcat(pr->anchor_call, b + (a[0] ? strlen(a) + 1 : 0),
+ sizeof(pr->anchor_call));
+ }
+ if (r->anchor_wildcard)
+ strlcat(pr->anchor_call, pr->anchor_call[0] ? "/*" : "*",
+ sizeof(pr->anchor_call));
+ return (0);
+}
+
+void
+pf_anchor_remove(struct pf_rule *r)
+{
+ if (r->anchor == NULL)
+ return;
+ if (r->anchor->refcnt <= 0) {
+ printf("pf_anchor_remove: broken refcount");
+ r->anchor = NULL;
+ return;
+ }
+ if (!--r->anchor->refcnt)
+ pf_remove_if_empty_ruleset(&r->anchor->ruleset);
+ r->anchor = NULL;
}
void
@@ -435,6 +578,8 @@ pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
*/
pf_tbladdr_remove(&rule->src.addr);
pf_tbladdr_remove(&rule->dst.addr);
+ if (rule->overload_tbl)
+ pfr_detach_table(rule->overload_tbl);
}
TAILQ_REMOVE(rulequeue, rule, entries);
rule->entries.tqe_prev = NULL;
@@ -451,13 +596,18 @@ pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
pf_qid_unref(rule->pqid);
pf_qid_unref(rule->qid);
#endif
+ pf_rtlabel_remove(&rule->src.addr);
+ pf_rtlabel_remove(&rule->dst.addr);
pfi_dynaddr_remove(&rule->src.addr);
pfi_dynaddr_remove(&rule->dst.addr);
if (rulequeue == NULL) {
pf_tbladdr_remove(&rule->src.addr);
pf_tbladdr_remove(&rule->dst.addr);
+ if (rule->overload_tbl)
+ pfr_detach_table(rule->overload_tbl);
}
pfi_detach_rule(rule->kif);
+ pf_anchor_remove(rule);
pf_empty_pool(&rule->rpool.list);
pool_put(&pf_rule_pl, rule);
}
@@ -552,11 +702,54 @@ pf_tag2tagname(u_int16_t tagid, char *p)
}
void
+pf_tag_ref(u_int16_t tag)
+{
+ struct pf_tagname *t;
+
+ TAILQ_FOREACH(t, &pf_tags, entries)
+ if (t->tag == tag)
+ break;
+ if (t != NULL)
+ t->ref++;
+}
+
+void
pf_tag_unref(u_int16_t tag)
{
return (tag_unref(&pf_tags, tag));
}
+int
+pf_rtlabel_add(struct pf_addr_wrap *a)
+{
+ if (a->type == PF_ADDR_RTLABEL &&
+ (a->v.rtlabel = rtlabel_name2id(a->v.rtlabelname)) == 0)
+ return (-1);
+ return (0);
+}
+
+void
+pf_rtlabel_remove(struct pf_addr_wrap *a)
+{
+ if (a->type == PF_ADDR_RTLABEL)
+ rtlabel_unref(a->v.rtlabel);
+}
+
+void
+pf_rtlabel_copyout(struct pf_addr_wrap *a)
+{
+ const char *name;
+
+ if (a->type == PF_ADDR_RTLABEL && a->v.rtlabel) {
+ if ((name = rtlabel_id2name(a->v.rtlabel)) == NULL)
+ strlcpy(a->v.rtlabelname, "?",
+ sizeof(a->v.rtlabelname));
+ else
+ strlcpy(a->v.rtlabelname, name,
+ sizeof(a->v.rtlabelname));
+ }
+}
+
#ifdef ALTQ
u_int32_t
pf_qname2qid(char *qname)
@@ -643,7 +836,9 @@ pf_commit_altq(u_int32_t ticket)
if (altq->qname[0] == 0) {
/* attach the discipline */
error = altq_pfattach(altq);
- if (error) {
+ if (error == 0 && pf_altq_running)
+ error = pf_enable_altq(altq);
+ if (error != 0) {
splx(s);
return (error);
}
@@ -655,6 +850,8 @@ pf_commit_altq(u_int32_t ticket)
TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
if (altq->qname[0] == 0) {
/* detach and destroy the discipline */
+ if (pf_altq_running)
+ error = pf_disable_altq(altq);
err = altq_pfdetach(altq);
if (err != 0 && error == 0)
error = err;
@@ -670,17 +867,72 @@ pf_commit_altq(u_int32_t ticket)
altqs_inactive_open = 0;
return (error);
}
+
+int
+pf_enable_altq(struct pf_altq *altq)
+{
+ struct ifnet *ifp;
+ struct tb_profile tb;
+ int s, error = 0;
+
+ if ((ifp = ifunit(altq->ifname)) == NULL)
+ return (EINVAL);
+
+ if (ifp->if_snd.altq_type != ALTQT_NONE)
+ error = altq_enable(&ifp->if_snd);
+
+ /* set tokenbucket regulator */
+ if (error == 0 && ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) {
+ tb.rate = altq->ifbandwidth;
+ tb.depth = altq->tbrsize;
+ s = splimp();
+ error = tbr_set(&ifp->if_snd, &tb);
+ splx(s);
+ }
+
+ return (error);
+}
+
+int
+pf_disable_altq(struct pf_altq *altq)
+{
+ struct ifnet *ifp;
+ struct tb_profile tb;
+ int s, error;
+
+ if ((ifp = ifunit(altq->ifname)) == NULL)
+ return (EINVAL);
+
+ /*
+ * when the discipline is no longer referenced, it was overridden
+ * by a new one. if so, just return.
+ */
+ if (altq->altq_disc != ifp->if_snd.altq_disc)
+ return (0);
+
+ error = altq_disable(&ifp->if_snd);
+
+ if (error == 0) {
+ /* clear tokenbucket regulator */
+ tb.rate = 0;
+ s = splimp();
+ error = tbr_set(&ifp->if_snd, &tb);
+ splx(s);
+ }
+
+ return (error);
+}
#endif /* ALTQ */
int
-pf_begin_rules(u_int32_t *ticket, int rs_num, char *anchor, char *ruleset)
+pf_begin_rules(u_int32_t *ticket, int rs_num, const char *anchor)
{
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);
+ rs = pf_find_or_create_ruleset(anchor);
if (rs == NULL)
return (EINVAL);
while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL)
@@ -691,14 +943,14 @@ pf_begin_rules(u_int32_t *ticket, int rs_num, char *anchor, char *ruleset)
}
int
-pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor, char *ruleset)
+pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor)
{
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);
+ rs = pf_find_ruleset(anchor);
if (rs == NULL || !rs->rules[rs_num].inactive.open ||
rs->rules[rs_num].inactive.ticket != ticket)
return (0);
@@ -709,7 +961,7 @@ pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor, char *ruleset)
}
int
-pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor, char *ruleset)
+pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
{
struct pf_ruleset *rs;
struct pf_rule *rule;
@@ -718,7 +970,7 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor, char *ruleset)
if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
return (EINVAL);
- rs = pf_find_ruleset(anchor, ruleset);
+ rs = pf_find_ruleset(anchor);
if (rs == NULL || !rs->rules[rs_num].inactive.open ||
ticket != rs->rules[rs_num].inactive.ticket)
return (EBUSY);
@@ -738,7 +990,6 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor, char *ruleset)
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);
}
@@ -771,8 +1022,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCGETALTQS:
case DIOCGETALTQ:
case DIOCGETQSTATS:
- case DIOCGETANCHORS:
- case DIOCGETANCHOR:
case DIOCGETRULESETS:
case DIOCGETRULESET:
case DIOCRGETTABLES:
@@ -791,6 +1040,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCCLRSRCNODES:
case DIOCIGETIFACES:
case DIOCICLRISTATS:
+ case DIOCSETIFFLAG:
+ case DIOCCLRIFFLAG:
break;
case DIOCRCLRTABLES:
case DIOCRADDTABLES:
@@ -818,8 +1069,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCGETALTQS:
case DIOCGETALTQ:
case DIOCGETQSTATS:
- case DIOCGETANCHORS:
- case DIOCGETANCHOR:
case DIOCGETRULESETS:
case DIOCGETRULESET:
case DIOCRGETTABLES:
@@ -848,6 +1097,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
return (EACCES);
}
+ s = splsoftnet();
switch (cmd) {
case DIOCSTART:
@@ -855,9 +1105,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = EEXIST;
else {
pf_status.running = 1;
- pf_status.since = time.tv_sec;
+ pf_status.since = time_second;
if (pf_status.stateid == 0) {
- pf_status.stateid = time.tv_sec;
+ pf_status.stateid = time_second;
pf_status.stateid = pf_status.stateid << 32;
}
DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n"));
@@ -869,19 +1119,11 @@ 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;
+ pf_status.since = time_second;
DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
}
break;
- case DIOCBEGINRULES: {
- struct pfioc_rule *pr = (struct pfioc_rule *)addr;
-
- error = pf_begin_rules(&pr->ticket, pf_get_ruleset_number(
- pr->rule.action), pr->anchor, pr->ruleset);
- break;
- }
-
case DIOCADDRULE: {
struct pfioc_rule *pr = (struct pfioc_rule *)addr;
struct pf_ruleset *ruleset;
@@ -889,7 +1131,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
struct pf_pooladdr *pa;
int rs_num;
- ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
+ pr->anchor[sizeof(pr->anchor) - 1] = 0;
+ ruleset = pf_find_ruleset(pr->anchor);
if (ruleset == NULL) {
error = EINVAL;
break;
@@ -899,10 +1142,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = EINVAL;
break;
}
- if (pr->rule.anchorname[0] && ruleset != &pf_main_ruleset) {
- error = EINVAL;
- break;
- }
if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
error = EINVAL;
break;
@@ -979,6 +1218,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 (pf_rtlabel_add(&rule->src.addr) ||
+ pf_rtlabel_add(&rule->dst.addr))
+ error = EBUSY;
if (pfi_dynaddr_setup(&rule->src.addr, rule->af))
error = EINVAL;
if (pfi_dynaddr_setup(&rule->dst.addr, rule->af))
@@ -987,13 +1229,24 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = EINVAL;
if (pf_tbladdr_setup(ruleset, &rule->dst.addr))
error = EINVAL;
+ if (pf_anchor_setup(rule, ruleset, pr->anchor_call))
+ error = EINVAL;
TAILQ_FOREACH(pa, &pf_pabuf, entries)
if (pf_tbladdr_setup(ruleset, &pa->addr))
error = EINVAL;
+ if (rule->overload_tblname[0]) {
+ if ((rule->overload_tbl = pfr_attach_table(ruleset,
+ rule->overload_tblname)) == NULL)
+ error = EINVAL;
+ else
+ rule->overload_tbl->pfrkt_flags |=
+ PFR_TFLAG_ACTIVE;
+ }
+
pf_mv_pool(&pf_pabuf, &rule->rpool.list);
if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) ||
- (rule->action == PF_BINAT)) && !rule->anchorname[0]) ||
+ (rule->action == PF_BINAT)) && rule->anchor == NULL) ||
(rule->rt > PF_FASTROUTE)) &&
(TAILQ_FIRST(&rule->rpool.list) == NULL))
error = EINVAL;
@@ -1009,21 +1262,14 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
- case DIOCCOMMITRULES: {
- struct pfioc_rule *pr = (struct pfioc_rule *)addr;
-
- error = pf_commit_rules(pr->ticket, pf_get_ruleset_number(
- pr->rule.action), pr->anchor, pr->ruleset);
- break;
- }
-
case DIOCGETRULES: {
struct pfioc_rule *pr = (struct pfioc_rule *)addr;
struct pf_ruleset *ruleset;
struct pf_rule *tail;
int rs_num;
- ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
+ pr->anchor[sizeof(pr->anchor) - 1] = 0;
+ ruleset = pf_find_ruleset(pr->anchor);
if (ruleset == NULL) {
error = EINVAL;
break;
@@ -1033,7 +1279,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = EINVAL;
break;
}
- s = splsoftnet();
tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
pf_rulequeue);
if (tail)
@@ -1041,7 +1286,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
else
pr->nr = 0;
pr->ticket = ruleset->rules[rs_num].active.ticket;
- splx(s);
break;
}
@@ -1051,7 +1295,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
struct pf_rule *rule;
int rs_num, i;
- ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
+ pr->anchor[sizeof(pr->anchor) - 1] = 0;
+ ruleset = pf_find_ruleset(pr->anchor);
if (ruleset == NULL) {
error = EINVAL;
break;
@@ -1065,27 +1310,30 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = EBUSY;
break;
}
- s = splsoftnet();
rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
while ((rule != NULL) && (rule->nr != pr->nr))
rule = TAILQ_NEXT(rule, entries);
if (rule == NULL) {
error = EBUSY;
- splx(s);
break;
}
bcopy(rule, &pr->rule, sizeof(struct pf_rule));
+ if (pf_anchor_copyout(ruleset, rule, pr)) {
+ error = EBUSY;
+ break;
+ }
pfi_dynaddr_copyout(&pr->rule.src.addr);
pfi_dynaddr_copyout(&pr->rule.dst.addr);
pf_tbladdr_copyout(&pr->rule.src.addr);
pf_tbladdr_copyout(&pr->rule.dst.addr);
+ pf_rtlabel_copyout(&pr->rule.src.addr);
+ pf_rtlabel_copyout(&pr->rule.dst.addr);
for (i = 0; i < PF_SKIP_COUNT; ++i)
if (rule->skip[i].ptr == NULL)
pr->rule.skip[i].nr = -1;
else
pr->rule.skip[i].nr =
rule->skip[i].ptr->nr;
- splx(s);
break;
}
@@ -1108,7 +1356,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = EINVAL;
break;
}
- ruleset = pf_find_ruleset(pcr->anchor, pcr->ruleset);
+ ruleset = pf_find_ruleset(pcr->anchor);
if (ruleset == NULL) {
error = EINVAL;
break;
@@ -1182,7 +1430,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
} else
newrule->pqid = newrule->qid;
}
-#endif
+#endif /* ALTQ */
if (newrule->tagname[0])
if ((newrule->tag =
pf_tagname2tag(newrule->tagname)) == 0)
@@ -1191,9 +1439,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
if ((newrule->match_tag = pf_tagname2tag(
newrule->match_tagname)) == 0)
error = EBUSY;
-
if (newrule->rt && !newrule->direction)
error = EINVAL;
+ if (pf_rtlabel_add(&newrule->src.addr) ||
+ pf_rtlabel_add(&newrule->dst.addr))
+ error = EBUSY;
if (pfi_dynaddr_setup(&newrule->src.addr, newrule->af))
error = EINVAL;
if (pfi_dynaddr_setup(&newrule->dst.addr, newrule->af))
@@ -1202,13 +1452,25 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = EINVAL;
if (pf_tbladdr_setup(ruleset, &newrule->dst.addr))
error = EINVAL;
+ if (pf_anchor_setup(newrule, ruleset, pcr->anchor_call))
+ error = EINVAL;
+
+ if (newrule->overload_tblname[0]) {
+ if ((newrule->overload_tbl = pfr_attach_table(
+ ruleset, newrule->overload_tblname)) ==
+ NULL)
+ error = EINVAL;
+ else
+ newrule->overload_tbl->pfrkt_flags |=
+ PFR_TFLAG_ACTIVE;
+ }
pf_mv_pool(&pf_pabuf, &newrule->rpool.list);
if (((((newrule->action == PF_NAT) ||
(newrule->action == PF_RDR) ||
(newrule->action == PF_BINAT) ||
(newrule->rt > PF_FASTROUTE)) &&
- !newrule->anchorname[0])) &&
+ !pcr->anchor[0])) &&
(TAILQ_FIRST(&newrule->rpool.list) == NULL))
error = EINVAL;
@@ -1222,8 +1484,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
pf_empty_pool(&pf_pabuf);
- s = splsoftnet();
-
if (pcr->action == PF_CHANGE_ADD_HEAD)
oldrule = TAILQ_FIRST(
ruleset->rules[rs_num].active.ptr);
@@ -1239,7 +1499,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
if (newrule != NULL)
pf_rm_rule(NULL, newrule);
error = EINVAL;
- splx(s);
break;
}
}
@@ -1265,12 +1524,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
ruleset->rules[rs_num].active.ptr, entries)
oldrule->nr = nr++;
+ ruleset->rules[rs_num].active.ticket++;
+
pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
pf_remove_if_empty_ruleset(ruleset);
- pf_update_anchor_rules();
- ruleset->rules[rs_num].active.ticket++;
- splx(s);
break;
}
@@ -1279,7 +1537,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
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_ifname[0] || !strcmp(psk->psk_ifname,
state->u.s.kif->pfik_name)) {
@@ -1297,7 +1554,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
#if NPFSYNC
pfsync_clear_states(pf_status.hostid, psk->psk_ifname);
#endif
- splx(s);
break;
}
@@ -1306,16 +1562,15 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
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) &&
- PF_MATCHA(psk->psk_src.not,
+ PF_MATCHA(psk->psk_src.neg,
&psk->psk_src.addr.v.a.addr,
&psk->psk_src.addr.v.a.mask,
&state->lan.addr, state->af) &&
- PF_MATCHA(psk->psk_dst.not,
+ PF_MATCHA(psk->psk_dst.neg,
&psk->psk_dst.addr.v.a.addr,
&psk->psk_dst.addr.v.a.mask,
&state->ext.addr, state->af) &&
@@ -1334,7 +1589,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
}
pf_purge_expired_states();
- splx(s);
psk->psk_af = killed;
break;
}
@@ -1354,12 +1608,10 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = ENOMEM;
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));
@@ -1368,7 +1620,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
state->nat_rule.ptr = NULL;
state->anchor.ptr = NULL;
state->rt_kif = NULL;
- state->creation = time.tv_sec;
+ state->creation = time_second;
state->pfsync_time = 0;
state->packets[0] = state->packets[1] = 0;
state->bytes[0] = state->bytes[1] = 0;
@@ -1378,7 +1630,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
pool_put(&pf_state_pl, state);
error = ENOMEM;
}
- splx(s);
break;
}
@@ -1388,7 +1639,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
u_int32_t nr;
nr = 0;
- s = splsoftnet();
RB_FOREACH(state, pf_state_tree_id, &tree_id) {
if (nr >= ps->nr)
break;
@@ -1396,7 +1646,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
if (state == NULL) {
error = EBUSY;
- splx(s);
break;
}
bcopy(state, &ps->state, sizeof(struct pf_state));
@@ -1405,10 +1654,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
-1 : state->nat_rule.ptr->nr;
ps->state.anchor.nr = (state->anchor.ptr == NULL) ?
-1 : state->anchor.ptr->nr;
- splx(s);
ps->state.expire = pf_state_expires(state);
- if (ps->state.expire > time.tv_sec)
- ps->state.expire -= time.tv_sec;
+ if (ps->state.expire > time_second)
+ ps->state.expire -= time_second;
else
ps->state.expire = 0;
break;
@@ -1423,20 +1671,17 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
int space = ps->ps_len;
if (space == 0) {
- s = splsoftnet();
TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states)
nr += kif->pfik_states;
- splx(s);
ps->ps_len = sizeof(struct pf_state) * nr;
- return (0);
+ break;
}
- 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;
+ int secs = time_second;
if ((nr+1) * sizeof(*p) > (unsigned)ps->ps_len)
break;
@@ -1456,15 +1701,12 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
else
pstore.expire = 0;
error = copyout(&pstore, p, sizeof(*p));
- if (error) {
- splx(s);
+ if (error)
goto fail;
- }
p++;
nr++;
}
ps->ps_len = sizeof(struct pf_state) * nr;
- splx(s);
break;
}
@@ -1515,8 +1757,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
!pnl->dport || !pnl->sport)
error = EINVAL;
else {
- s = splsoftnet();
-
/*
* userland gives us source and dest of connection,
* reverse the lookup so we ask for what happens with
@@ -1556,7 +1796,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
} else
error = ENOENT;
- splx(s);
}
break;
}
@@ -1629,88 +1868,48 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
struct pf_ruleset *ruleset = &pf_main_ruleset;
struct pf_rule *rule;
- s = splsoftnet();
TAILQ_FOREACH(rule,
ruleset->rules[PF_RULESET_FILTER].active.ptr, entries)
rule->evaluations = rule->packets =
rule->bytes = 0;
- splx(s);
break;
}
#ifdef ALTQ
case DIOCSTARTALTQ: {
struct pf_altq *altq;
- struct ifnet *ifp;
- struct tb_profile tb;
/* enable 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;
- break;
- }
- if (ifp->if_snd.altq_type != ALTQT_NONE)
- error = altq_enable(&ifp->if_snd);
- if (error != 0)
- break;
- /* set tokenbucket regulator */
- tb.rate = altq->ifbandwidth;
- tb.depth = altq->tbrsize;
- error = tbr_set(&ifp->if_snd, &tb);
+ error = pf_enable_altq(altq);
if (error != 0)
break;
}
}
if (error == 0)
- pfaltq_running = 1;
- splx(s);
+ pf_altq_running = 1;
DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n"));
break;
}
case DIOCSTOPALTQ: {
struct pf_altq *altq;
- struct ifnet *ifp;
- struct tb_profile tb;
- int err;
/* 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;
+ error = pf_disable_altq(altq);
+ if (error != 0)
break;
- }
- if (ifp->if_snd.altq_type != ALTQT_NONE) {
- err = altq_disable(&ifp->if_snd);
- if (err != 0 && error == 0)
- error = err;
- }
- /* clear tokenbucket regulator */
- tb.rate = 0;
- err = tbr_set(&ifp->if_snd, &tb);
- if (err != 0 && error == 0)
- error = err;
}
}
if (error == 0)
- pfaltq_running = 0;
- splx(s);
+ pf_altq_running = 0;
DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n"));
break;
}
- case DIOCBEGINALTQS: {
- u_int32_t *ticket = (u_int32_t *)addr;
-
- error = pf_begin_altq(ticket);
- break;
- }
-
case DIOCADDALTQ: {
struct pfioc_altq *pa = (struct pfioc_altq *)addr;
struct pf_altq *altq, *a;
@@ -1756,23 +1955,14 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
- case DIOCCOMMITALTQS: {
- u_int32_t ticket = *(u_int32_t *)addr;
-
- error = pf_commit_altq(ticket);
- break;
- }
-
case DIOCGETALTQS: {
struct pfioc_altq *pa = (struct pfioc_altq *)addr;
struct pf_altq *altq;
pa->nr = 0;
- s = splsoftnet();
TAILQ_FOREACH(altq, pf_altqs_active, entries)
pa->nr++;
pa->ticket = ticket_altqs_active;
- splx(s);
break;
}
@@ -1786,7 +1976,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
nr = 0;
- s = splsoftnet();
altq = TAILQ_FIRST(pf_altqs_active);
while ((altq != NULL) && (nr < pa->nr)) {
altq = TAILQ_NEXT(altq, entries);
@@ -1794,11 +1983,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
if (altq == NULL) {
error = EBUSY;
- splx(s);
break;
}
bcopy(altq, &pa->altq, sizeof(struct pf_altq));
- splx(s);
break;
}
@@ -1819,7 +2006,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
nbytes = pq->nbytes;
nr = 0;
- s = splsoftnet();
altq = TAILQ_FIRST(pf_altqs_active);
while ((altq != NULL) && (nr < pq->nr)) {
altq = TAILQ_NEXT(altq, entries);
@@ -1827,11 +2013,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
if (altq == NULL) {
error = EBUSY;
- splx(s);
break;
}
error = altq_getqstats(altq, pq->buf, &nbytes);
- splx(s);
if (error == 0) {
pq->scheduler = altq->scheduler;
pq->nbytes = nbytes;
@@ -1898,17 +2082,14 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
pp->nr = 0;
- s = splsoftnet();
- pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket,
- pp->r_action, pp->r_num, 0, 1, 0);
+ pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action,
+ pp->r_num, 0, 1, 0);
if (pool == NULL) {
error = EBUSY;
- splx(s);
break;
}
TAILQ_FOREACH(pa, &pool->list, entries)
pp->nr++;
- splx(s);
break;
}
@@ -1916,12 +2097,10 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
u_int32_t nr = 0;
- s = splsoftnet();
- pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket,
- pp->r_action, pp->r_num, 0, 1, 1);
+ pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action,
+ pp->r_num, 0, 1, 1);
if (pool == NULL) {
error = EBUSY;
- splx(s);
break;
}
pa = TAILQ_FIRST(&pool->list);
@@ -1931,13 +2110,12 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
if (pa == NULL) {
error = EBUSY;
- splx(s);
break;
}
bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr));
pfi_dynaddr_copyout(&pp->addr.addr);
pf_tbladdr_copyout(&pp->addr.addr);
- splx(s);
+ pf_rtlabel_copyout(&pp->addr.addr);
break;
}
@@ -1958,13 +2136,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
- ruleset = pf_find_ruleset(pca->anchor, pca->ruleset);
+ ruleset = pf_find_ruleset(pca->anchor);
if (ruleset == NULL) {
error = EBUSY;
break;
}
- pool = pf_get_pool(pca->anchor, pca->ruleset, pca->ticket,
- pca->r_action, pca->r_num, pca->r_last, 1, 1);
+ pool = pf_get_pool(pca->anchor, pca->ticket, pca->r_action,
+ pca->r_num, pca->r_last, 1, 1);
if (pool == NULL) {
error = EBUSY;
break;
@@ -2009,8 +2187,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
}
- s = splsoftnet();
-
if (pca->action == PF_CHANGE_ADD_HEAD)
oldpa = TAILQ_FIRST(&pool->list);
else if (pca->action == PF_CHANGE_ADD_TAIL)
@@ -2025,7 +2201,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
if (oldpa == NULL) {
error = EINVAL;
- splx(s);
break;
}
}
@@ -2050,72 +2225,64 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
pool->cur = TAILQ_FIRST(&pool->list);
PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr,
pca->af);
- splx(s);
- break;
- }
-
- case DIOCGETANCHORS: {
- struct pfioc_anchor *pa = (struct pfioc_anchor *)addr;
- struct pf_anchor *anchor;
-
- pa->nr = 0;
- TAILQ_FOREACH(anchor, &pf_anchors, entries)
- pa->nr++;
- break;
- }
-
- case DIOCGETANCHOR: {
- struct pfioc_anchor *pa = (struct pfioc_anchor *)addr;
- struct pf_anchor *anchor;
- u_int32_t nr = 0;
-
- anchor = TAILQ_FIRST(&pf_anchors);
- while (anchor != NULL && nr < pa->nr) {
- anchor = TAILQ_NEXT(anchor, entries);
- nr++;
- }
- if (anchor == NULL)
- error = EBUSY;
- else
- bcopy(anchor->name, pa->name, sizeof(pa->name));
break;
}
case DIOCGETRULESETS: {
struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr;
- struct pf_anchor *anchor;
struct pf_ruleset *ruleset;
+ struct pf_anchor *anchor;
- pr->anchor[PF_ANCHOR_NAME_SIZE-1] = 0;
- if ((anchor = pf_find_anchor(pr->anchor)) == NULL) {
+ pr->path[sizeof(pr->path) - 1] = 0;
+ if ((ruleset = pf_find_ruleset(pr->path)) == NULL) {
error = EINVAL;
break;
}
pr->nr = 0;
- TAILQ_FOREACH(ruleset, &anchor->rulesets, entries)
- pr->nr++;
+ if (ruleset->anchor == NULL) {
+ /* XXX kludge for pf_main_ruleset */
+ RB_FOREACH(anchor, pf_anchor_global, &pf_anchors)
+ if (anchor->parent == NULL)
+ pr->nr++;
+ } else {
+ RB_FOREACH(anchor, pf_anchor_node,
+ &ruleset->anchor->children)
+ pr->nr++;
+ }
break;
}
case DIOCGETRULESET: {
struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr;
- struct pf_anchor *anchor;
struct pf_ruleset *ruleset;
+ struct pf_anchor *anchor;
u_int32_t nr = 0;
- if ((anchor = pf_find_anchor(pr->anchor)) == NULL) {
+ pr->path[sizeof(pr->path) - 1] = 0;
+ if ((ruleset = pf_find_ruleset(pr->path)) == NULL) {
error = EINVAL;
break;
}
- ruleset = TAILQ_FIRST(&anchor->rulesets);
- while (ruleset != NULL && nr < pr->nr) {
- ruleset = TAILQ_NEXT(ruleset, entries);
- nr++;
+ pr->name[0] = 0;
+ if (ruleset->anchor == NULL) {
+ /* XXX kludge for pf_main_ruleset */
+ RB_FOREACH(anchor, pf_anchor_global, &pf_anchors)
+ if (anchor->parent == NULL && nr++ == pr->nr) {
+ strlcpy(pr->name, anchor->name,
+ sizeof(pr->name));
+ break;
+ }
+ } else {
+ RB_FOREACH(anchor, pf_anchor_node,
+ &ruleset->anchor->children)
+ if (nr++ == pr->nr) {
+ strlcpy(pr->name, anchor->name,
+ sizeof(pr->name));
+ break;
+ }
}
- if (ruleset == NULL)
+ if (!pr->name[0])
error = EBUSY;
- else
- bcopy(ruleset->name, pr->name, sizeof(pr->name));
break;
}
@@ -2306,31 +2473,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
- case DIOCRINABEGIN: {
- struct pfioc_table *io = (struct pfioc_table *)addr;
-
- if (io->pfrio_esize != 0) {
- error = ENODEV;
- break;
- }
- error = pfr_ina_begin(&io->pfrio_table, &io->pfrio_ticket,
- &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL);
- break;
- }
-
- case DIOCRINACOMMIT: {
- struct pfioc_table *io = (struct pfioc_table *)addr;
-
- if (io->pfrio_esize != 0) {
- error = ENODEV;
- break;
- }
- error = pfr_ina_commit(&io->pfrio_table, io->pfrio_ticket,
- &io->pfrio_nadd, &io->pfrio_nchange, io->pfrio_flags |
- PFR_FLAG_USERIOCTL);
- break;
- }
-
case DIOCRINADEFINE: {
struct pfioc_table *io = (struct pfioc_table *)addr;
@@ -2346,25 +2488,22 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCOSFPADD: {
struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
- s = splsoftnet();
error = pf_osfp_add(io);
- splx(s);
break;
}
case DIOCOSFPGET: {
struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
- s = splsoftnet();
error = pf_osfp_get(io);
- splx(s);
break;
}
case DIOCXBEGIN: {
- struct pfioc_trans *io = (struct pfioc_trans *)addr;
- struct pfioc_trans_e ioe;
- struct pfr_table table;
- int i;
+ struct pfioc_trans *io = (struct pfioc_trans *)
+ addr;
+ static struct pfioc_trans_e ioe;
+ static struct pfr_table table;
+ int i;
if (io->esize != sizeof(ioe)) {
error = ENODEV;
@@ -2378,7 +2517,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
switch (ioe.rs_num) {
#ifdef ALTQ
case PF_RULESET_ALTQ:
- if (ioe.anchor[0] || ioe.ruleset[0]) {
+ if (ioe.anchor[0]) {
error = EINVAL;
goto fail;
}
@@ -2390,15 +2529,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
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)))
+ ioe.rs_num, ioe.anchor)))
goto fail;
break;
}
@@ -2411,10 +2548,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
case DIOCXROLLBACK: {
- struct pfioc_trans *io = (struct pfioc_trans *)addr;
- struct pfioc_trans_e ioe;
- struct pfr_table table;
- int i;
+ struct pfioc_trans *io = (struct pfioc_trans *)
+ addr;
+ static struct pfioc_trans_e ioe;
+ static struct pfr_table table;
+ int i;
if (io->esize != sizeof(ioe)) {
error = ENODEV;
@@ -2428,7 +2566,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
switch (ioe.rs_num) {
#ifdef ALTQ
case PF_RULESET_ALTQ:
- if (ioe.anchor[0] || ioe.ruleset[0]) {
+ if (ioe.anchor[0]) {
error = EINVAL;
goto fail;
}
@@ -2440,15 +2578,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
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)))
+ ioe.rs_num, ioe.anchor)))
goto fail; /* really bad */
break;
}
@@ -2457,11 +2593,12 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
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;
+ struct pfioc_trans *io = (struct pfioc_trans *)
+ addr;
+ static struct pfioc_trans_e ioe;
+ static struct pfr_table table;
+ struct pf_ruleset *rs;
+ int i;
if (io->esize != sizeof(ioe)) {
error = ENODEV;
@@ -2476,7 +2613,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
switch (ioe.rs_num) {
#ifdef ALTQ
case PF_RULESET_ALTQ:
- if (ioe.anchor[0] || ioe.ruleset[0]) {
+ if (ioe.anchor[0]) {
error = EINVAL;
goto fail;
}
@@ -2488,7 +2625,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
#endif /* ALTQ */
case PF_RULESET_TABLE:
- rs = pf_find_ruleset(ioe.anchor, ioe.ruleset);
+ rs = pf_find_ruleset(ioe.anchor);
if (rs == NULL || !rs->topen || ioe.ticket !=
rs->tticket) {
error = EBUSY;
@@ -2501,7 +2638,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = EINVAL;
goto fail;
}
- rs = pf_find_ruleset(ioe.anchor, ioe.ruleset);
+ rs = pf_find_ruleset(ioe.anchor);
if (rs == NULL ||
!rs->rules[ioe.rs_num].inactive.open ||
rs->rules[ioe.rs_num].inactive.ticket !=
@@ -2529,15 +2666,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
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)))
+ ioe.rs_num, ioe.anchor)))
goto fail; /* really bad */
break;
}
@@ -2553,18 +2688,15 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
int space = psn->psn_len;
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);
+ break;
}
- s = splsoftnet();
p = psn->psn_src_nodes;
RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
- int secs = time.tv_sec;
+ int secs = time_second, diff;
if ((nr + 1) * sizeof(*p) > (unsigned)psn->psn_len)
break;
@@ -2577,16 +2709,23 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
pstore.expire -= secs;
else
pstore.expire = 0;
+
+ /* adjust the connection rate estimate */
+ diff = secs - n->conn_rate.last;
+ if (diff >= n->conn_rate.seconds)
+ pstore.conn_rate.count = 0;
+ else
+ pstore.conn_rate.count -=
+ n->conn_rate.count * diff /
+ n->conn_rate.seconds;
+
error = copyout(&pstore, p, sizeof(*p));
- if (error) {
- splx(s);
+ if (error)
goto fail;
- }
p++;
nr++;
}
psn->psn_len = sizeof(struct pf_src_node) * nr;
- splx(s);
break;
}
@@ -2594,7 +2733,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
struct pf_src_node *n;
struct pf_state *state;
- s = splsoftnet();
RB_FOREACH(state, pf_state_tree_id, &tree_id) {
state->src_node = NULL;
state->nat_src_node = NULL;
@@ -2605,25 +2743,21 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
pf_purge_expired_src_nodes();
pf_status.src_nodes = 0;
- splx(s);
break;
}
case DIOCSETHOSTID: {
u_int32_t *hostid = (u_int32_t *)addr;
- if (*hostid == 0) {
- error = EINVAL;
- goto fail;
- }
- pf_status.hostid = *hostid;
+ if (*hostid == 0)
+ pf_status.hostid = arc4random();
+ else
+ pf_status.hostid = *hostid;
break;
}
case DIOCOSFPFLUSH:
- s = splsoftnet();
pf_osfp_flush();
- splx(s);
break;
case DIOCIGETIFACES: {
@@ -2646,11 +2780,25 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
+ case DIOCSETIFFLAG: {
+ struct pfioc_iface *io = (struct pfioc_iface *)addr;
+
+ error = pfi_set_flags(io->pfiio_name, io->pfiio_flags);
+ break;
+ }
+
+ case DIOCCLRIFFLAG: {
+ struct pfioc_iface *io = (struct pfioc_iface *)addr;
+
+ error = pfi_clear_flags(io->pfiio_name, io->pfiio_flags);
+ break;
+ }
+
default:
error = ENODEV;
break;
}
fail:
-
+ splx(s);
return (error);
}
diff --git a/sys/contrib/pf/net/pf_norm.c b/sys/contrib/pf/net/pf_norm.c
index 3e5b40281db0..3c3dbc062ca4 100644
--- a/sys/contrib/pf/net/pf_norm.c
+++ b/sys/contrib/pf/net/pf_norm.c
@@ -1,5 +1,4 @@
-/* $OpenBSD: pf_norm.c,v 1.80.2.1 2004/04/30 21:46:33 brad Exp $ */
-/* add $OpenBSD: pf_norm.c,v 1.87 2004/05/11 07:34:11 dhartmei Exp $ */
+/* $OpenBSD: pf_norm.c,v 1.97 2004/09/21 16:59:12 aaron Exp $ */
/*
* Copyright 2001 Niels Provos <provos@citi.umich.edu>
@@ -118,8 +117,12 @@ struct mbuf *pf_fragcache(struct mbuf **, struct ip*,
int pf_normalize_tcpopt(struct pf_rule *, struct mbuf *,
struct tcphdr *, int);
-#define DPFPRINTF(x) if (pf_status.debug >= PF_DEBUG_MISC) \
- { printf("%s: ", __func__); printf x ;}
+#define DPFPRINTF(x) do { \
+ if (pf_status.debug >= PF_DEBUG_MISC) { \
+ printf("%s: ", __func__); \
+ printf x ; \
+ } \
+} while(0)
/* Globals */
struct pool pf_frent_pl, pf_frag_pl, pf_cache_pl, pf_cent_pl;
@@ -173,7 +176,7 @@ void
pf_purge_expired_fragments(void)
{
struct pf_fragment *frag;
- u_int32_t expire = time.tv_sec -
+ u_int32_t expire = time_second -
pf_default_rule.timeout[PFTM_FRAG];
while ((frag = TAILQ_LAST(&pf_fragqueue, pf_fragqueue)) != NULL) {
@@ -284,7 +287,7 @@ 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? */
- frag->fr_timeout = time.tv_sec;
+ frag->fr_timeout = time_second;
if (BUFFER_FRAGMENTS(frag)) {
TAILQ_REMOVE(&pf_fragqueue, frag, frag_next);
TAILQ_INSERT_HEAD(&pf_fragqueue, frag, frag_next);
@@ -349,7 +352,7 @@ 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;
- (*frag)->fr_timeout = time.tv_sec;
+ (*frag)->fr_timeout = time_second;
LIST_INIT(&(*frag)->fr_queue);
RB_INSERT(pf_frag_tree, &pf_frag_tree, *frag);
@@ -551,7 +554,7 @@ 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;
- (*frag)->fr_timeout = time.tv_sec;
+ (*frag)->fr_timeout = time_second;
cur->fr_off = off;
cur->fr_end = max;
@@ -810,7 +813,8 @@ 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 pfi_kif *kif, u_short *reason,
+ struct pf_pdesc *pd)
{
struct mbuf *m = *m0;
struct pf_rule *r;
@@ -837,10 +841,10 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason)
else if (r->proto && r->proto != h->ip_p)
r = r->skip[PF_SKIP_PROTO].ptr;
else if (PF_MISMATCHAW(&r->src.addr,
- (struct pf_addr *)&h->ip_src.s_addr, AF_INET, r->src.not))
+ (struct pf_addr *)&h->ip_src.s_addr, AF_INET, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
else if (PF_MISMATCHAW(&r->dst.addr,
- (struct pf_addr *)&h->ip_dst.s_addr, AF_INET, r->dst.not))
+ (struct pf_addr *)&h->ip_dst.s_addr, AF_INET, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else
break;
@@ -982,6 +986,8 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason)
h->ip_id = ip_randomid();
h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_id, h->ip_id, 0);
}
+ if ((r->rule_flag & (PFRULE_FRAGCROP|PFRULE_FRAGDROP)) == 0)
+ pd->flags |= PFDESC_IP_REAS;
return (PF_PASS);
@@ -989,7 +995,8 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason)
/* Enforce a minimum ttl, may cause endless packet loops */
if (r->min_ttl && h->ip_ttl < r->min_ttl)
h->ip_ttl = r->min_ttl;
-
+ if ((r->rule_flag & (PFRULE_FRAGCROP|PFRULE_FRAGDROP)) == 0)
+ pd->flags |= PFDESC_IP_REAS;
return (PF_PASS);
no_mem:
@@ -1021,7 +1028,7 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason)
#ifdef INET6
int
pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif,
- u_short *reason)
+ u_short *reason, struct pf_pdesc *pd)
{
struct mbuf *m = *m0;
struct pf_rule *r;
@@ -1053,10 +1060,10 @@ pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif,
r = r->skip[PF_SKIP_PROTO].ptr;
#endif
else if (PF_MISMATCHAW(&r->src.addr,
- (struct pf_addr *)&h->ip6_src, AF_INET6, r->src.not))
+ (struct pf_addr *)&h->ip6_src, AF_INET6, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
else if (PF_MISMATCHAW(&r->dst.addr,
- (struct pf_addr *)&h->ip6_dst, AF_INET6, r->dst.not))
+ (struct pf_addr *)&h->ip6_dst, AF_INET6, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else
break;
@@ -1171,6 +1178,7 @@ pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif,
goto badfrag;
/* do something about it */
+ /* remember to set pd->flags |= PFDESC_IP_REAS */
return (PF_PASS);
shortpkt:
@@ -1191,7 +1199,7 @@ pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif,
PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL);
return (PF_DROP);
}
-#endif
+#endif /* INET6 */
int
pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff,
@@ -1216,12 +1224,12 @@ pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff,
r = r->skip[PF_SKIP_AF].ptr;
else if (r->proto && r->proto != pd->proto)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.not))
+ else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
else if (r->src.port_op && !pf_match_port(r->src.port_op,
r->src.port[0], r->src.port[1], th->th_sport))
r = r->skip[PF_SKIP_SRC_PORT].ptr;
- else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.not))
+ else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
r->dst.port[0], r->dst.port[1], th->th_dport))
@@ -1236,7 +1244,7 @@ pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff,
}
}
- if (rm == NULL)
+ if (rm == NULL || rm->action == PF_NOSCRUB)
return (PF_PASS);
else
r->packets++;
@@ -1309,6 +1317,7 @@ int
pf_normalize_tcp_init(struct mbuf *m, int off, struct pf_pdesc *pd,
struct tcphdr *th, struct pf_state_peer *src, struct pf_state_peer *dst)
{
+ u_int32_t tsval, tsecr;
u_int8_t hdr[60];
u_int8_t *opt;
@@ -1362,7 +1371,18 @@ pf_normalize_tcp_init(struct mbuf *m, int off, struct pf_pdesc *pd,
if (opt[1] >= TCPOLEN_TIMESTAMP) {
src->scrub->pfss_flags |=
PFSS_TIMESTAMP;
- src->scrub->pfss_ts_mod = arc4random();
+ src->scrub->pfss_ts_mod =
+ htonl(arc4random());
+
+ /* note PFSS_PAWS not set yet */
+ memcpy(&tsval, &opt[2],
+ sizeof(u_int32_t));
+ memcpy(&tsecr, &opt[6],
+ sizeof(u_int32_t));
+ src->scrub->pfss_tsval0 = ntohl(tsval);
+ src->scrub->pfss_tsval = ntohl(tsval);
+ src->scrub->pfss_tsecr = ntohl(tsecr);
+ getmicrouptime(&src->scrub->pfss_last);
}
/* FALLTHROUGH */
default:
@@ -1389,12 +1409,16 @@ pf_normalize_tcp_cleanup(struct pf_state *state)
int
pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd,
- u_short *reason, struct tcphdr *th, struct pf_state_peer *src,
- struct pf_state_peer *dst, int *writeback)
+ u_short *reason, struct tcphdr *th, struct pf_state *state,
+ struct pf_state_peer *src, struct pf_state_peer *dst, int *writeback)
{
+ struct timeval uptime;
+ u_int32_t tsval, tsecr;
+ u_int tsval_from_last;
u_int8_t hdr[60];
u_int8_t *opt;
int copyback = 0;
+ int got_ts = 0;
KASSERT(src->scrub || dst->scrub);
@@ -1448,32 +1472,46 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd,
* NAT detection, OS uptime determination or
* reboot detection.
*/
+
+ if (got_ts) {
+ /* Huh? Multiple timestamps!? */
+ if (pf_status.debug >= PF_DEBUG_MISC) {
+ DPFPRINTF(("multiple TS??"));
+ pf_print_state(state);
+ printf("\n");
+ }
+ REASON_SET(reason, PFRES_TS);
+ return (PF_DROP);
+ }
if (opt[1] >= TCPOLEN_TIMESTAMP) {
- u_int32_t ts_value;
- if (src->scrub &&
+ memcpy(&tsval, &opt[2],
+ sizeof(u_int32_t));
+ if (tsval && src->scrub &&
(src->scrub->pfss_flags &
PFSS_TIMESTAMP)) {
- memcpy(&ts_value, &opt[2],
- sizeof(u_int32_t));
- ts_value = htonl(ntohl(ts_value)
- + src->scrub->pfss_ts_mod);
+ tsval = ntohl(tsval);
pf_change_a(&opt[2],
- &th->th_sum, ts_value, 0);
+ &th->th_sum,
+ htonl(tsval +
+ src->scrub->pfss_ts_mod),
+ 0);
copyback = 1;
}
/* Modulate TS reply iff valid (!0) */
- memcpy(&ts_value, &opt[6],
+ memcpy(&tsecr, &opt[6],
sizeof(u_int32_t));
- if (ts_value && dst->scrub &&
+ if (tsecr && dst->scrub &&
(dst->scrub->pfss_flags &
PFSS_TIMESTAMP)) {
- ts_value = htonl(ntohl(ts_value)
- - dst->scrub->pfss_ts_mod);
+ tsecr = ntohl(tsecr)
+ - dst->scrub->pfss_ts_mod;
pf_change_a(&opt[6],
- &th->th_sum, ts_value, 0);
+ &th->th_sum, htonl(tsecr),
+ 0);
copyback = 1;
}
+ got_ts = 1;
}
/* FALLTHROUGH */
default:
@@ -1492,9 +1530,274 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd,
}
+ /*
+ * Must invalidate PAWS checks on connections idle for too long.
+ * The fastest allowed timestamp clock is 1ms. That turns out to
+ * be about 24 days before it wraps. XXX Right now our lowerbound
+ * TS echo check only works for the first 12 days of a connection
+ * when the TS has exhausted half its 32bit space
+ */
+#define TS_MAX_IDLE (24*24*60*60)
+#define TS_MAX_CONN (12*24*60*60) /* XXX remove when better tsecr check */
+
+ getmicrouptime(&uptime);
+ if (src->scrub && (src->scrub->pfss_flags & PFSS_PAWS) &&
+ (uptime.tv_sec - src->scrub->pfss_last.tv_sec > TS_MAX_IDLE ||
+ time_second - state->creation > TS_MAX_CONN)) {
+ if (pf_status.debug >= PF_DEBUG_MISC) {
+ DPFPRINTF(("src idled out of PAWS\n"));
+ pf_print_state(state);
+ printf("\n");
+ }
+ src->scrub->pfss_flags = (src->scrub->pfss_flags & ~PFSS_PAWS)
+ | PFSS_PAWS_IDLED;
+ }
+ if (dst->scrub && (dst->scrub->pfss_flags & PFSS_PAWS) &&
+ uptime.tv_sec - dst->scrub->pfss_last.tv_sec > TS_MAX_IDLE) {
+ if (pf_status.debug >= PF_DEBUG_MISC) {
+ DPFPRINTF(("dst idled out of PAWS\n"));
+ pf_print_state(state);
+ printf("\n");
+ }
+ dst->scrub->pfss_flags = (dst->scrub->pfss_flags & ~PFSS_PAWS)
+ | PFSS_PAWS_IDLED;
+ }
+
+ if (got_ts && src->scrub && dst->scrub &&
+ (src->scrub->pfss_flags & PFSS_PAWS) &&
+ (dst->scrub->pfss_flags & PFSS_PAWS)) {
+ /* Validate that the timestamps are "in-window".
+ * RFC1323 describes TCP Timestamp options that allow
+ * measurement of RTT (round trip time) and PAWS
+ * (protection against wrapped sequence numbers). PAWS
+ * gives us a set of rules for rejecting packets on
+ * long fat pipes (packets that were somehow delayed
+ * in transit longer than the time it took to send the
+ * full TCP sequence space of 4Gb). We can use these
+ * rules and infer a few others that will let us treat
+ * the 32bit timestamp and the 32bit echoed timestamp
+ * as sequence numbers to prevent a blind attacker from
+ * inserting packets into a connection.
+ *
+ * RFC1323 tells us:
+ * - The timestamp on this packet must be greater than
+ * or equal to the last value echoed by the other
+ * endpoint. The RFC says those will be discarded
+ * since it is a dup that has already been acked.
+ * This gives us a lowerbound on the timestamp.
+ * timestamp >= other last echoed timestamp
+ * - The timestamp will be less than or equal to
+ * the last timestamp plus the time between the
+ * last packet and now. The RFC defines the max
+ * clock rate as 1ms. We will allow clocks to be
+ * up to 10% fast and will allow a total difference
+ * or 30 seconds due to a route change. And this
+ * gives us an upperbound on the timestamp.
+ * timestamp <= last timestamp + max ticks
+ * We have to be careful here. Windows will send an
+ * initial timestamp of zero and then initialize it
+ * to a random value after the 3whs; presumably to
+ * avoid a DoS by having to call an expensive RNG
+ * during a SYN flood. Proof MS has at least one
+ * good security geek.
+ *
+ * - The TCP timestamp option must also echo the other
+ * endpoints timestamp. The timestamp echoed is the
+ * one carried on the earliest unacknowledged segment
+ * on the left edge of the sequence window. The RFC
+ * states that the host will reject any echoed
+ * timestamps that were larger than any ever sent.
+ * This gives us an upperbound on the TS echo.
+ * tescr <= largest_tsval
+ * - The lowerbound on the TS echo is a little more
+ * tricky to determine. The other endpoint's echoed
+ * values will not decrease. But there may be
+ * network conditions that re-order packets and
+ * cause our view of them to decrease. For now the
+ * only lowerbound we can safely determine is that
+ * the TS echo will never be less than the orginal
+ * TS. XXX There is probably a better lowerbound.
+ * Remove TS_MAX_CONN with better lowerbound check.
+ * tescr >= other original TS
+ *
+ * It is also important to note that the fastest
+ * timestamp clock of 1ms will wrap its 32bit space in
+ * 24 days. So we just disable TS checking after 24
+ * days of idle time. We actually must use a 12d
+ * connection limit until we can come up with a better
+ * lowerbound to the TS echo check.
+ */
+ struct timeval delta_ts;
+ int ts_fudge;
+
+
+ /*
+ * PFTM_TS_DIFF is how many seconds of leeway to allow
+ * a host's timestamp. This can happen if the previous
+ * packet got delayed in transit for much longer than
+ * this packet.
+ */
+ if ((ts_fudge = state->rule.ptr->timeout[PFTM_TS_DIFF]) == 0)
+ ts_fudge = pf_default_rule.timeout[PFTM_TS_DIFF];
+
+
+ /* Calculate max ticks since the last timestamp */
+#define TS_MAXFREQ 1100 /* RFC max TS freq of 1Khz + 10% skew */
+#define TS_MICROSECS 1000000 /* microseconds per second */
+ timersub(&uptime, &src->scrub->pfss_last, &delta_ts);
+ tsval_from_last = (delta_ts.tv_sec + ts_fudge) * TS_MAXFREQ;
+ tsval_from_last += delta_ts.tv_usec / (TS_MICROSECS/TS_MAXFREQ);
+
+
+ if ((src->state >= TCPS_ESTABLISHED &&
+ dst->state >= TCPS_ESTABLISHED) &&
+ (SEQ_LT(tsval, dst->scrub->pfss_tsecr) ||
+ SEQ_GT(tsval, src->scrub->pfss_tsval + tsval_from_last) ||
+ (tsecr && (SEQ_GT(tsecr, dst->scrub->pfss_tsval) ||
+ SEQ_LT(tsecr, dst->scrub->pfss_tsval0))))) {
+ /* Bad RFC1323 implementation or an insertion attack.
+ *
+ * - Solaris 2.6 and 2.7 are known to send another ACK
+ * after the FIN,FIN|ACK,ACK closing that carries
+ * an old timestamp.
+ */
+
+ DPFPRINTF(("Timestamp failed %c%c%c%c\n",
+ SEQ_LT(tsval, dst->scrub->pfss_tsecr) ? '0' : ' ',
+ SEQ_GT(tsval, src->scrub->pfss_tsval +
+ tsval_from_last) ? '1' : ' ',
+ SEQ_GT(tsecr, dst->scrub->pfss_tsval) ? '2' : ' ',
+ SEQ_LT(tsecr, dst->scrub->pfss_tsval0)? '3' : ' '));
+ DPFPRINTF((" tsval: %lu tsecr: %lu +ticks: %lu "
+ "idle: %lus %lums\n",
+ tsval, tsecr, tsval_from_last, delta_ts.tv_sec,
+ delta_ts.tv_usec / 1000));
+ DPFPRINTF((" src->tsval: %lu tsecr: %lu\n",
+ src->scrub->pfss_tsval, src->scrub->pfss_tsecr));
+ DPFPRINTF((" dst->tsval: %lu tsecr: %lu tsval0: %lu"
+ "\n", dst->scrub->pfss_tsval,
+ dst->scrub->pfss_tsecr, dst->scrub->pfss_tsval0));
+ if (pf_status.debug >= PF_DEBUG_MISC) {
+ pf_print_state(state);
+ pf_print_flags(th->th_flags);
+ printf("\n");
+ }
+ REASON_SET(reason, PFRES_TS);
+ return (PF_DROP);
+ }
+
+ /* XXX I'd really like to require tsecr but it's optional */
+
+ } else if (!got_ts && (th->th_flags & TH_RST) == 0 &&
+ ((src->state == TCPS_ESTABLISHED && dst->state == TCPS_ESTABLISHED)
+ || pd->p_len > 0 || (th->th_flags & TH_SYN)) &&
+ src->scrub && dst->scrub &&
+ (src->scrub->pfss_flags & PFSS_PAWS) &&
+ (dst->scrub->pfss_flags & PFSS_PAWS)) {
+ /* Didn't send a timestamp. Timestamps aren't really useful
+ * when:
+ * - connection opening or closing (often not even sent).
+ * but we must not let an attacker to put a FIN on a
+ * data packet to sneak it through our ESTABLISHED check.
+ * - on a TCP reset. RFC suggests not even looking at TS.
+ * - on an empty ACK. The TS will not be echoed so it will
+ * probably not help keep the RTT calculation in sync and
+ * there isn't as much danger when the sequence numbers
+ * got wrapped. So some stacks don't include TS on empty
+ * ACKs :-(
+ *
+ * To minimize the disruption to mostly RFC1323 conformant
+ * stacks, we will only require timestamps on data packets.
+ *
+ * And what do ya know, we cannot require timestamps on data
+ * packets. There appear to be devices that do legitimate
+ * TCP connection hijacking. There are HTTP devices that allow
+ * a 3whs (with timestamps) and then buffer the HTTP request.
+ * If the intermediate device has the HTTP response cache, it
+ * will spoof the response but not bother timestamping its
+ * packets. So we can look for the presence of a timestamp in
+ * the first data packet and if there, require it in all future
+ * packets.
+ */
+
+ if (pd->p_len > 0 && (src->scrub->pfss_flags & PFSS_DATA_TS)) {
+ /*
+ * Hey! Someone tried to sneak a packet in. Or the
+ * stack changed its RFC1323 behavior?!?!
+ */
+ if (pf_status.debug >= PF_DEBUG_MISC) {
+ DPFPRINTF(("Did not receive expected RFC1323 "
+ "timestamp\n"));
+ pf_print_state(state);
+ pf_print_flags(th->th_flags);
+ printf("\n");
+ }
+ REASON_SET(reason, PFRES_TS);
+ return (PF_DROP);
+ }
+ }
+
+
+ /*
+ * We will note if a host sends his data packets with or without
+ * timestamps. And require all data packets to contain a timestamp
+ * if the first does. PAWS implicitly requires that all data packets be
+ * timestamped. But I think there are middle-man devices that hijack
+ * TCP streams immedietly after the 3whs and don't timestamp their
+ * packets (seen in a WWW accelerator or cache).
+ */
+ if (pd->p_len > 0 && src->scrub && (src->scrub->pfss_flags &
+ (PFSS_TIMESTAMP|PFSS_DATA_TS|PFSS_DATA_NOTS)) == PFSS_TIMESTAMP) {
+ if (got_ts)
+ src->scrub->pfss_flags |= PFSS_DATA_TS;
+ else {
+ src->scrub->pfss_flags |= PFSS_DATA_NOTS;
+ if (pf_status.debug >= PF_DEBUG_MISC && dst->scrub &&
+ (dst->scrub->pfss_flags & PFSS_TIMESTAMP)) {
+ /* Don't warn if other host rejected RFC1323 */
+ DPFPRINTF(("Broken RFC1323 stack did not "
+ "timestamp data packet. Disabled PAWS "
+ "security.\n"));
+ pf_print_state(state);
+ pf_print_flags(th->th_flags);
+ printf("\n");
+ }
+ }
+ }
+
+
+ /*
+ * Update PAWS values
+ */
+ if (got_ts && src->scrub && PFSS_TIMESTAMP == (src->scrub->pfss_flags &
+ (PFSS_PAWS_IDLED|PFSS_TIMESTAMP))) {
+ getmicrouptime(&src->scrub->pfss_last);
+ if (SEQ_GEQ(tsval, src->scrub->pfss_tsval) ||
+ (src->scrub->pfss_flags & PFSS_PAWS) == 0)
+ src->scrub->pfss_tsval = tsval;
+
+ if (tsecr) {
+ if (SEQ_GEQ(tsecr, src->scrub->pfss_tsecr) ||
+ (src->scrub->pfss_flags & PFSS_PAWS) == 0)
+ src->scrub->pfss_tsecr = tsecr;
+
+ if ((src->scrub->pfss_flags & PFSS_PAWS) == 0 &&
+ (SEQ_LT(tsval, src->scrub->pfss_tsval0) ||
+ src->scrub->pfss_tsval0 == 0)) {
+ /* tsval0 MUST be the lowest timestamp */
+ src->scrub->pfss_tsval0 = tsval;
+ }
+
+ /* Only fully initialized after a TS gets echoed */
+ if ((src->scrub->pfss_flags & PFSS_PAWS) == 0)
+ src->scrub->pfss_flags |= PFSS_PAWS;
+ }
+ }
+
/* I have a dream.... TCP segment reassembly.... */
return (0);
}
+
int
pf_normalize_tcpopt(struct pf_rule *r, struct mbuf *m, struct tcphdr *th,
int off)
diff --git a/sys/contrib/pf/net/pf_osfp.c b/sys/contrib/pf/net/pf_osfp.c
index 98cc01ab1fb6..b2adcf29667d 100644
--- a/sys/contrib/pf/net/pf_osfp.c
+++ b/sys/contrib/pf/net/pf_osfp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_osfp.c,v 1.9 2004/01/04 20:08:42 pvalchev Exp $ */
+/* $OpenBSD: pf_osfp.c,v 1.10 2004/04/09 19:30:41 frantzen Exp $ */
/*
* Copyright (c) 2003 Mike Frantzen <frantzen@w4g.org>
@@ -233,9 +233,9 @@ void
pf_osfp_initialize(void)
{
pool_init(&pf_osfp_entry_pl, sizeof(struct pf_osfp_entry), 0, 0, 0,
- "pfosfpen", NULL);
+ "pfosfpen", &pool_allocator_nointr);
pool_init(&pf_osfp_pl, sizeof(struct pf_os_fingerprint), 0, 0, 0,
- "pfosfp", NULL);
+ "pfosfp", &pool_allocator_nointr);
SLIST_INIT(&pf_osfp_list);
}
diff --git a/sys/contrib/pf/net/pf_table.c b/sys/contrib/pf/net/pf_table.c
index 42d4cee0b7c3..621809a3b0e4 100644
--- a/sys/contrib/pf/net/pf_table.c
+++ b/sys/contrib/pf/net/pf_table.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_table.c,v 1.47 2004/03/09 21:44:41 mcbride Exp $ */
+/* $OpenBSD: pf_table.c,v 1.62 2004/12/07 18:02:04 mcbride Exp $ */
/*
* Copyright (c) 2002 Cedric Berger
@@ -125,6 +125,7 @@ struct pfr_walktree {
struct pool pfr_ktable_pl;
struct pool pfr_kentry_pl;
+struct pool pfr_kentry_pl2;
struct sockaddr_in pfr_sin;
struct sockaddr_in6 pfr_sin6;
union sockaddr_union pfr_mask;
@@ -138,7 +139,7 @@ void pfr_enqueue_addrs(struct pfr_ktable *,
void pfr_mark_addrs(struct pfr_ktable *);
struct pfr_kentry *pfr_lookup_addr(struct pfr_ktable *,
struct pfr_addr *, int);
-struct pfr_kentry *pfr_create_kentry(struct pfr_addr *);
+struct pfr_kentry *pfr_create_kentry(struct pfr_addr *, int);
void pfr_destroy_kentries(struct pfr_kentryworkq *);
void pfr_destroy_kentry(struct pfr_kentry *);
void pfr_insert_kentries(struct pfr_ktable *,
@@ -155,6 +156,7 @@ 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_fix_anchor(char *);
void pfr_commit_ktable(struct pfr_ktable *, long);
void pfr_insert_ktables(struct pfr_ktableworkq *);
void pfr_insert_ktable(struct pfr_ktable *);
@@ -187,9 +189,11 @@ void
pfr_initialize(void)
{
pool_init(&pfr_ktable_pl, sizeof(struct pfr_ktable), 0, 0, 0,
- "pfrktable", NULL);
+ "pfrktable", &pool_allocator_oldnointr);
pool_init(&pfr_kentry_pl, sizeof(struct pfr_kentry), 0, 0, 0,
- "pfrkentry", NULL);
+ "pfrkentry", &pool_allocator_oldnointr);
+ pool_init(&pfr_kentry_pl2, sizeof(struct pfr_kentry), 0, 0, 0,
+ "pfrkentry2", NULL);
pfr_sin.sin_len = sizeof(pfr_sin);
pfr_sin.sin_family = AF_INET;
@@ -240,7 +244,7 @@ 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;
- long tzero = time.tv_sec;
+ long tzero = time_second;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
@@ -272,7 +276,7 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
ad.pfra_fback = PFR_FB_NONE;
}
if (p == NULL && q == NULL) {
- p = pfr_create_kentry(&ad);
+ p = pfr_create_kentry(&ad, 0);
if (p == NULL)
senderr(ENOMEM);
if (pfr_route_kentry(tmpkt, p)) {
@@ -317,7 +321,7 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
struct pfr_kentryworkq workq;
struct pfr_kentry *p;
struct pfr_addr ad;
- int i, rv, s, xdel = 0;
+ int i, rv, s, xdel = 0, log = 1;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
@@ -327,7 +331,34 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
return (ESRCH);
if (kt->pfrkt_flags & PFR_TFLAG_CONST)
return (EPERM);
- pfr_mark_addrs(kt);
+ /*
+ * there are two algorithms to choose from here.
+ * with:
+ * n: number of addresses to delete
+ * N: number of addresses in the table
+ *
+ * one is O(N) and is better for large 'n'
+ * one is O(n*LOG(N)) and is better for small 'n'
+ *
+ * following code try to decide which one is best.
+ */
+ for (i = kt->pfrkt_cnt; i > 0; i >>= 1)
+ log++;
+ if (size > kt->pfrkt_cnt/log) {
+ /* full table scan */
+ pfr_mark_addrs(kt);
+ } else {
+ /* iterate over addresses to delete */
+ for (i = 0; i < size; i++) {
+ if (COPYIN(addr+i, &ad, sizeof(ad)))
+ return (EFAULT);
+ if (pfr_validate_addr(&ad))
+ return (EINVAL);
+ p = pfr_lookup_addr(kt, &ad, 1);
+ if (p != NULL)
+ p->pfrke_mark = 0;
+ }
+ }
SLIST_INIT(&workq);
for (i = 0; i < size; i++) {
if (COPYIN(addr+i, &ad, sizeof(ad)))
@@ -380,7 +411,7 @@ 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;
- long tzero = time.tv_sec;
+ long tzero = time_second;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
@@ -421,7 +452,7 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
ad.pfra_fback = PFR_FB_DUPLICATE;
goto _skip;
}
- p = pfr_create_kentry(&ad);
+ p = pfr_create_kentry(&ad, 0);
if (p == NULL)
senderr(ENOMEM);
if (pfr_route_kentry(tmpkt, p)) {
@@ -568,7 +599,7 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
struct pfr_walktree w;
struct pfr_kentryworkq workq;
int rv, s;
- long tzero = time.tv_sec;
+ long tzero = time_second;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC); /* XXX PFR_FLAG_CLSTATS disabled */
if (pfr_validate_table(tbl, 0, 0))
@@ -666,14 +697,18 @@ pfr_validate_addr(struct pfr_addr *ad)
int i;
switch (ad->pfra_af) {
+#ifdef INET
case AF_INET:
if (ad->pfra_net > 32)
return (-1);
break;
+#endif /* INET */
+#ifdef INET6
case AF_INET6:
if (ad->pfra_net > 128)
return (-1);
break;
+#endif /* INET6 */
default:
return (-1);
}
@@ -736,7 +771,7 @@ pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact)
if (ad->pfra_af == AF_INET) {
FILLIN_SIN(sa.sin, ad->pfra_ip4addr);
head = kt->pfrkt_ip4;
- } else {
+ } else if ( ad->pfra_af == AF_INET6 ) {
FILLIN_SIN6(sa.sin6, ad->pfra_ip6addr);
head = kt->pfrkt_ip6;
}
@@ -758,22 +793,26 @@ pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact)
}
struct pfr_kentry *
-pfr_create_kentry(struct pfr_addr *ad)
+pfr_create_kentry(struct pfr_addr *ad, int intr)
{
struct pfr_kentry *ke;
- ke = pool_get(&pfr_kentry_pl, PR_NOWAIT);
+ if (intr)
+ ke = pool_get(&pfr_kentry_pl2, PR_NOWAIT);
+ else
+ ke = pool_get(&pfr_kentry_pl, PR_NOWAIT);
if (ke == NULL)
return (NULL);
bzero(ke, sizeof(*ke));
if (ad->pfra_af == AF_INET)
FILLIN_SIN(ke->pfrke_sa.sin, ad->pfra_ip4addr);
- else
+ else if (ad->pfra_af == AF_INET6)
FILLIN_SIN6(ke->pfrke_sa.sin6, ad->pfra_ip6addr);
ke->pfrke_af = ad->pfra_af;
ke->pfrke_net = ad->pfra_net;
ke->pfrke_not = ad->pfra_not;
+ ke->pfrke_intrpool = intr;
return (ke);
}
@@ -791,7 +830,10 @@ pfr_destroy_kentries(struct pfr_kentryworkq *workq)
void
pfr_destroy_kentry(struct pfr_kentry *ke)
{
- pool_put(&pfr_kentry_pl, ke);
+ if (ke->pfrke_intrpool)
+ pool_put(&pfr_kentry_pl2, ke);
+ else
+ pool_put(&pfr_kentry_pl, ke);
}
void
@@ -814,6 +856,29 @@ pfr_insert_kentries(struct pfr_ktable *kt,
kt->pfrkt_cnt += n;
}
+int
+pfr_insert_kentry(struct pfr_ktable *kt, struct pfr_addr *ad, long tzero)
+{
+ struct pfr_kentry *p;
+ int rv;
+
+ p = pfr_lookup_addr(kt, ad, 1);
+ if (p != NULL)
+ return (0);
+ p = pfr_create_kentry(ad, 1);
+ if (p == NULL)
+ return (EINVAL);
+
+ rv = pfr_route_kentry(kt, p);
+ if (rv)
+ return (rv);
+
+ p->pfrke_tzero = tzero;
+ kt->pfrkt_cnt++;
+
+ return (0);
+}
+
void
pfr_remove_kentries(struct pfr_ktable *kt,
struct pfr_kentryworkq *workq)
@@ -880,14 +945,14 @@ pfr_prepare_network(union sockaddr_union *sa, int af, int net)
if (af == AF_INET) {
sa->sin.sin_len = sizeof(sa->sin);
sa->sin.sin_family = AF_INET;
- sa->sin.sin_addr.s_addr = htonl(-1 << (32-net));
- } else {
+ sa->sin.sin_addr.s_addr = net ? htonl(-1 << (32-net)) : 0;
+ } else if (af == AF_INET6) {
sa->sin6.sin6_len = sizeof(sa->sin6);
sa->sin6.sin6_family = AF_INET6;
for (i = 0; i < 4; i++) {
if (net <= 32) {
sa->sin6.sin6_addr.s6_addr32[i] =
- htonl(-1 << (32-net));
+ net ? htonl(-1 << (32-net)) : 0;
break;
}
sa->sin6.sin6_addr.s6_addr32[i] = 0xFFFFFFFF;
@@ -907,7 +972,7 @@ pfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke)
bzero(ke->pfrke_node, sizeof(ke->pfrke_node));
if (ke->pfrke_af == AF_INET)
head = kt->pfrkt_ip4;
- else
+ else if (ke->pfrke_af == AF_INET6)
head = kt->pfrkt_ip6;
s = splsoftnet();
@@ -931,15 +996,15 @@ pfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke)
if (ke->pfrke_af == AF_INET)
head = kt->pfrkt_ip4;
- else
+ else if (ke->pfrke_af == AF_INET6)
head = kt->pfrkt_ip6;
s = splsoftnet();
if (KENTRY_NETWORK(ke)) {
pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net);
- rn = rn_delete(&ke->pfrke_sa, &mask, head);
+ rn = rn_delete(&ke->pfrke_sa, &mask, head, NULL);
} else
- rn = rn_delete(&ke->pfrke_sa, NULL, head);
+ rn = rn_delete(&ke->pfrke_sa, NULL, head, NULL);
splx(s);
if (rn == NULL) {
@@ -960,7 +1025,7 @@ pfr_copyout_addr(struct pfr_addr *ad, struct pfr_kentry *ke)
ad->pfra_not = ke->pfrke_not;
if (ad->pfra_af == AF_INET)
ad->pfra_ip4addr = ke->pfrke_sa.sin.sin_addr;
- else
+ else if (ad->pfra_af == AF_INET6)
ad->pfra_ip6addr = ke->pfrke_sa.sin6.sin6_addr;
}
@@ -1029,7 +1094,7 @@ pfr_walktree(struct radix_node *rn, void *arg)
&ke->pfrke_sa, AF_INET);
w->pfrw_dyn->pfid_mask4 = *SUNION2PF(
&pfr_mask, AF_INET);
- } else {
+ } else if (ke->pfrke_af == AF_INET6){
if (w->pfrw_dyn->pfid_acnt6++ > 0)
break;
pfr_prepare_network(&pfr_mask, AF_INET6, ke->pfrke_net);
@@ -1051,6 +1116,8 @@ pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags)
int s, xdel = 0;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_ALLRSETS);
+ if (pfr_fix_anchor(filter->pfrt_anchor))
+ return (EINVAL);
if (pfr_table_count(filter, flags) < 0)
return (ENOENT);
@@ -1084,7 +1151,7 @@ pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
struct pfr_ktableworkq addq, changeq;
struct pfr_ktable *p, *q, *r, key;
int i, rv, s, xadd = 0;
- long tzero = time.tv_sec;
+ long tzero = time_second;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
SLIST_INIT(&addq);
@@ -1112,7 +1179,6 @@ pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
/* find or create root table */
bzero(key.pfrkt_anchor, sizeof(key.pfrkt_anchor));
- bzero(key.pfrkt_ruleset, sizeof(key.pfrkt_ruleset));
r = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
if (r != NULL) {
p->pfrkt_root = r;
@@ -1207,6 +1273,8 @@ pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size,
int n, nn;
ACCEPT_FLAGS(PFR_FLAG_ALLRSETS);
+ if (pfr_fix_anchor(filter->pfrt_anchor))
+ return (EINVAL);
n = nn = pfr_table_count(filter, flags);
if (n < 0)
return (ENOENT);
@@ -1237,10 +1305,12 @@ 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;
- long tzero = time.tv_sec;
+ long tzero = time_second;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC|PFR_FLAG_ALLRSETS);
/* XXX PFR_FLAG_CLSTATS disabled */
+ if (pfr_fix_anchor(filter->pfrt_anchor))
+ return (EINVAL);
n = nn = pfr_table_count(filter, flags);
if (n < 0)
return (ENOENT);
@@ -1285,7 +1355,7 @@ pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
struct pfr_ktableworkq workq;
struct pfr_ktable *p, key;
int i, s, xzero = 0;
- long tzero = time.tv_sec;
+ long tzero = time_second;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_ADDRSTOO);
SLIST_INIT(&workq);
@@ -1375,7 +1445,7 @@ pfr_ina_begin(struct pfr_table *trs, u_int32_t *ticket, int *ndel, int flags)
int xdel = 0;
ACCEPT_FLAGS(PFR_FLAG_DUMMY);
- rs = pf_find_or_create_ruleset(trs->pfrt_anchor, trs->pfrt_ruleset);
+ rs = pf_find_or_create_ruleset(trs->pfrt_anchor);
if (rs == NULL)
return (ENOMEM);
SLIST_INIT(&workq);
@@ -1417,7 +1487,7 @@ pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
if (pfr_validate_table(tbl, PFR_TFLAG_USRMASK,
flags & PFR_FLAG_USERIOCTL))
return (EINVAL);
- rs = pf_find_ruleset(tbl->pfrt_anchor, tbl->pfrt_ruleset);
+ rs = pf_find_ruleset(tbl->pfrt_anchor);
if (rs == NULL || !rs->topen || ticket != rs->tticket)
return (EBUSY);
tbl->pfrt_flags |= PFR_TFLAG_INACTIVE;
@@ -1463,7 +1533,7 @@ _skip:
senderr(EINVAL);
if (pfr_lookup_addr(shadow, &ad, 1) != NULL)
continue;
- p = pfr_create_kentry(&ad);
+ p = pfr_create_kentry(&ad, 0);
if (p == NULL)
senderr(ENOMEM);
if (pfr_route_kentry(shadow, p)) {
@@ -1508,7 +1578,7 @@ pfr_ina_rollback(struct pfr_table *trs, u_int32_t ticket, int *ndel, int flags)
int xdel = 0;
ACCEPT_FLAGS(PFR_FLAG_DUMMY);
- rs = pf_find_ruleset(trs->pfrt_anchor, trs->pfrt_ruleset);
+ rs = pf_find_ruleset(trs->pfrt_anchor);
if (rs == NULL || !rs->topen || ticket != rs->tticket)
return (0);
SLIST_INIT(&workq);
@@ -1534,14 +1604,14 @@ int
pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd,
int *nchange, int flags)
{
- struct pfr_ktable *p;
+ struct pfr_ktable *p, *q;
struct pfr_ktableworkq workq;
struct pf_ruleset *rs;
int s, xadd = 0, xchange = 0;
- long tzero = time.tv_sec;
+ long tzero = time_second;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
- rs = pf_find_ruleset(trs->pfrt_anchor, trs->pfrt_ruleset);
+ rs = pf_find_ruleset(trs->pfrt_anchor);
if (rs == NULL || !rs->topen || ticket != rs->tticket)
return (EBUSY);
@@ -1560,8 +1630,10 @@ pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd,
if (!(flags & PFR_FLAG_DUMMY)) {
if (flags & PFR_FLAG_ATOMIC)
s = splsoftnet();
- SLIST_FOREACH(p, &workq, pfrkt_workq)
+ for (p = SLIST_FIRST(&workq); p != NULL; p = q) {
+ q = SLIST_NEXT(p, pfrkt_workq);
pfr_commit_ktable(p, tzero);
+ }
if (flags & PFR_FLAG_ATOMIC)
splx(s);
rs->topen = 0;
@@ -1648,27 +1720,52 @@ pfr_validate_table(struct pfr_table *tbl, int allowedflags, int no_reserved)
for (i = strlen(tbl->pfrt_name); i < PF_TABLE_NAME_SIZE; i++)
if (tbl->pfrt_name[i])
return (-1);
+ if (pfr_fix_anchor(tbl->pfrt_anchor))
+ return (-1);
if (tbl->pfrt_flags & ~allowedflags)
return (-1);
return (0);
}
+/*
+ * Rewrite anchors referenced by tables to remove slashes
+ * and check for validity.
+ */
+int
+pfr_fix_anchor(char *anchor)
+{
+ size_t siz = MAXPATHLEN;
+ int i;
+
+ if (anchor[0] == '/') {
+ char *path;
+ int off;
+
+ path = anchor;
+ off = 1;
+ while (*++path == '/')
+ off++;
+ bcopy(path, anchor, siz - off);
+ memset(anchor + siz - off, 0, off);
+ }
+ if (anchor[siz - 1])
+ return (-1);
+ for (i = strlen(anchor); i < siz; i++)
+ if (anchor[i])
+ return (-1);
+ return (0);
+}
+
int
pfr_table_count(struct pfr_table *filter, int flags)
{
struct pf_ruleset *rs;
- struct pf_anchor *ac;
if (flags & PFR_FLAG_ALLRSETS)
return (pfr_ktable_cnt);
- if (filter->pfrt_ruleset[0]) {
- rs = pf_find_ruleset(filter->pfrt_anchor,
- filter->pfrt_ruleset);
- return ((rs != NULL) ? rs->tables : -1);
- }
if (filter->pfrt_anchor[0]) {
- ac = pf_find_anchor(filter->pfrt_anchor);
- return ((ac != NULL) ? ac->tables : -1);
+ rs = pf_find_ruleset(filter->pfrt_anchor);
+ return ((rs != NULL) ? rs->tables : -1);
}
return (pf_main_ruleset.tables);
}
@@ -1678,13 +1775,7 @@ pfr_skip_table(struct pfr_table *filter, struct pfr_ktable *kt, int flags)
{
if (flags & PFR_FLAG_ALLRSETS)
return (0);
- if (strncmp(filter->pfrt_anchor, kt->pfrkt_anchor,
- PF_ANCHOR_NAME_SIZE))
- return (1);
- if (!filter->pfrt_ruleset[0])
- return (0);
- if (strncmp(filter->pfrt_ruleset, kt->pfrkt_ruleset,
- PF_RULESET_NAME_SIZE))
+ if (strcmp(filter->pfrt_anchor, kt->pfrkt_anchor))
return (1);
return (0);
}
@@ -1712,10 +1803,12 @@ pfr_insert_ktable(struct pfr_ktable *kt)
void
pfr_setflags_ktables(struct pfr_ktableworkq *workq)
{
- struct pfr_ktable *p;
+ struct pfr_ktable *p, *q;
- SLIST_FOREACH(p, workq, pfrkt_workq)
+ for (p = SLIST_FIRST(workq); p; p = q) {
+ q = SLIST_NEXT(p, pfrkt_workq);
pfr_setflags_ktable(p, p->pfrkt_nflags);
+ }
}
void
@@ -1790,16 +1883,13 @@ pfr_create_ktable(struct pfr_table *tbl, long tzero, int attachruleset)
kt->pfrkt_t = *tbl;
if (attachruleset) {
- rs = pf_find_or_create_ruleset(tbl->pfrt_anchor,
- tbl->pfrt_ruleset);
+ rs = pf_find_or_create_ruleset(tbl->pfrt_anchor);
if (!rs) {
pfr_destroy_ktable(kt, 0);
return (NULL);
}
kt->pfrkt_rs = rs;
rs->tables++;
- if (rs->anchor != NULL)
- rs->anchor->tables++;
}
if (!rn_inithead((void **)&kt->pfrkt_ip4,
@@ -1843,8 +1933,6 @@ pfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr)
pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr);
if (kt->pfrkt_rs != NULL) {
kt->pfrkt_rs->tables--;
- if (kt->pfrkt_rs->anchor != NULL)
- kt->pfrkt_rs->anchor->tables--;
pf_remove_if_empty_ruleset(kt->pfrkt_rs);
}
pool_put(&pfr_ktable_pl, kt);
@@ -1857,11 +1945,7 @@ pfr_ktable_compare(struct pfr_ktable *p, struct pfr_ktable *q)
if ((d = strncmp(p->pfrkt_name, q->pfrkt_name, PF_TABLE_NAME_SIZE)))
return (d);
- 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 (strcmp(p->pfrkt_anchor, q->pfrkt_anchor));
}
struct pfr_ktable *
@@ -1884,18 +1968,22 @@ pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af)
return (0);
switch (af) {
+#ifdef INET
case AF_INET:
pfr_sin.sin_addr.s_addr = a->addr32[0];
ke = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4);
if (ke && KENTRY_RNF_ROOT(ke))
ke = NULL;
break;
+#endif /* INET */
+#ifdef INET6
case AF_INET6:
bcopy(a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr));
ke = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6);
if (ke && KENTRY_RNF_ROOT(ke))
ke = NULL;
break;
+#endif /* INET6 */
}
match = (ke && !ke->pfrke_not);
if (match)
@@ -1917,18 +2005,24 @@ pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af,
return;
switch (af) {
+#ifdef INET
case AF_INET:
pfr_sin.sin_addr.s_addr = a->addr32[0];
ke = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4);
if (ke && KENTRY_RNF_ROOT(ke))
ke = NULL;
break;
+#endif /* INET */
+#ifdef INET6
case AF_INET6:
bcopy(a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr));
ke = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6);
if (ke && KENTRY_RNF_ROOT(ke))
ke = NULL;
break;
+#endif /* INET6 */
+ default:
+ ;
}
if ((ke == NULL || ke->pfrke_not) != notrule) {
if (op_pass != PFR_OP_PASS)
@@ -1952,18 +2046,15 @@ pfr_attach_table(struct pf_ruleset *rs, char *name)
bzero(&tbl, sizeof(tbl));
strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name));
- if (ac != NULL) {
+ if (ac != NULL)
strlcpy(tbl.pfrt_anchor, ac->name, sizeof(tbl.pfrt_anchor));
- strlcpy(tbl.pfrt_ruleset, rs->name, sizeof(tbl.pfrt_ruleset));
- }
kt = pfr_lookup_table(&tbl);
if (kt == NULL) {
- kt = pfr_create_ktable(&tbl, time.tv_sec, 1);
+ kt = pfr_create_ktable(&tbl, time_second, 1);
if (kt == NULL)
return (NULL);
if (ac != NULL) {
bzero(tbl.pfrt_anchor, sizeof(tbl.pfrt_anchor));
- bzero(tbl.pfrt_ruleset, sizeof(tbl.pfrt_ruleset));
rt = pfr_lookup_table(&tbl);
if (rt == NULL) {
rt = pfr_create_ktable(&tbl, 0, 1);
@@ -2001,8 +2092,10 @@ pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter,
union sockaddr_union mask;
int idx = -1, use_counter = 0;
- addr = (af == AF_INET) ? (struct pf_addr *)&pfr_sin.sin_addr :
- (struct pf_addr *)&pfr_sin6.sin6_addr;
+ if (af == AF_INET)
+ addr = (struct pf_addr *)&pfr_sin.sin_addr;
+ else if (af == AF_INET6)
+ addr = (struct pf_addr *)&pfr_sin6.sin6_addr;
if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
kt = kt->pfrkt_root;
if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
@@ -2045,9 +2138,12 @@ _next_block:
}
for (;;) {
/* we don't want to use a nested block */
- ke2 = (struct pfr_kentry *)(af == AF_INET ?
- rn_match(&pfr_sin, kt->pfrkt_ip4) :
- rn_match(&pfr_sin6, kt->pfrkt_ip6));
+ if (af == AF_INET)
+ ke2 = (struct pfr_kentry *)rn_match(&pfr_sin,
+ kt->pfrkt_ip4);
+ else if (af == AF_INET6)
+ ke2 = (struct pfr_kentry *)rn_match(&pfr_sin6,
+ kt->pfrkt_ip6);
/* no need to check KENTRY_RNF_ROOT() here */
if (ke2 == ke) {
/* lookup return the same block - perfect */
@@ -2080,12 +2176,16 @@ pfr_kentry_byidx(struct pfr_ktable *kt, int idx, int af)
w.pfrw_cnt = idx;
switch (af) {
+#ifdef INET
case AF_INET:
rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
return (w.pfrw_kentry);
+#endif /* INET */
+#ifdef INET6
case AF_INET6:
rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
return (w.pfrw_kentry);
+#endif /* INET6 */
default:
return (NULL);
}
diff --git a/sys/contrib/pf/net/pfvar.h b/sys/contrib/pf/net/pfvar.h
index 851d39591960..d27d01d2323b 100644
--- a/sys/contrib/pf/net/pfvar.h
+++ b/sys/contrib/pf/net/pfvar.h
@@ -1,5 +1,4 @@
-/* $OpenBSD: pfvar.h,v 1.187 2004/03/22 04:54:18 mcbride Exp $ */
-/* add $OpenBSD: pfvar.h,v 1.194 2004/05/11 07:34:11 dhartmei Exp $ */
+/* $OpenBSD: pfvar.h,v 1.213 2005/03/03 07:13:39 dhartmei Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -34,11 +33,13 @@
#ifndef _NET_PFVAR_H_
#define _NET_PFVAR_H_
+#include <sys/param.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/tree.h>
#include <net/radix.h>
+#include <net/route.h>
#include <netinet/ip_ipsp.h>
#include <netinet/tcp_fsm.h>
@@ -49,7 +50,7 @@ struct ip;
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,
+enum { PF_PASS, PF_DROP, PF_SCRUB, PF_NOSCRUB, 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,
PF_RULESET_BINAT, PF_RULESET_RDR, PF_RULESET_MAX };
@@ -70,14 +71,35 @@ enum { PFTM_TCP_FIRST_PACKET, PFTM_TCP_OPENING, PFTM_TCP_ESTABLISHED,
PFTM_OTHER_FIRST_PACKET, PFTM_OTHER_SINGLE,
PFTM_OTHER_MULTIPLE, PFTM_FRAG, PFTM_INTERVAL,
PFTM_ADAPTIVE_START, PFTM_ADAPTIVE_END, PFTM_SRC_NODE,
- PFTM_MAX, PFTM_PURGE, PFTM_UNTIL_PACKET };
+ PFTM_TS_DIFF, PFTM_MAX, PFTM_PURGE, PFTM_UNTIL_PACKET };
+
+/* PFTM default values */
+#define PFTM_TCP_FIRST_PACKET_VAL 120 /* First TCP packet */
+#define PFTM_TCP_OPENING_VAL 30 /* No response yet */
+#define PFTM_TCP_ESTABLISHED_VAL 24*60*60/* Established */
+#define PFTM_TCP_CLOSING_VAL 15 * 60 /* Half closed */
+#define PFTM_TCP_FIN_WAIT_VAL 45 /* Got both FINs */
+#define PFTM_TCP_CLOSED_VAL 90 /* Got a RST */
+#define PFTM_UDP_FIRST_PACKET_VAL 60 /* First UDP packet */
+#define PFTM_UDP_SINGLE_VAL 30 /* Unidirectional */
+#define PFTM_UDP_MULTIPLE_VAL 60 /* Bidirectional */
+#define PFTM_ICMP_FIRST_PACKET_VAL 20 /* First ICMP packet */
+#define PFTM_ICMP_ERROR_REPLY_VAL 10 /* Got error response */
+#define PFTM_OTHER_FIRST_PACKET_VAL 60 /* First packet */
+#define PFTM_OTHER_SINGLE_VAL 30 /* Unidirectional */
+#define PFTM_OTHER_MULTIPLE_VAL 60 /* Bidirectional */
+#define PFTM_FRAG_VAL 30 /* Fragment expire */
+#define PFTM_INTERVAL_VAL 10 /* Expire interval */
+#define PFTM_SRC_NODE_VAL 0 /* Source tracking */
+#define PFTM_TS_DIFF_VAL 30 /* Allowed TS diff */
+
enum { PF_NOPFROUTE, PF_FASTROUTE, PF_ROUTETO, PF_DUPTO, PF_REPLYTO };
enum { PF_LIMIT_STATES, PF_LIMIT_SRC_NODES, PF_LIMIT_FRAGS, PF_LIMIT_MAX };
#define PF_POOL_IDMASK 0x0f
enum { PF_POOL_NONE, PF_POOL_BITMASK, PF_POOL_RANDOM,
PF_POOL_SRCHASH, PF_POOL_ROUNDROBIN };
enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL,
- PF_ADDR_TABLE };
+ PF_ADDR_TABLE, PF_ADDR_RTLABEL };
#define PF_POOL_TYPEMASK 0x0f
#define PF_POOL_STICKYADDR 0x20
#define PF_WSCALE_FLAG 0x80
@@ -114,6 +136,8 @@ struct pf_addr_wrap {
} a;
char ifname[IFNAMSIZ];
char tblname[PF_TABLE_NAME_SIZE];
+ char rtlabelname[RTLABEL_LEN];
+ u_int32_t rtlabel;
} v;
union {
struct pfi_dynaddr *dyn;
@@ -275,10 +299,12 @@ struct pfi_dynaddr {
#endif /* PF_INET6_ONLY */
#endif /* PF_INET_INET6 */
-#define PF_MISMATCHAW(aw, x, af, not) \
+#define PF_MISMATCHAW(aw, x, af, neg) \
( \
(((aw)->type == PF_ADDR_NOROUTE && \
pf_routable((x), (af))) || \
+ ((aw)->type == PF_ADDR_RTLABEL && \
+ !pf_rtlabel_match((x), (af), (aw))) || \
((aw)->type == PF_ADDR_TABLE && \
!pfr_match_addr((aw)->p.tbl, (x), (af))) || \
((aw)->type == PF_ADDR_DYNIFTL && \
@@ -287,7 +313,7 @@ struct pfi_dynaddr {
!PF_AZERO(&(aw)->v.a.mask, (af)) && \
!PF_MATCHA(0, &(aw)->v.a.addr, \
&(aw)->v.a.mask, (x), (af)))) != \
- (not) \
+ (neg) \
)
struct pf_rule_uid {
@@ -303,7 +329,7 @@ struct pf_rule_gid {
struct pf_rule_addr {
struct pf_addr_wrap addr;
u_int16_t port[2];
- u_int8_t not;
+ u_int8_t neg;
u_int8_t port_op;
};
@@ -445,6 +471,8 @@ union pf_rule_ptr {
u_int32_t nr;
};
+#define PF_ANCHOR_NAME_SIZE 64
+
struct pf_rule {
struct pf_rule_addr src;
struct pf_rule_addr dst;
@@ -464,12 +492,12 @@ struct pf_rule {
char ifname[IFNAMSIZ];
char qname[PF_QNAME_SIZE];
char pqname[PF_QNAME_SIZE];
-#define PF_ANCHOR_NAME_SIZE 16
- char anchorname[PF_ANCHOR_NAME_SIZE];
#define PF_TAG_NAME_SIZE 16
char tagname[PF_TAG_NAME_SIZE];
char match_tagname[PF_TAG_NAME_SIZE];
+ char overload_tblname[PF_TABLE_NAME_SIZE];
+
TAILQ_ENTRY(pf_rule) entries;
struct pf_pool rpool;
@@ -479,6 +507,7 @@ struct pf_rule {
struct pfi_kif *kif;
struct pf_anchor *anchor;
+ struct pfr_ktable *overload_tbl;
pf_osfp_t os_fingerprint;
@@ -488,10 +517,16 @@ struct pf_rule {
u_int32_t src_nodes;
u_int32_t max_src_nodes;
u_int32_t max_src_states;
+ u_int32_t max_src_conn;
+ struct {
+ u_int32_t limit;
+ u_int32_t seconds;
+ } max_src_conn_rate;
u_int32_t qid;
u_int32_t pqid;
u_int32_t rt_listid;
u_int32_t nr;
+ u_int32_t prob;
u_int16_t return_icmp;
u_int16_t return_icmp6;
@@ -526,6 +561,12 @@ struct pf_rule {
u_int8_t rt;
u_int8_t return_ttl;
u_int8_t tos;
+ u_int8_t anchor_relative;
+ u_int8_t anchor_wildcard;
+
+#define PF_FLUSH 0x01
+#define PF_FLUSH_GLOBAL 0x02
+ u_int8_t flush;
};
/* rule flags */
@@ -551,6 +592,16 @@ struct pf_rule {
#define PFSTATE_HIWAT 10000 /* default state table size */
+
+struct pf_threshold {
+ u_int32_t limit;
+#define PF_THRESHOLD_MULT 1000
+#define PF_THRESHOLD_MAX 0xffffffff / PF_THRESHOLD_MULT
+ u_int32_t seconds;
+ u_int32_t count;
+ u_int32_t last;
+};
+
struct pf_src_node {
RB_ENTRY(pf_src_node) entry;
struct pf_addr addr;
@@ -560,6 +611,8 @@ struct pf_src_node {
u_int32_t bytes;
u_int32_t packets;
u_int32_t states;
+ u_int32_t conn;
+ struct pf_threshold conn_rate;
u_int32_t creation;
u_int32_t expire;
sa_family_t af;
@@ -569,11 +622,19 @@ struct pf_src_node {
#define PFSNODE_HIWAT 10000 /* default source node table size */
struct pf_state_scrub {
+ struct timeval pfss_last; /* time received last packet */
+ u_int32_t pfss_tsecr; /* last echoed timestamp */
+ u_int32_t pfss_tsval; /* largest timestamp */
+ u_int32_t pfss_tsval0; /* original timestamp */
u_int16_t pfss_flags;
-#define PFSS_TIMESTAMP 0x0001 /* modulate timestamp */
- u_int8_t pfss_ttl; /* stashed TTL */
+#define PFSS_TIMESTAMP 0x0001 /* modulate timestamp */
+#define PFSS_PAWS 0x0010 /* stricter PAWS checks */
+#define PFSS_PAWS_IDLED 0x0020 /* was idle too long. no PAWS */
+#define PFSS_DATA_TS 0x0040 /* timestamp on data packets */
+#define PFSS_DATA_NOTS 0x0080 /* no timestamp on data packets */
+ u_int8_t pfss_ttl; /* stashed TTL */
u_int8_t pad;
- u_int32_t pfss_ts_mod; /* timestamp modulation */
+ u_int32_t pfss_ts_mod; /* timestamp modulation */
};
struct pf_state_host {
@@ -625,6 +686,7 @@ struct pf_state {
u_int32_t packets[2];
u_int32_t bytes[2];
u_int32_t creatorid;
+ u_int16_t tag;
sa_family_t af;
u_int8_t proto;
u_int8_t direction;
@@ -634,6 +696,7 @@ struct pf_state {
u_int8_t sync_flags;
#define PFSTATE_NOSYNC 0x01
#define PFSTATE_FROMSYNC 0x02
+#define PFSTATE_STALE 0x04
u_int8_t pad;
};
@@ -642,9 +705,6 @@ TAILQ_HEAD(pf_rulequeue, pf_rule);
struct pf_anchor;
struct pf_ruleset {
- TAILQ_ENTRY(pf_ruleset) entries;
-#define PF_RULESET_NAME_SIZE 16
- char name[PF_RULESET_NAME_SIZE];
struct {
struct pf_rulequeue queues[2];
struct {
@@ -659,19 +719,22 @@ struct pf_ruleset {
int topen;
};
-TAILQ_HEAD(pf_rulesetqueue, pf_ruleset);
-
+RB_HEAD(pf_anchor_global, pf_anchor);
+RB_HEAD(pf_anchor_node, pf_anchor);
struct pf_anchor {
- TAILQ_ENTRY(pf_anchor) entries;
+ RB_ENTRY(pf_anchor) entry_global;
+ RB_ENTRY(pf_anchor) entry_node;
+ struct pf_anchor *parent;
+ struct pf_anchor_node children;
char name[PF_ANCHOR_NAME_SIZE];
- struct pf_rulesetqueue rulesets;
- int tables;
+ char path[MAXPATHLEN];
+ struct pf_ruleset ruleset;
+ int refcnt; /* anchor rules */
};
-
-TAILQ_HEAD(pf_anchorqueue, pf_anchor);
+RB_PROTOTYPE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare);
+RB_PROTOTYPE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare);
#define PF_RESERVED_ANCHOR "_pf"
-#define PF_INTERFACE_RULESET "_if"
#define PFR_TFLAG_PERSIST 0x00000001
#define PFR_TFLAG_CONST 0x00000002
@@ -684,8 +747,7 @@ TAILQ_HEAD(pf_anchorqueue, pf_anchor);
#define PFR_TFLAG_ALLMASK 0x0000003F
struct pfr_table {
- char pfrt_anchor[PF_ANCHOR_NAME_SIZE];
- char pfrt_ruleset[PF_RULESET_NAME_SIZE];
+ char pfrt_anchor[MAXPATHLEN];
char pfrt_name[PF_TABLE_NAME_SIZE];
u_int32_t pfrt_flags;
u_int8_t pfrt_fback;
@@ -746,6 +808,7 @@ struct pfr_kentry {
u_int8_t pfrke_net;
u_int8_t pfrke_not;
u_int8_t pfrke_mark;
+ u_int8_t pfrke_intrpool;
};
SLIST_HEAD(pfr_ktableworkq, pfr_ktable);
@@ -828,6 +891,8 @@ struct pfi_kif {
#define PFI_IFLAG_CLONABLE 0x0010 /* clonable group */
#define PFI_IFLAG_DYNAMIC 0x0020 /* dynamic group */
#define PFI_IFLAG_ATTACHED 0x0040 /* interface attached */
+#define PFI_IFLAG_SKIP 0x0100 /* skip filtering on interface */
+#define PFI_IFLAG_SETABLE_MASK 0x0100 /* setable via DIOC{SET,CLR}IFFLAG */
struct pf_pdesc {
u_int64_t tot_len; /* Make Mickey money */
@@ -845,11 +910,14 @@ struct pf_pdesc {
struct pf_rule *nat_rule; /* nat/rdr rule applied to packet */
struct pf_addr *src;
struct pf_addr *dst;
+ struct ether_header
+ *eh;
u_int16_t *ip_sum;
u_int32_t p_len; /* total length of payload */
u_int16_t flags; /* Let SCRUB trigger behavior in
* state code. Easier than tags */
#define PFDESC_TCP_NORM 0x0001 /* TCP shall be statefully scrubbed */
+#define PFDESC_IP_REAS 0x0002 /* IP frags would've been reassembled */
sa_family_t af;
u_int8_t proto;
u_int8_t tos;
@@ -866,7 +934,16 @@ struct pf_pdesc {
#define PFRES_SHORT 3 /* Dropping short packet */
#define PFRES_NORM 4 /* Dropping by normalizer */
#define PFRES_MEMORY 5 /* Dropped due to lacking mem */
-#define PFRES_MAX 6 /* total+1 */
+#define PFRES_TS 6 /* Bad TCP Timestamp (RFC1323) */
+#define PFRES_CONGEST 7 /* Congestion (of ipintrq) */
+#define PFRES_IPOPTIONS 8 /* IP option */
+#define PFRES_PROTCKSUM 9 /* Protocol checksum invalid */
+#define PFRES_BADSTATE 10 /* State mismatch */
+#define PFRES_STATEINS 11 /* State insertion failure */
+#define PFRES_MAXSTATES 12 /* State limit */
+#define PFRES_SRCLIMIT 13 /* Source node/conn limit */
+#define PFRES_SYNPROXY 14 /* SYN proxy */
+#define PFRES_MAX 15 /* total+1 */
#define PFRES_NAMES { \
"match", \
@@ -875,6 +952,36 @@ struct pf_pdesc {
"short", \
"normalize", \
"memory", \
+ "bad-timestamp", \
+ "congestion", \
+ "ip-option", \
+ "proto-cksum", \
+ "state-mismatch", \
+ "state-insert", \
+ "state-limit", \
+ "src-limit", \
+ "synproxy", \
+ NULL \
+}
+
+/* Counters for other things we want to keep track of */
+#define LCNT_STATES 0 /* states */
+#define LCNT_SRCSTATES 1 /* max-src-states */
+#define LCNT_SRCNODES 2 /* max-src-nodes */
+#define LCNT_SRCCONN 3 /* max-src-conn */
+#define LCNT_SRCCONNRATE 4 /* max-src-conn-rate */
+#define LCNT_OVERLOAD_TABLE 5 /* entry added to overload table */
+#define LCNT_OVERLOAD_FLUSH 6 /* state entries flushed */
+#define LCNT_MAX 7 /* total+1 */
+
+#define LCNT_NAMES { \
+ "max states per rule", \
+ "max-src-states", \
+ "max-src-nodes", \
+ "max-src-conn", \
+ "max-src-conn-rate", \
+ "overload table insertion", \
+ "overload flush states", \
NULL \
}
@@ -932,6 +1039,7 @@ struct pf_pdesc {
struct pf_status {
u_int64_t counters[PFRES_MAX];
+ u_int64_t lcounters[LCNT_MAX]; /* limit counters */
u_int64_t fcounters[FCNT_MAX];
u_int64_t scounters[SCNT_MAX];
u_int64_t pcounters[2][2][3];
@@ -1034,8 +1142,7 @@ struct pfioc_pooladdr {
u_int8_t r_action;
u_int8_t r_last;
u_int8_t af;
- char anchor[PF_ANCHOR_NAME_SIZE];
- char ruleset[PF_RULESET_NAME_SIZE];
+ char anchor[MAXPATHLEN];
struct pf_pooladdr addr;
};
@@ -1044,8 +1151,8 @@ struct pfioc_rule {
u_int32_t ticket;
u_int32_t pool_ticket;
u_int32_t nr;
- char anchor[PF_ANCHOR_NAME_SIZE];
- char ruleset[PF_RULESET_NAME_SIZE];
+ char anchor[MAXPATHLEN];
+ char anchor_call[MAXPATHLEN];
struct pf_rule rule;
};
@@ -1126,15 +1233,10 @@ struct pfioc_qstats {
u_int8_t scheduler;
};
-struct pfioc_anchor {
- u_int32_t nr;
- char name[PF_ANCHOR_NAME_SIZE];
-};
-
struct pfioc_ruleset {
u_int32_t nr;
- char anchor[PF_ANCHOR_NAME_SIZE];
- char name[PF_RULESET_NAME_SIZE];
+ char path[MAXPATHLEN];
+ char name[PF_ANCHOR_NAME_SIZE];
};
#define PF_RULESET_ALTQ (PF_RULESET_MAX)
@@ -1144,8 +1246,7 @@ struct pfioc_trans {
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];
+ char anchor[MAXPATHLEN];
u_int32_t ticket;
} *array;
};
@@ -1202,9 +1303,7 @@ struct pfioc_iface {
#define DIOCSTART _IO ('D', 1)
#define DIOCSTOP _IO ('D', 2)
-#define DIOCBEGINRULES _IOWR('D', 3, struct pfioc_rule)
#define DIOCADDRULE _IOWR('D', 4, struct pfioc_rule)
-#define DIOCCOMMITRULES _IOWR('D', 5, struct pfioc_rule)
#define DIOCGETRULES _IOWR('D', 6, struct pfioc_rule)
#define DIOCGETRULE _IOWR('D', 7, struct pfioc_rule)
/* XXX cut 8 - 17 */
@@ -1227,9 +1326,7 @@ struct pfioc_iface {
#define DIOCKILLSTATES _IOWR('D', 41, struct pfioc_state_kill)
#define DIOCSTARTALTQ _IO ('D', 42)
#define DIOCSTOPALTQ _IO ('D', 43)
-#define DIOCBEGINALTQS _IOWR('D', 44, u_int32_t)
#define DIOCADDALTQ _IOWR('D', 45, struct pfioc_altq)
-#define DIOCCOMMITALTQS _IOWR('D', 46, u_int32_t)
#define DIOCGETALTQS _IOWR('D', 47, struct pfioc_altq)
#define DIOCGETALTQ _IOWR('D', 48, struct pfioc_altq)
#define DIOCCHANGEALTQ _IOWR('D', 49, struct pfioc_altq)
@@ -1239,8 +1336,7 @@ struct pfioc_iface {
#define DIOCGETADDRS _IOWR('D', 53, struct pfioc_pooladdr)
#define DIOCGETADDR _IOWR('D', 54, struct pfioc_pooladdr)
#define DIOCCHANGEADDR _IOWR('D', 55, struct pfioc_pooladdr)
-#define DIOCGETANCHORS _IOWR('D', 56, struct pfioc_anchor)
-#define DIOCGETANCHOR _IOWR('D', 57, struct pfioc_anchor)
+/* XXX cut 55 - 57 */
#define DIOCGETRULESETS _IOWR('D', 58, struct pfioc_ruleset)
#define DIOCGETRULESET _IOWR('D', 59, struct pfioc_ruleset)
#define DIOCRCLRTABLES _IOWR('D', 60, struct pfioc_table)
@@ -1258,8 +1354,6 @@ struct pfioc_iface {
#define DIOCRCLRASTATS _IOWR('D', 72, struct pfioc_table)
#define DIOCRTSTADDRS _IOWR('D', 73, struct pfioc_table)
#define DIOCRSETTFLAGS _IOWR('D', 74, struct pfioc_table)
-#define DIOCRINABEGIN _IOWR('D', 75, struct pfioc_table)
-#define DIOCRINACOMMIT _IOWR('D', 76, struct pfioc_table)
#define DIOCRINADEFINE _IOWR('D', 77, struct pfioc_table)
#define DIOCOSFPFLUSH _IO('D', 78)
#define DIOCOSFPADD _IOWR('D', 79, struct pf_osfp_ioctl)
@@ -1272,6 +1366,8 @@ struct pfioc_iface {
#define DIOCSETHOSTID _IOWR('D', 86, u_int32_t)
#define DIOCIGETIFACES _IOWR('D', 87, struct pfioc_iface)
#define DIOCICLRISTATS _IOWR('D', 88, struct pfioc_iface)
+#define DIOCSETIFFLAG _IOWR('D', 89, struct pfioc_iface)
+#define DIOCCLRIFFLAG _IOWR('D', 90, struct pfioc_iface)
#ifdef _KERNEL
RB_HEAD(pf_src_tree, pf_src_node);
@@ -1284,7 +1380,7 @@ RB_PROTOTYPE(pf_state_tree_id, pf_state,
extern struct pf_state_tree_id tree_id;
extern struct pf_state_queue state_updates;
-extern struct pf_anchorqueue pf_anchors;
+extern struct pf_anchor_global pf_anchors;
extern struct pf_ruleset pf_main_ruleset;
TAILQ_HEAD(pf_poolqueue, pf_pool);
extern struct pf_poolqueue pf_pools[2];
@@ -1306,13 +1402,13 @@ extern int pf_tbladdr_setup(struct pf_ruleset *,
extern void pf_tbladdr_remove(struct pf_addr_wrap *);
extern void pf_tbladdr_copyout(struct pf_addr_wrap *);
extern void pf_calc_skip_steps(struct pf_rulequeue *);
-extern void pf_update_anchor_rules(void);
extern struct pool pf_src_tree_pl, pf_rule_pl;
extern struct pool pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
extern struct pool pf_state_scrub_pl;
extern void pf_purge_timeout(void *);
extern void pf_purge_expired_src_nodes(void);
extern void pf_purge_expired_states(void);
+extern void pf_purge_expired_state(struct pf_state *);
extern int pf_insert_state(struct pfi_kif *,
struct pf_state *);
extern int pf_insert_src_node(struct pf_src_node **,
@@ -1322,11 +1418,11 @@ 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 void pf_print_state(struct pf_state *);
+extern void pf_print_flags(u_int8_t);
extern struct pf_anchor *pf_find_anchor(const char *);
-extern struct pf_ruleset *pf_find_ruleset(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_ruleset(const char *);
+extern struct pf_ruleset *pf_find_or_create_ruleset(const char *);
extern void pf_remove_if_empty_ruleset(
struct pf_ruleset *);
extern u_int16_t pf_cksum_fixup(u_int16_t, u_int16_t, u_int16_t,
@@ -1340,11 +1436,11 @@ void pf_rm_rule(struct pf_rulequeue *,
struct pf_rule *);
#ifdef INET
-int pf_test(int, struct ifnet *, struct mbuf **);
+int pf_test(int, struct ifnet *, struct mbuf **, struct ether_header *);
#endif /* INET */
#ifdef INET6
-int pf_test6(int, struct ifnet *, struct mbuf **);
+int pf_test6(int, struct ifnet *, struct mbuf **, struct ether_header *);
void pf_poolmask(struct pf_addr *, struct pf_addr*,
struct pf_addr *, struct pf_addr *, u_int8_t);
void pf_addr_inc(struct pf_addr *, sa_family_t);
@@ -1363,20 +1459,23 @@ 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_ip(struct mbuf **, int, struct pfi_kif *, u_short *,
+ struct pf_pdesc *);
+int pf_normalize_ip6(struct mbuf **, int, struct pfi_kif *, u_short *,
+ struct pf_pdesc *);
int pf_normalize_tcp(int, struct pfi_kif *, 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 *,
struct tcphdr *, struct pf_state_peer *, struct pf_state_peer *);
int pf_normalize_tcp_stateful(struct mbuf *, int, struct pf_pdesc *,
- u_short *, struct tcphdr *, struct pf_state_peer *,
- struct pf_state_peer *, int *);
+ u_short *, struct tcphdr *, struct pf_state *,
+ struct pf_state_peer *, struct pf_state_peer *, int *);
u_int32_t
pf_state_expires(const struct pf_state *);
void pf_purge_expired_fragments(void);
int pf_routable(struct pf_addr *addr, sa_family_t af);
+int pf_rtlabel_match(struct pf_addr *, sa_family_t, struct pf_addr_wrap *);
void pfr_initialize(void);
int pfr_match_addr(struct pfr_ktable *, struct pf_addr *, sa_family_t);
void pfr_update_stats(struct pfr_ktable *, struct pf_addr *, sa_family_t,
@@ -1395,6 +1494,7 @@ int pfr_get_tstats(struct pfr_table *, struct pfr_tstats *, int *, int);
int pfr_clr_tstats(struct pfr_table *, int, int *, int);
int pfr_set_tflags(struct pfr_table *, int, int, int, int *, int *, int);
int pfr_clr_addrs(struct pfr_table *, int *, int);
+int pfr_insert_kentry(struct pfr_ktable *, struct pfr_addr *, long);
int pfr_add_addrs(struct pfr_table *, struct pfr_addr *, int, int *,
int);
int pfr_del_addrs(struct pfr_table *, struct pfr_addr *, int, int *,
@@ -1430,6 +1530,8 @@ 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_set_flags(const char *, int);
+int pfi_clear_flags(const char *, int);
int pfi_match_addr(struct pfi_dynaddr *, struct pf_addr *,
sa_family_t);
@@ -1437,6 +1539,7 @@ extern struct pfi_statehead pfi_statehead;
u_int16_t pf_tagname2tag(char *);
void pf_tag2tagname(u_int16_t, char *);
+void pf_tag_ref(u_int16_t);
void pf_tag_unref(u_int16_t);
int pf_tag_packet(struct mbuf *, struct pf_tag *, int);
u_int32_t pf_qname2qid(char *);