Import pf from OpenBSD 3.7 (OPENBSD_3_7 as of today)

This commit is contained in:
Max Laier 2005-05-03 16:34:36 +00:00
parent 61ba182027
commit f0d663ded8
11 changed files with 2404 additions and 1094 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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++;

View File

@ -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_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_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_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

File diff suppressed because it is too large Load Diff

View File

@ -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) {
@ -628,46 +624,6 @@ pfi_copy_group(char *p, const char *q, int m)
*p++ = '\0';
}
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)
{
@ -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;
@ -732,6 +688,44 @@ pfi_clr_istats(const char *name, int *nzero, int flags)
return (0);
}
int
pfi_set_flags(const char *name, int flags)
{
struct pfi_kif *p;
int s;
if (flags & ~PFI_IFLAG_SETABLE_MASK)
return (EINVAL);
s = splsoftnet();
RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
if (pfi_skip_if(name, p, PFI_FLAG_GROUP|PFI_FLAG_INSTANCE))
continue;
p->pfik_flags |= flags;
}
splx(s);
return (0);
}
int
pfi_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)
{
@ -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);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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)

View File

@ -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);
}

View File

@ -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 @@ pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
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 @@ pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter,
}
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);
}

View File

@ -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 *);