Import pf from OpenBSD 4.1
This commit is contained in:
parent
608d90c70d
commit
dc6ae5fc92
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: if_pflog.c,v 1.12 2004/05/19 17:50:51 dhartmei Exp $ */
|
||||
/* $OpenBSD: if_pflog.c,v 1.22 2006/12/15 09:31:20 otto Exp $ */
|
||||
/*
|
||||
* The authors of this code are John Ioannidis (ji@tla.org),
|
||||
* Angelos D. Keromytis (kermit@csd.uch.gr) and
|
||||
@ -39,6 +39,7 @@
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
@ -72,44 +73,90 @@
|
||||
#define DPRINTF(x)
|
||||
#endif
|
||||
|
||||
struct pflog_softc pflogif[NPFLOG];
|
||||
|
||||
void pflogattach(int);
|
||||
int pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
|
||||
struct rtentry *);
|
||||
int pflogioctl(struct ifnet *, u_long, caddr_t);
|
||||
void pflogrtrequest(int, struct rtentry *, struct sockaddr *);
|
||||
void pflogstart(struct ifnet *);
|
||||
int pflog_clone_create(struct if_clone *, int);
|
||||
int pflog_clone_destroy(struct ifnet *);
|
||||
|
||||
LIST_HEAD(, pflog_softc) pflogif_list;
|
||||
struct if_clone pflog_cloner =
|
||||
IF_CLONE_INITIALIZER("pflog", pflog_clone_create, pflog_clone_destroy);
|
||||
|
||||
struct ifnet *pflogifs[PFLOGIFS_MAX]; /* for fast access */
|
||||
|
||||
extern int ifqmaxlen;
|
||||
|
||||
void
|
||||
pflogattach(int npflog)
|
||||
{
|
||||
int i;
|
||||
LIST_INIT(&pflogif_list);
|
||||
for (i = 0; i < PFLOGIFS_MAX; i++)
|
||||
pflogifs[i] = NULL;
|
||||
(void) pflog_clone_create(&pflog_cloner, 0);
|
||||
if_clone_attach(&pflog_cloner);
|
||||
}
|
||||
|
||||
int
|
||||
pflog_clone_create(struct if_clone *ifc, int unit)
|
||||
{
|
||||
struct ifnet *ifp;
|
||||
int i;
|
||||
struct pflog_softc *pflogif;
|
||||
int s;
|
||||
|
||||
bzero(pflogif, sizeof(pflogif));
|
||||
if (unit >= PFLOGIFS_MAX)
|
||||
return (EINVAL);
|
||||
|
||||
for (i = 0; i < NPFLOG; i++) {
|
||||
ifp = &pflogif[i].sc_if;
|
||||
snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", i);
|
||||
ifp->if_softc = &pflogif[i];
|
||||
ifp->if_mtu = PFLOGMTU;
|
||||
ifp->if_ioctl = pflogioctl;
|
||||
ifp->if_output = pflogoutput;
|
||||
ifp->if_start = pflogstart;
|
||||
ifp->if_type = IFT_PFLOG;
|
||||
ifp->if_snd.ifq_maxlen = ifqmaxlen;
|
||||
ifp->if_hdrlen = PFLOG_HDRLEN;
|
||||
if_attach(ifp);
|
||||
if_alloc_sadl(ifp);
|
||||
if ((pflogif = malloc(sizeof(*pflogif), M_DEVBUF, M_NOWAIT)) == NULL)
|
||||
return (ENOMEM);
|
||||
bzero(pflogif, sizeof(*pflogif));
|
||||
|
||||
pflogif->sc_unit = unit;
|
||||
ifp = &pflogif->sc_if;
|
||||
snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", unit);
|
||||
ifp->if_softc = pflogif;
|
||||
ifp->if_mtu = PFLOGMTU;
|
||||
ifp->if_ioctl = pflogioctl;
|
||||
ifp->if_output = pflogoutput;
|
||||
ifp->if_start = pflogstart;
|
||||
ifp->if_type = IFT_PFLOG;
|
||||
ifp->if_snd.ifq_maxlen = ifqmaxlen;
|
||||
ifp->if_hdrlen = PFLOG_HDRLEN;
|
||||
if_attach(ifp);
|
||||
if_alloc_sadl(ifp);
|
||||
|
||||
#if NBPFILTER > 0
|
||||
bpfattach(&pflogif[i].sc_if.if_bpf, ifp, DLT_PFLOG,
|
||||
PFLOG_HDRLEN);
|
||||
bpfattach(&pflogif->sc_if.if_bpf, ifp, DLT_PFLOG, PFLOG_HDRLEN);
|
||||
#endif
|
||||
}
|
||||
|
||||
s = splnet();
|
||||
LIST_INSERT_HEAD(&pflogif_list, pflogif, sc_list);
|
||||
pflogifs[unit] = ifp;
|
||||
splx(s);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pflog_clone_destroy(struct ifnet *ifp)
|
||||
{
|
||||
struct pflog_softc *pflogif = ifp->if_softc;
|
||||
int s;
|
||||
|
||||
s = splnet();
|
||||
pflogifs[pflogif->sc_unit] = NULL;
|
||||
LIST_REMOVE(pflogif, sc_list);
|
||||
splx(s);
|
||||
|
||||
#if NBPFILTER > 0
|
||||
bpfdetach(ifp);
|
||||
#endif
|
||||
if_detach(ifp);
|
||||
free(pflogif, M_DEVBUF);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -122,7 +169,7 @@ pflogstart(struct ifnet *ifp)
|
||||
int s;
|
||||
|
||||
for (;;) {
|
||||
s = splimp();
|
||||
s = splnet();
|
||||
IF_DROP(&ifp->if_snd);
|
||||
IF_DEQUEUE(&ifp->if_snd, m);
|
||||
splx(s);
|
||||
@ -142,14 +189,6 @@ pflogoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
pflogrtrequest(int cmd, struct rtentry *rt, struct sockaddr *sa)
|
||||
{
|
||||
if (rt)
|
||||
rt->rt_rmx.rmx_mtu = PFLOGMTU;
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
@ -174,16 +213,18 @@ pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
int
|
||||
pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
|
||||
u_int8_t reason, struct pf_rule *rm, struct pf_rule *am,
|
||||
struct pf_ruleset *ruleset)
|
||||
struct pf_ruleset *ruleset, struct pf_pdesc *pd)
|
||||
{
|
||||
#if NBPFILTER > 0
|
||||
struct ifnet *ifn;
|
||||
struct pfloghdr hdr;
|
||||
struct mbuf m1;
|
||||
|
||||
if (kif == NULL || m == NULL || rm == NULL)
|
||||
if (kif == NULL || m == NULL || rm == NULL || pd == NULL)
|
||||
return (-1);
|
||||
|
||||
if ((ifn = pflogifs[rm->logif]) == NULL || !ifn->if_bpf)
|
||||
return (0);
|
||||
|
||||
bzero(&hdr, sizeof(hdr));
|
||||
hdr.length = PFLOG_REAL_HDRLEN;
|
||||
hdr.af = af;
|
||||
@ -201,6 +242,17 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
|
||||
strlcpy(hdr.ruleset, ruleset->anchor->name,
|
||||
sizeof(hdr.ruleset));
|
||||
}
|
||||
if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done)
|
||||
pd->lookup.done = pf_socket_lookup(dir, pd);
|
||||
if (pd->lookup.done > 0) {
|
||||
hdr.uid = pd->lookup.uid;
|
||||
hdr.pid = pd->lookup.pid;
|
||||
} else {
|
||||
hdr.uid = UID_MAX;
|
||||
hdr.pid = NO_PID;
|
||||
}
|
||||
hdr.rule_uid = rm->cuid;
|
||||
hdr.rule_pid = rm->cpid;
|
||||
hdr.dir = dir;
|
||||
|
||||
#ifdef INET
|
||||
@ -213,14 +265,10 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
|
||||
}
|
||||
#endif /* INET */
|
||||
|
||||
m1.m_next = m;
|
||||
m1.m_len = PFLOG_HDRLEN;
|
||||
m1.m_data = (char *) &hdr;
|
||||
|
||||
ifn = &(pflogif[0].sc_if);
|
||||
|
||||
if (ifn->if_bpf)
|
||||
bpf_mtap(ifn->if_bpf, &m1);
|
||||
ifn->if_opackets++;
|
||||
ifn->if_obytes += m->m_pkthdr.len;
|
||||
bpf_mtap_hdr(ifn->if_bpf, (char *)&hdr, PFLOG_HDRLEN, m,
|
||||
BPF_DIRECTION_OUT);
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: if_pflog.h,v 1.11 2004/05/19 17:50:51 dhartmei Exp $ */
|
||||
/* $OpenBSD: if_pflog.h,v 1.14 2006/10/25 11:27:01 henning Exp $ */
|
||||
/*
|
||||
* Copyright 2001 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
@ -27,8 +27,12 @@
|
||||
#ifndef _NET_IF_PFLOG_H_
|
||||
#define _NET_IF_PFLOG_H_
|
||||
|
||||
#define PFLOGIFS_MAX 16
|
||||
|
||||
struct pflog_softc {
|
||||
struct ifnet sc_if; /* the interface */
|
||||
struct ifnet sc_if; /* the interface */
|
||||
int sc_unit;
|
||||
LIST_ENTRY(pflog_softc) sc_list;
|
||||
};
|
||||
|
||||
#define PFLOG_RULESET_NAME_SIZE 16
|
||||
@ -42,6 +46,10 @@ struct pfloghdr {
|
||||
char ruleset[PFLOG_RULESET_NAME_SIZE];
|
||||
u_int32_t rulenr;
|
||||
u_int32_t subrulenr;
|
||||
uid_t uid;
|
||||
pid_t pid;
|
||||
uid_t rule_uid;
|
||||
pid_t rule_pid;
|
||||
u_int8_t dir;
|
||||
u_int8_t pad[3];
|
||||
};
|
||||
@ -64,9 +72,9 @@ struct old_pfloghdr {
|
||||
#ifdef _KERNEL
|
||||
|
||||
#if NPFLOG > 0
|
||||
#define PFLOG_PACKET(i,x,a,b,c,d,e,f,g) pflog_packet(i,a,b,c,d,e,f,g)
|
||||
#define PFLOG_PACKET(i,x,a,b,c,d,e,f,g,h) pflog_packet(i,a,b,c,d,e,f,g,h)
|
||||
#else
|
||||
#define PFLOG_PACKET(i,x,a,b,c,d,e,f,g) ((void)0)
|
||||
#define PFLOG_PACKET(i,x,a,b,c,d,e,f,g,h) ((void)0)
|
||||
#endif /* NPFLOG > 0 */
|
||||
#endif /* _KERNEL */
|
||||
#endif /* _NET_IF_PFLOG_H_ */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: if_pfsync.c,v 1.46 2005/02/20 15:58:38 mcbride Exp $ */
|
||||
/* $OpenBSD: if_pfsync.c,v 1.73 2006/11/16 13:13:38 henning Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002 Michael Shalayeff
|
||||
@ -26,8 +26,6 @@
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "bpfilter.h"
|
||||
#include "pfsync.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/proc.h>
|
||||
@ -43,11 +41,12 @@
|
||||
#include <net/if_types.h>
|
||||
#include <net/route.h>
|
||||
#include <net/bpf.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/if_ether.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/tcp_seq.h>
|
||||
|
||||
#ifdef INET
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/in_var.h>
|
||||
#include <netinet/ip.h>
|
||||
@ -55,20 +54,20 @@
|
||||
#endif
|
||||
|
||||
#ifdef INET6
|
||||
#ifndef INET
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#include <netinet6/nd6.h>
|
||||
#endif /* INET6 */
|
||||
|
||||
#include "carp.h"
|
||||
#if NCARP > 0
|
||||
extern int carp_suppress_preempt;
|
||||
#include <netinet/ip_carp.h>
|
||||
#endif
|
||||
|
||||
#include <net/pfvar.h>
|
||||
#include <net/if_pfsync.h>
|
||||
|
||||
#include "bpfilter.h"
|
||||
#include "pfsync.h"
|
||||
|
||||
#define PFSYNC_MINMTU \
|
||||
(sizeof(struct pfsync_header) + sizeof(struct pf_state))
|
||||
|
||||
@ -79,12 +78,17 @@ int pfsyncdebug;
|
||||
#define DPRINTF(x)
|
||||
#endif
|
||||
|
||||
struct pfsync_softc pfsyncif;
|
||||
struct pfsyncstats pfsyncstats;
|
||||
struct pfsync_softc *pfsyncif = NULL;
|
||||
struct pfsyncstats pfsyncstats;
|
||||
|
||||
void pfsyncattach(int);
|
||||
int pfsync_clone_create(struct if_clone *, int);
|
||||
int pfsync_clone_destroy(struct ifnet *);
|
||||
void pfsync_setmtu(struct pfsync_softc *, int);
|
||||
int pfsync_insert_net_state(struct pfsync_state *);
|
||||
int pfsync_alloc_scrub_memory(struct pfsync_state_peer *,
|
||||
struct pf_state_peer *);
|
||||
int pfsync_insert_net_state(struct pfsync_state *, u_int8_t);
|
||||
void pfsync_update_net_tdb(struct pfsync_tdb *);
|
||||
int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
|
||||
struct rtentry *);
|
||||
int pfsyncioctl(struct ifnet *, u_long, caddr_t);
|
||||
@ -93,7 +97,10 @@ void pfsyncstart(struct ifnet *);
|
||||
struct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **);
|
||||
int pfsync_request_update(struct pfsync_state_upd *, struct in_addr *);
|
||||
int pfsync_sendout(struct pfsync_softc *);
|
||||
int pfsync_tdb_sendout(struct pfsync_softc *);
|
||||
int pfsync_sendout_mbuf(struct pfsync_softc *, struct mbuf *);
|
||||
void pfsync_timeout(void *);
|
||||
void pfsync_tdb_timeout(void *);
|
||||
void pfsync_send_bus(struct pfsync_softc *, u_int8_t);
|
||||
void pfsync_bulk_update(void *);
|
||||
void pfsync_bulkfail(void *);
|
||||
@ -101,41 +108,77 @@ void pfsync_bulkfail(void *);
|
||||
int pfsync_sync_ok;
|
||||
extern int ifqmaxlen;
|
||||
|
||||
struct if_clone pfsync_cloner =
|
||||
IF_CLONE_INITIALIZER("pfsync", pfsync_clone_create, pfsync_clone_destroy);
|
||||
|
||||
void
|
||||
pfsyncattach(int npfsync)
|
||||
{
|
||||
if_clone_attach(&pfsync_cloner);
|
||||
}
|
||||
int
|
||||
pfsync_clone_create(struct if_clone *ifc, int unit)
|
||||
{
|
||||
struct ifnet *ifp;
|
||||
|
||||
if (unit != 0)
|
||||
return (EINVAL);
|
||||
|
||||
pfsync_sync_ok = 1;
|
||||
bzero(&pfsyncif, sizeof(pfsyncif));
|
||||
pfsyncif.sc_mbuf = NULL;
|
||||
pfsyncif.sc_mbuf_net = NULL;
|
||||
pfsyncif.sc_statep.s = NULL;
|
||||
pfsyncif.sc_statep_net.s = NULL;
|
||||
pfsyncif.sc_maxupdates = 128;
|
||||
pfsyncif.sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
|
||||
pfsyncif.sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
|
||||
pfsyncif.sc_ureq_received = 0;
|
||||
pfsyncif.sc_ureq_sent = 0;
|
||||
ifp = &pfsyncif.sc_if;
|
||||
strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname);
|
||||
ifp->if_softc = &pfsyncif;
|
||||
if ((pfsyncif = malloc(sizeof(*pfsyncif), M_DEVBUF, M_NOWAIT)) == NULL)
|
||||
return (ENOMEM);
|
||||
bzero(pfsyncif, sizeof(*pfsyncif));
|
||||
pfsyncif->sc_mbuf = NULL;
|
||||
pfsyncif->sc_mbuf_net = NULL;
|
||||
pfsyncif->sc_mbuf_tdb = NULL;
|
||||
pfsyncif->sc_statep.s = NULL;
|
||||
pfsyncif->sc_statep_net.s = NULL;
|
||||
pfsyncif->sc_statep_tdb.t = NULL;
|
||||
pfsyncif->sc_maxupdates = 128;
|
||||
pfsyncif->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
|
||||
pfsyncif->sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
|
||||
pfsyncif->sc_ureq_received = 0;
|
||||
pfsyncif->sc_ureq_sent = 0;
|
||||
pfsyncif->sc_bulk_send_next = NULL;
|
||||
pfsyncif->sc_bulk_terminator = NULL;
|
||||
ifp = &pfsyncif->sc_if;
|
||||
snprintf(ifp->if_xname, sizeof ifp->if_xname, "pfsync%d", unit);
|
||||
ifp->if_softc = pfsyncif;
|
||||
ifp->if_ioctl = pfsyncioctl;
|
||||
ifp->if_output = pfsyncoutput;
|
||||
ifp->if_start = pfsyncstart;
|
||||
ifp->if_type = IFT_PFSYNC;
|
||||
ifp->if_snd.ifq_maxlen = ifqmaxlen;
|
||||
ifp->if_hdrlen = PFSYNC_HDRLEN;
|
||||
pfsync_setmtu(&pfsyncif, MCLBYTES);
|
||||
timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif);
|
||||
timeout_set(&pfsyncif.sc_bulk_tmo, pfsync_bulk_update, &pfsyncif);
|
||||
timeout_set(&pfsyncif.sc_bulkfail_tmo, pfsync_bulkfail, &pfsyncif);
|
||||
pfsync_setmtu(pfsyncif, ETHERMTU);
|
||||
timeout_set(&pfsyncif->sc_tmo, pfsync_timeout, pfsyncif);
|
||||
timeout_set(&pfsyncif->sc_tdb_tmo, pfsync_tdb_timeout, pfsyncif);
|
||||
timeout_set(&pfsyncif->sc_bulk_tmo, pfsync_bulk_update, pfsyncif);
|
||||
timeout_set(&pfsyncif->sc_bulkfail_tmo, pfsync_bulkfail, pfsyncif);
|
||||
if_attach(ifp);
|
||||
if_alloc_sadl(ifp);
|
||||
|
||||
#if NBPFILTER > 0
|
||||
bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
|
||||
#if NCARP > 0
|
||||
if_addgroup(ifp, "carp");
|
||||
#endif
|
||||
|
||||
#if NBPFILTER > 0
|
||||
bpfattach(&pfsyncif->sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfsync_clone_destroy(struct ifnet *ifp)
|
||||
{
|
||||
#if NBPFILTER > 0
|
||||
bpfdetach(ifp);
|
||||
#endif
|
||||
if_detach(ifp);
|
||||
free(pfsyncif, M_DEVBUF);
|
||||
pfsyncif = NULL;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -148,7 +191,7 @@ pfsyncstart(struct ifnet *ifp)
|
||||
int s;
|
||||
|
||||
for (;;) {
|
||||
s = splimp();
|
||||
s = splnet();
|
||||
IF_DROP(&ifp->if_snd);
|
||||
IF_DEQUEUE(&ifp->if_snd, m);
|
||||
splx(s);
|
||||
@ -161,7 +204,21 @@ pfsyncstart(struct ifnet *ifp)
|
||||
}
|
||||
|
||||
int
|
||||
pfsync_insert_net_state(struct pfsync_state *sp)
|
||||
pfsync_alloc_scrub_memory(struct pfsync_state_peer *s,
|
||||
struct pf_state_peer *d)
|
||||
{
|
||||
if (s->scrub.scrub_flag && d->scrub == NULL) {
|
||||
d->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT);
|
||||
if (d->scrub == NULL)
|
||||
return (ENOMEM);
|
||||
bzero(d->scrub, sizeof(*d->scrub));
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag)
|
||||
{
|
||||
struct pf_state *st = NULL;
|
||||
struct pf_rule *r = NULL;
|
||||
@ -173,7 +230,7 @@ pfsync_insert_net_state(struct pfsync_state *sp)
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
kif = pfi_lookup_create(sp->ifname);
|
||||
kif = pfi_kif_get(sp->ifname);
|
||||
if (kif == NULL) {
|
||||
if (pf_status.debug >= PF_DEBUG_MISC)
|
||||
printf("pfsync_insert_net_state: "
|
||||
@ -183,19 +240,33 @@ pfsync_insert_net_state(struct pfsync_state *sp)
|
||||
}
|
||||
|
||||
/*
|
||||
* Just use the default rule until we have infrastructure to find the
|
||||
* best matching rule.
|
||||
* If the ruleset checksums match, it's safe to associate the state
|
||||
* with the rule of that number.
|
||||
*/
|
||||
r = &pf_default_rule;
|
||||
if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && chksum_flag)
|
||||
r = pf_main_ruleset.rules[
|
||||
PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)];
|
||||
else
|
||||
r = &pf_default_rule;
|
||||
|
||||
if (!r->max_states || r->states < r->max_states)
|
||||
st = pool_get(&pf_state_pl, PR_NOWAIT);
|
||||
if (st == NULL) {
|
||||
pfi_maybe_destroy(kif);
|
||||
pfi_kif_unref(kif, PFI_KIF_REF_NONE);
|
||||
return (ENOMEM);
|
||||
}
|
||||
bzero(st, sizeof(*st));
|
||||
|
||||
/* allocate memory for scrub info */
|
||||
if (pfsync_alloc_scrub_memory(&sp->src, &st->src) ||
|
||||
pfsync_alloc_scrub_memory(&sp->dst, &st->dst)) {
|
||||
pfi_kif_unref(kif, PFI_KIF_REF_NONE);
|
||||
if (st->src.scrub)
|
||||
pool_put(&pf_state_scrub_pl, st->src.scrub);
|
||||
pool_put(&pf_state_pl, st);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
st->rule.ptr = r;
|
||||
/* XXX get pointers to nat_rule and anchor */
|
||||
|
||||
@ -225,11 +296,14 @@ pfsync_insert_net_state(struct pfsync_state *sp)
|
||||
st->creatorid = sp->creatorid;
|
||||
st->sync_flags = PFSTATE_FROMSYNC;
|
||||
|
||||
|
||||
if (pf_insert_state(kif, st)) {
|
||||
pfi_maybe_destroy(kif);
|
||||
pfi_kif_unref(kif, PFI_KIF_REF_NONE);
|
||||
/* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */
|
||||
r->states--;
|
||||
if (st->dst.scrub)
|
||||
pool_put(&pf_state_scrub_pl, st->dst.scrub);
|
||||
if (st->src.scrub)
|
||||
pool_put(&pf_state_scrub_pl, st->src.scrub);
|
||||
pool_put(&pf_state_pl, st);
|
||||
return (EINVAL);
|
||||
}
|
||||
@ -242,22 +316,25 @@ pfsync_input(struct mbuf *m, ...)
|
||||
{
|
||||
struct ip *ip = mtod(m, struct ip *);
|
||||
struct pfsync_header *ph;
|
||||
struct pfsync_softc *sc = &pfsyncif;
|
||||
struct pf_state *st, key;
|
||||
struct pfsync_softc *sc = pfsyncif;
|
||||
struct pf_state *st;
|
||||
struct pf_state_cmp key;
|
||||
struct pfsync_state *sp;
|
||||
struct pfsync_state_upd *up;
|
||||
struct pfsync_state_del *dp;
|
||||
struct pfsync_state_clr *cp;
|
||||
struct pfsync_state_upd_req *rup;
|
||||
struct pfsync_state_bus *bus;
|
||||
struct pfsync_tdb *pt;
|
||||
struct in_addr src;
|
||||
struct mbuf *mp;
|
||||
int iplen, action, error, i, s, count, offp, sfail, stale = 0;
|
||||
u_int8_t chksum_flag = 0;
|
||||
|
||||
pfsyncstats.pfsyncs_ipackets++;
|
||||
|
||||
/* verify that we have a sync interface configured */
|
||||
if (!sc->sc_sync_ifp || !pf_status.running)
|
||||
if (!sc || !sc->sc_sync_ifp || !pf_status.running)
|
||||
goto done;
|
||||
|
||||
/* verify that the packet came in on the right interface */
|
||||
@ -306,6 +383,9 @@ pfsync_input(struct mbuf *m, ...)
|
||||
/* Cheaper to grab this now than having to mess with mbufs later */
|
||||
src = ip->ip_src;
|
||||
|
||||
if (!bcmp(&ph->pf_chksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH))
|
||||
chksum_flag++;
|
||||
|
||||
switch (action) {
|
||||
case PFSYNC_ACT_CLR: {
|
||||
struct pf_state *nexts;
|
||||
@ -323,28 +403,24 @@ pfsync_input(struct mbuf *m, ...)
|
||||
if (cp->ifname[0] == '\0') {
|
||||
for (st = RB_MIN(pf_state_tree_id, &tree_id);
|
||||
st; st = nexts) {
|
||||
nexts = RB_NEXT(pf_state_tree_id, &tree_id, st);
|
||||
nexts = RB_NEXT(pf_state_tree_id, &tree_id, st);
|
||||
if (st->creatorid == creatorid) {
|
||||
st->timeout = PFTM_PURGE;
|
||||
pf_purge_expired_state(st);
|
||||
st->sync_flags |= PFSTATE_FROMSYNC;
|
||||
pf_unlink_state(st);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
kif = pfi_lookup_if(cp->ifname);
|
||||
if (kif == NULL) {
|
||||
if (pf_status.debug >= PF_DEBUG_MISC)
|
||||
printf("pfsync_input: PFSYNC_ACT_CLR "
|
||||
"bad interface: %s\n", cp->ifname);
|
||||
if ((kif = pfi_kif_get(cp->ifname)) == NULL) {
|
||||
splx(s);
|
||||
goto done;
|
||||
return;
|
||||
}
|
||||
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);
|
||||
st->sync_flags |= PFSTATE_FROMSYNC;
|
||||
pf_unlink_state(st);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -375,7 +451,8 @@ pfsync_input(struct mbuf *m, ...)
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((error = pfsync_insert_net_state(sp))) {
|
||||
if ((error = pfsync_insert_net_state(sp,
|
||||
chksum_flag))) {
|
||||
if (error == ENOMEM) {
|
||||
splx(s);
|
||||
goto done;
|
||||
@ -414,7 +491,7 @@ pfsync_input(struct mbuf *m, ...)
|
||||
st = pf_find_state_byid(&key);
|
||||
if (st == NULL) {
|
||||
/* insert the update */
|
||||
if (pfsync_insert_net_state(sp))
|
||||
if (pfsync_insert_net_state(sp, chksum_flag))
|
||||
pfsyncstats.pfsyncs_badstate++;
|
||||
continue;
|
||||
}
|
||||
@ -453,7 +530,7 @@ pfsync_input(struct mbuf *m, ...)
|
||||
*/
|
||||
if (st->src.state > sp->src.state)
|
||||
sfail = 5;
|
||||
else if ( st->dst.state > sp->dst.state)
|
||||
else if (st->dst.state > sp->dst.state)
|
||||
sfail = 6;
|
||||
}
|
||||
if (sfail) {
|
||||
@ -478,6 +555,7 @@ pfsync_input(struct mbuf *m, ...)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
pfsync_alloc_scrub_memory(&sp->dst, &st->dst);
|
||||
pf_state_peer_ntoh(&sp->src, &st->src);
|
||||
pf_state_peer_ntoh(&sp->dst, &st->dst);
|
||||
st->expire = ntohl(sp->expire) + time_second;
|
||||
@ -509,9 +587,8 @@ pfsync_input(struct mbuf *m, ...)
|
||||
pfsyncstats.pfsyncs_badstate++;
|
||||
continue;
|
||||
}
|
||||
st->timeout = PFTM_PURGE;
|
||||
st->sync_flags |= PFSTATE_FROMSYNC;
|
||||
pf_purge_expired_state(st);
|
||||
pf_unlink_state(st);
|
||||
}
|
||||
splx(s);
|
||||
break;
|
||||
@ -604,6 +681,7 @@ pfsync_input(struct mbuf *m, ...)
|
||||
PFSYNC_FLAG_STALE);
|
||||
continue;
|
||||
}
|
||||
pfsync_alloc_scrub_memory(&up->dst, &st->dst);
|
||||
pf_state_peer_ntoh(&up->src, &st->src);
|
||||
pf_state_peer_ntoh(&up->dst, &st->dst);
|
||||
st->expire = ntohl(up->expire) + time_second;
|
||||
@ -632,9 +710,8 @@ pfsync_input(struct mbuf *m, ...)
|
||||
pfsyncstats.pfsyncs_badstate++;
|
||||
continue;
|
||||
}
|
||||
st->timeout = PFTM_PURGE;
|
||||
st->sync_flags |= PFSTATE_FROMSYNC;
|
||||
pf_purge_expired_state(st);
|
||||
pf_unlink_state(st);
|
||||
}
|
||||
splx(s);
|
||||
break;
|
||||
@ -660,6 +737,10 @@ pfsync_input(struct mbuf *m, ...)
|
||||
|
||||
if (key.id == 0 && key.creatorid == 0) {
|
||||
sc->sc_ureq_received = time_uptime;
|
||||
if (sc->sc_bulk_send_next == NULL)
|
||||
sc->sc_bulk_send_next =
|
||||
TAILQ_FIRST(&state_list);
|
||||
sc->sc_bulk_terminator = sc->sc_bulk_send_next;
|
||||
if (pf_status.debug >= PF_DEBUG_MISC)
|
||||
printf("pfsync: received "
|
||||
"bulk update request\n");
|
||||
@ -709,7 +790,7 @@ pfsync_input(struct mbuf *m, ...)
|
||||
timeout_del(&sc->sc_bulkfail_tmo);
|
||||
#if NCARP > 0
|
||||
if (!pfsync_sync_ok)
|
||||
carp_suppress_preempt--;
|
||||
carp_group_demote_adj(&sc->sc_if, -1);
|
||||
#endif
|
||||
pfsync_sync_ok = 1;
|
||||
if (pf_status.debug >= PF_DEBUG_MISC)
|
||||
@ -723,6 +804,18 @@ pfsync_input(struct mbuf *m, ...)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PFSYNC_ACT_TDB_UPD:
|
||||
if ((mp = m_pulldown(m, iplen + sizeof(*ph),
|
||||
count * sizeof(*pt), &offp)) == NULL) {
|
||||
pfsyncstats.pfsyncs_badlen++;
|
||||
return;
|
||||
}
|
||||
s = splsoftnet();
|
||||
for (i = 0, pt = (struct pfsync_tdb *)(mp->m_data + offp);
|
||||
i < count; i++, pt++)
|
||||
pfsync_update_net_tdb(pt);
|
||||
splx(s);
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
@ -862,7 +955,7 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
sc->sc_ureq_sent = time_uptime;
|
||||
#if NCARP > 0
|
||||
if (pfsync_sync_ok)
|
||||
carp_suppress_preempt++;
|
||||
carp_group_demote_adj(&sc->sc_if, 1);
|
||||
#endif
|
||||
pfsync_sync_ok = 0;
|
||||
if (pf_status.debug >= PF_DEBUG_MISC)
|
||||
@ -938,6 +1031,10 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
|
||||
len = sizeof(struct pfsync_header) +
|
||||
sizeof(struct pfsync_state_bus);
|
||||
break;
|
||||
case PFSYNC_ACT_TDB_UPD:
|
||||
len = (sc->sc_maxcount * sizeof(struct pfsync_tdb)) +
|
||||
sizeof(struct pfsync_header);
|
||||
break;
|
||||
default:
|
||||
len = (sc->sc_maxcount * sizeof(struct pfsync_state)) +
|
||||
sizeof(struct pfsync_header);
|
||||
@ -962,17 +1059,23 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
|
||||
h->af = 0;
|
||||
h->count = 0;
|
||||
h->action = action;
|
||||
if (action != PFSYNC_ACT_TDB_UPD)
|
||||
bcopy(&pf_status.pf_chksum, &h->pf_chksum,
|
||||
PF_MD5_DIGEST_LENGTH);
|
||||
|
||||
*sp = (void *)((char *)h + PFSYNC_HDRLEN);
|
||||
timeout_add(&sc->sc_tmo, hz);
|
||||
if (action == PFSYNC_ACT_TDB_UPD)
|
||||
timeout_add(&sc->sc_tdb_tmo, hz);
|
||||
else
|
||||
timeout_add(&sc->sc_tmo, hz);
|
||||
return (m);
|
||||
}
|
||||
|
||||
int
|
||||
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;
|
||||
struct ifnet *ifp = NULL;
|
||||
struct pfsync_softc *sc = pfsyncif;
|
||||
struct pfsync_header *h, *h_net;
|
||||
struct pfsync_state *sp = NULL;
|
||||
struct pfsync_state_upd *up = NULL;
|
||||
@ -982,6 +1085,10 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
|
||||
int s, ret = 0;
|
||||
u_int8_t i = 255, newaction = 0;
|
||||
|
||||
if (sc == NULL)
|
||||
return (0);
|
||||
ifp = &sc->sc_if;
|
||||
|
||||
/*
|
||||
* If a packet falls in the forest and there's nobody around to
|
||||
* hear, does it make a sound?
|
||||
@ -1044,8 +1151,6 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
|
||||
secs = time_second;
|
||||
|
||||
st->pfsync_time = time_uptime;
|
||||
TAILQ_REMOVE(&state_updates, st, u.s.entry_updates);
|
||||
TAILQ_INSERT_TAIL(&state_updates, st, u.s.entry_updates);
|
||||
|
||||
if (sp == NULL) {
|
||||
/* not a "duplicate" update */
|
||||
@ -1067,10 +1172,10 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
|
||||
bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
|
||||
|
||||
sp->creation = htonl(secs - st->creation);
|
||||
sp->packets[0] = htonl(st->packets[0]);
|
||||
sp->packets[1] = htonl(st->packets[1]);
|
||||
sp->bytes[0] = htonl(st->bytes[0]);
|
||||
sp->bytes[1] = htonl(st->bytes[1]);
|
||||
pf_state_counter_hton(st->packets[0], sp->packets[0]);
|
||||
pf_state_counter_hton(st->packets[1], sp->packets[1]);
|
||||
pf_state_counter_hton(st->bytes[0], sp->bytes[0]);
|
||||
pf_state_counter_hton(st->bytes[1], sp->bytes[1]);
|
||||
if ((r = st->rule.ptr) == NULL)
|
||||
sp->rule = htonl(-1);
|
||||
else
|
||||
@ -1169,12 +1274,16 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
|
||||
int
|
||||
pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src)
|
||||
{
|
||||
struct ifnet *ifp = &pfsyncif.sc_if;
|
||||
struct ifnet *ifp = NULL;
|
||||
struct pfsync_header *h;
|
||||
struct pfsync_softc *sc = ifp->if_softc;
|
||||
struct pfsync_softc *sc = pfsyncif;
|
||||
struct pfsync_state_upd_req *rup;
|
||||
int ret = 0;
|
||||
|
||||
if (sc == NULL)
|
||||
return (0);
|
||||
|
||||
ifp = &sc->sc_if;
|
||||
if (sc->sc_mbuf == NULL) {
|
||||
if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
|
||||
(void *)&sc->sc_statep.s)) == NULL)
|
||||
@ -1211,11 +1320,15 @@ pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src)
|
||||
int
|
||||
pfsync_clear_states(u_int32_t creatorid, char *ifname)
|
||||
{
|
||||
struct ifnet *ifp = &pfsyncif.sc_if;
|
||||
struct pfsync_softc *sc = ifp->if_softc;
|
||||
struct ifnet *ifp = NULL;
|
||||
struct pfsync_softc *sc = pfsyncif;
|
||||
struct pfsync_state_clr *cp;
|
||||
int s, ret;
|
||||
|
||||
if (sc == NULL)
|
||||
return (0);
|
||||
|
||||
ifp = &sc->sc_if;
|
||||
s = splnet();
|
||||
if (sc->sc_mbuf != NULL)
|
||||
pfsync_sendout(sc);
|
||||
@ -1246,6 +1359,17 @@ pfsync_timeout(void *v)
|
||||
splx(s);
|
||||
}
|
||||
|
||||
void
|
||||
pfsync_tdb_timeout(void *v)
|
||||
{
|
||||
struct pfsync_softc *sc = v;
|
||||
int s;
|
||||
|
||||
s = splnet();
|
||||
pfsync_tdb_sendout(sc);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
/* This must be called in splnet() */
|
||||
void
|
||||
pfsync_send_bus(struct pfsync_softc *sc, u_int8_t status)
|
||||
@ -1282,28 +1406,39 @@ pfsync_bulk_update(void *v)
|
||||
* Grab at most PFSYNC_BULKPACKETS worth of states which have not
|
||||
* been sent since the latest request was made.
|
||||
*/
|
||||
while ((state = TAILQ_FIRST(&state_updates)) != NULL &&
|
||||
++i < (sc->sc_maxcount * PFSYNC_BULKPACKETS)) {
|
||||
if (state->pfsync_time > sc->sc_ureq_received) {
|
||||
/* we're done */
|
||||
pfsync_send_bus(sc, PFSYNC_BUS_END);
|
||||
sc->sc_ureq_received = 0;
|
||||
timeout_del(&sc->sc_bulk_tmo);
|
||||
if (pf_status.debug >= PF_DEBUG_MISC)
|
||||
printf("pfsync: bulk update complete\n");
|
||||
break;
|
||||
} else {
|
||||
/* send an update and move to end of list */
|
||||
if (!state->sync_flags)
|
||||
state = sc->sc_bulk_send_next;
|
||||
if (state)
|
||||
do {
|
||||
/* send state update if syncable and not already sent */
|
||||
if (!state->sync_flags
|
||||
&& state->timeout < PFTM_MAX
|
||||
&& state->pfsync_time <= sc->sc_ureq_received) {
|
||||
pfsync_pack_state(PFSYNC_ACT_UPD, state, 0);
|
||||
state->pfsync_time = time_uptime;
|
||||
TAILQ_REMOVE(&state_updates, state, u.s.entry_updates);
|
||||
TAILQ_INSERT_TAIL(&state_updates, state,
|
||||
u.s.entry_updates);
|
||||
i++;
|
||||
}
|
||||
|
||||
/* look again for more in a bit */
|
||||
timeout_add(&sc->sc_bulk_tmo, 1);
|
||||
}
|
||||
/* figure next state to send */
|
||||
state = TAILQ_NEXT(state, u.s.entry_list);
|
||||
|
||||
/* wrap to start of list if we hit the end */
|
||||
if (!state)
|
||||
state = TAILQ_FIRST(&state_list);
|
||||
} while (i < sc->sc_maxcount * PFSYNC_BULKPACKETS &&
|
||||
state != sc->sc_bulk_terminator);
|
||||
|
||||
if (!state || state == sc->sc_bulk_terminator) {
|
||||
/* we're done */
|
||||
pfsync_send_bus(sc, PFSYNC_BUS_END);
|
||||
sc->sc_ureq_received = 0;
|
||||
sc->sc_bulk_send_next = NULL;
|
||||
sc->sc_bulk_terminator = NULL;
|
||||
timeout_del(&sc->sc_bulk_tmo);
|
||||
if (pf_status.debug >= PF_DEBUG_MISC)
|
||||
printf("pfsync: bulk update complete\n");
|
||||
} else {
|
||||
/* look again for more in a bit */
|
||||
timeout_add(&sc->sc_bulk_tmo, 1);
|
||||
sc->sc_bulk_send_next = state;
|
||||
}
|
||||
if (sc->sc_mbuf != NULL)
|
||||
pfsync_sendout(sc);
|
||||
@ -1334,7 +1469,7 @@ pfsync_bulkfail(void *v)
|
||||
sc->sc_bulk_tries = 0;
|
||||
#if NCARP > 0
|
||||
if (!pfsync_sync_ok)
|
||||
carp_suppress_preempt--;
|
||||
carp_group_demote_adj(&sc->sc_if, -1);
|
||||
#endif
|
||||
pfsync_sync_ok = 1;
|
||||
if (pf_status.debug >= PF_DEBUG_MISC)
|
||||
@ -1346,10 +1481,11 @@ pfsync_bulkfail(void *v)
|
||||
|
||||
/* This must be called in splnet() */
|
||||
int
|
||||
pfsync_sendout(sc)
|
||||
struct pfsync_softc *sc;
|
||||
pfsync_sendout(struct pfsync_softc *sc)
|
||||
{
|
||||
#if NBPFILTER > 0
|
||||
struct ifnet *ifp = &sc->sc_if;
|
||||
#endif
|
||||
struct mbuf *m;
|
||||
|
||||
timeout_del(&sc->sc_tmo);
|
||||
@ -1362,7 +1498,7 @@ pfsync_sendout(sc)
|
||||
|
||||
#if NBPFILTER > 0
|
||||
if (ifp->if_bpf)
|
||||
bpf_mtap(ifp->if_bpf, m);
|
||||
bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
|
||||
#endif
|
||||
|
||||
if (sc->sc_mbuf_net) {
|
||||
@ -1372,10 +1508,41 @@ pfsync_sendout(sc)
|
||||
sc->sc_statep_net.s = NULL;
|
||||
}
|
||||
|
||||
if (sc->sc_sync_ifp || sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) {
|
||||
struct ip *ip;
|
||||
struct sockaddr sa;
|
||||
return pfsync_sendout_mbuf(sc, m);
|
||||
}
|
||||
|
||||
int
|
||||
pfsync_tdb_sendout(struct pfsync_softc *sc)
|
||||
{
|
||||
#if NBPFILTER > 0
|
||||
struct ifnet *ifp = &sc->sc_if;
|
||||
#endif
|
||||
struct mbuf *m;
|
||||
|
||||
timeout_del(&sc->sc_tdb_tmo);
|
||||
|
||||
if (sc->sc_mbuf_tdb == NULL)
|
||||
return (0);
|
||||
m = sc->sc_mbuf_tdb;
|
||||
sc->sc_mbuf_tdb = NULL;
|
||||
sc->sc_statep_tdb.t = NULL;
|
||||
|
||||
#if NBPFILTER > 0
|
||||
if (ifp->if_bpf)
|
||||
bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
|
||||
#endif
|
||||
|
||||
return pfsync_sendout_mbuf(sc, m);
|
||||
}
|
||||
|
||||
int
|
||||
pfsync_sendout_mbuf(struct pfsync_softc *sc, struct mbuf *m)
|
||||
{
|
||||
struct sockaddr sa;
|
||||
struct ip *ip;
|
||||
|
||||
if (sc->sc_sync_ifp ||
|
||||
sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) {
|
||||
M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
|
||||
if (m == NULL) {
|
||||
pfsyncstats.pfsyncs_onomem++;
|
||||
@ -1409,3 +1576,154 @@ pfsync_sendout(sc)
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Update an in-kernel tdb. Silently fail if no tdb is found. */
|
||||
void
|
||||
pfsync_update_net_tdb(struct pfsync_tdb *pt)
|
||||
{
|
||||
struct tdb *tdb;
|
||||
int s;
|
||||
|
||||
/* check for invalid values */
|
||||
if (ntohl(pt->spi) <= SPI_RESERVED_MAX ||
|
||||
(pt->dst.sa.sa_family != AF_INET &&
|
||||
pt->dst.sa.sa_family != AF_INET6))
|
||||
goto bad;
|
||||
|
||||
s = spltdb();
|
||||
tdb = gettdb(pt->spi, &pt->dst, pt->sproto);
|
||||
if (tdb) {
|
||||
pt->rpl = ntohl(pt->rpl);
|
||||
pt->cur_bytes = betoh64(pt->cur_bytes);
|
||||
|
||||
/* Neither replay nor byte counter should ever decrease. */
|
||||
if (pt->rpl < tdb->tdb_rpl ||
|
||||
pt->cur_bytes < tdb->tdb_cur_bytes) {
|
||||
splx(s);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
tdb->tdb_rpl = pt->rpl;
|
||||
tdb->tdb_cur_bytes = pt->cur_bytes;
|
||||
}
|
||||
splx(s);
|
||||
return;
|
||||
|
||||
bad:
|
||||
if (pf_status.debug >= PF_DEBUG_MISC)
|
||||
printf("pfsync_insert: PFSYNC_ACT_TDB_UPD: "
|
||||
"invalid value\n");
|
||||
pfsyncstats.pfsyncs_badstate++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* One of our local tdbs have been updated, need to sync rpl with others */
|
||||
int
|
||||
pfsync_update_tdb(struct tdb *tdb, int output)
|
||||
{
|
||||
struct ifnet *ifp = NULL;
|
||||
struct pfsync_softc *sc = pfsyncif;
|
||||
struct pfsync_header *h;
|
||||
struct pfsync_tdb *pt = NULL;
|
||||
int s, i, ret;
|
||||
|
||||
if (sc == NULL)
|
||||
return (0);
|
||||
|
||||
ifp = &sc->sc_if;
|
||||
if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL &&
|
||||
sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
|
||||
/* Don't leave any stale pfsync packets hanging around. */
|
||||
if (sc->sc_mbuf_tdb != NULL) {
|
||||
m_freem(sc->sc_mbuf_tdb);
|
||||
sc->sc_mbuf_tdb = NULL;
|
||||
sc->sc_statep_tdb.t = NULL;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
s = splnet();
|
||||
if (sc->sc_mbuf_tdb == NULL) {
|
||||
if ((sc->sc_mbuf_tdb = pfsync_get_mbuf(sc, PFSYNC_ACT_TDB_UPD,
|
||||
(void *)&sc->sc_statep_tdb.t)) == NULL) {
|
||||
splx(s);
|
||||
return (ENOMEM);
|
||||
}
|
||||
h = mtod(sc->sc_mbuf_tdb, struct pfsync_header *);
|
||||
} else {
|
||||
h = mtod(sc->sc_mbuf_tdb, struct pfsync_header *);
|
||||
if (h->action != PFSYNC_ACT_TDB_UPD) {
|
||||
/*
|
||||
* XXX will never happen as long as there's
|
||||
* only one "TDB action".
|
||||
*/
|
||||
pfsync_tdb_sendout(sc);
|
||||
sc->sc_mbuf_tdb = pfsync_get_mbuf(sc,
|
||||
PFSYNC_ACT_TDB_UPD, (void *)&sc->sc_statep_tdb.t);
|
||||
if (sc->sc_mbuf_tdb == NULL) {
|
||||
splx(s);
|
||||
return (ENOMEM);
|
||||
}
|
||||
h = mtod(sc->sc_mbuf_tdb, struct pfsync_header *);
|
||||
} else if (sc->sc_maxupdates) {
|
||||
/*
|
||||
* If it's an update, look in the packet to see if
|
||||
* we already have an update for the state.
|
||||
*/
|
||||
struct pfsync_tdb *u =
|
||||
(void *)((char *)h + PFSYNC_HDRLEN);
|
||||
|
||||
for (i = 0; !pt && i < h->count; i++) {
|
||||
if (tdb->tdb_spi == u->spi &&
|
||||
tdb->tdb_sproto == u->sproto &&
|
||||
!bcmp(&tdb->tdb_dst, &u->dst,
|
||||
SA_LEN(&u->dst.sa))) {
|
||||
pt = u;
|
||||
pt->updates++;
|
||||
}
|
||||
u++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pt == NULL) {
|
||||
/* not a "duplicate" update */
|
||||
pt = sc->sc_statep_tdb.t++;
|
||||
sc->sc_mbuf_tdb->m_pkthdr.len =
|
||||
sc->sc_mbuf_tdb->m_len += sizeof(struct pfsync_tdb);
|
||||
h->count++;
|
||||
bzero(pt, sizeof(*pt));
|
||||
|
||||
pt->spi = tdb->tdb_spi;
|
||||
memcpy(&pt->dst, &tdb->tdb_dst, sizeof pt->dst);
|
||||
pt->sproto = tdb->tdb_sproto;
|
||||
}
|
||||
|
||||
/*
|
||||
* When a failover happens, the master's rpl is probably above
|
||||
* what we see here (we may be up to a second late), so
|
||||
* increase it a bit for outbound tdbs to manage most such
|
||||
* situations.
|
||||
*
|
||||
* For now, just add an offset that is likely to be larger
|
||||
* than the number of packets we can see in one second. The RFC
|
||||
* just says the next packet must have a higher seq value.
|
||||
*
|
||||
* XXX What is a good algorithm for this? We could use
|
||||
* a rate-determined increase, but to know it, we would have
|
||||
* to extend struct tdb.
|
||||
* XXX pt->rpl can wrap over MAXINT, but if so the real tdb
|
||||
* will soon be replaced anyway. For now, just don't handle
|
||||
* this edge case.
|
||||
*/
|
||||
#define RPL_INCR 16384
|
||||
pt->rpl = htonl(tdb->tdb_rpl + (output ? RPL_INCR : 0));
|
||||
pt->cur_bytes = htobe64(tdb->tdb_cur_bytes);
|
||||
|
||||
if (h->count == sc->sc_maxcount ||
|
||||
(sc->sc_maxupdates && (pt->updates >= sc->sc_maxupdates)))
|
||||
ret = pfsync_tdb_sendout(sc);
|
||||
|
||||
splx(s);
|
||||
return (ret);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: if_pfsync.h,v 1.19 2005/01/20 17:47:38 mcbride Exp $ */
|
||||
/* $OpenBSD: if_pfsync.h,v 1.30 2006/10/31 14:49:01 henning Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 Michael Shalayeff
|
||||
@ -35,6 +35,7 @@
|
||||
struct pfsync_state_scrub {
|
||||
u_int16_t pfss_flags;
|
||||
u_int8_t pfss_ttl; /* stashed TTL */
|
||||
#define PFSYNC_SCRUB_FLAG_VALID 0x01
|
||||
u_int8_t scrub_flag;
|
||||
u_int32_t pfss_ts_mod; /* timestamp modulation */
|
||||
} __packed;
|
||||
@ -54,8 +55,7 @@ struct pfsync_state_peer {
|
||||
u_int16_t mss; /* Maximum segment size option */
|
||||
u_int8_t state; /* active state level */
|
||||
u_int8_t wscale; /* window scaling factor */
|
||||
u_int8_t scrub_flag;
|
||||
u_int8_t pad[5];
|
||||
u_int8_t pad[6];
|
||||
} __packed;
|
||||
|
||||
struct pfsync_state {
|
||||
@ -72,8 +72,8 @@ struct pfsync_state {
|
||||
u_int32_t nat_rule;
|
||||
u_int32_t creation;
|
||||
u_int32_t expire;
|
||||
u_int32_t packets[2];
|
||||
u_int32_t bytes[2];
|
||||
u_int32_t packets[2][2];
|
||||
u_int32_t bytes[2][2];
|
||||
u_int32_t creatorid;
|
||||
sa_family_t af;
|
||||
u_int8_t proto;
|
||||
@ -88,6 +88,16 @@ struct pfsync_state {
|
||||
#define PFSYNC_FLAG_COMPRESS 0x01
|
||||
#define PFSYNC_FLAG_STALE 0x02
|
||||
|
||||
struct pfsync_tdb {
|
||||
u_int32_t spi;
|
||||
union sockaddr_union dst;
|
||||
u_int32_t rpl;
|
||||
u_int64_t cur_bytes;
|
||||
u_int8_t sproto;
|
||||
u_int8_t updates;
|
||||
u_int8_t pad[2];
|
||||
} __packed;
|
||||
|
||||
struct pfsync_state_upd {
|
||||
u_int32_t id[2];
|
||||
struct pfsync_state_peer src;
|
||||
@ -143,6 +153,10 @@ union sc_statep {
|
||||
struct pfsync_state_upd_req *r;
|
||||
};
|
||||
|
||||
union sc_tdb_statep {
|
||||
struct pfsync_tdb *t;
|
||||
};
|
||||
|
||||
extern int pfsync_sync_ok;
|
||||
|
||||
struct pfsync_softc {
|
||||
@ -151,26 +165,33 @@ struct pfsync_softc {
|
||||
|
||||
struct ip_moptions sc_imo;
|
||||
struct timeout sc_tmo;
|
||||
struct timeout sc_tdb_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 cumulative mbuf */
|
||||
struct mbuf *sc_mbuf_net; /* current cumulative mbuf */
|
||||
struct mbuf *sc_mbuf_tdb; /* dito for TDB updates */
|
||||
union sc_statep sc_statep;
|
||||
union sc_statep sc_statep_net;
|
||||
union sc_tdb_statep sc_statep_tdb;
|
||||
u_int32_t sc_ureq_received;
|
||||
u_int32_t sc_ureq_sent;
|
||||
struct pf_state *sc_bulk_send_next;
|
||||
struct pf_state *sc_bulk_terminator;
|
||||
int sc_bulk_tries;
|
||||
int sc_maxcount; /* number of states in mtu */
|
||||
int sc_maxupdates; /* number of updates/state */
|
||||
};
|
||||
|
||||
extern struct pfsync_softc *pfsyncif;
|
||||
#endif
|
||||
|
||||
|
||||
struct pfsync_header {
|
||||
u_int8_t version;
|
||||
#define PFSYNC_VERSION 2
|
||||
#define PFSYNC_VERSION 3
|
||||
u_int8_t af;
|
||||
u_int8_t action;
|
||||
#define PFSYNC_ACT_CLR 0 /* clear all states */
|
||||
@ -183,8 +204,10 @@ struct pfsync_header {
|
||||
#define PFSYNC_ACT_DEL_F 7 /* delete fragments */
|
||||
#define PFSYNC_ACT_UREQ 8 /* request "uncompressed" state */
|
||||
#define PFSYNC_ACT_BUS 9 /* Bulk Update Status */
|
||||
#define PFSYNC_ACT_MAX 10
|
||||
#define PFSYNC_ACT_TDB_UPD 10 /* TDB replay counter update */
|
||||
#define PFSYNC_ACT_MAX 11
|
||||
u_int8_t count;
|
||||
u_int8_t pf_chksum[PF_MD5_DIGEST_LENGTH];
|
||||
} __packed;
|
||||
|
||||
#define PFSYNC_BULKPACKETS 1 /* # of packets per timeout */
|
||||
@ -193,7 +216,7 @@ struct pfsync_header {
|
||||
#define PFSYNC_ACTIONS \
|
||||
"CLR ST", "INS ST", "UPD ST", "DEL ST", \
|
||||
"UPD ST COMP", "DEL ST COMP", "INS FR", "DEL FR", \
|
||||
"UPD REQ", "BLK UPD STAT"
|
||||
"UPD REQ", "BLK UPD STAT", "TDB UPD"
|
||||
|
||||
#define PFSYNC_DFLTTL 255
|
||||
|
||||
@ -236,6 +259,13 @@ struct pfsyncreq {
|
||||
(d)->mss = htons((s)->mss); \
|
||||
(d)->state = (s)->state; \
|
||||
(d)->wscale = (s)->wscale; \
|
||||
if ((s)->scrub) { \
|
||||
(d)->scrub.pfss_flags = \
|
||||
htons((s)->scrub->pfss_flags & PFSS_TIMESTAMP); \
|
||||
(d)->scrub.pfss_ttl = (s)->scrub->pfss_ttl; \
|
||||
(d)->scrub.pfss_ts_mod = htonl((s)->scrub->pfss_ts_mod);\
|
||||
(d)->scrub.scrub_flag = PFSYNC_SCRUB_FLAG_VALID; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define pf_state_peer_ntoh(s,d) do { \
|
||||
@ -246,6 +276,13 @@ struct pfsyncreq {
|
||||
(d)->mss = ntohs((s)->mss); \
|
||||
(d)->state = (s)->state; \
|
||||
(d)->wscale = (s)->wscale; \
|
||||
if ((s)->scrub.scrub_flag == PFSYNC_SCRUB_FLAG_VALID && \
|
||||
(d)->scrub != NULL) { \
|
||||
(d)->scrub->pfss_flags = \
|
||||
ntohs((s)->scrub.pfss_flags) & PFSS_TIMESTAMP; \
|
||||
(d)->scrub->pfss_ttl = (s)->scrub.pfss_ttl; \
|
||||
(d)->scrub->pfss_ts_mod = ntohl((s)->scrub.pfss_ts_mod);\
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define pf_state_host_hton(s,d) do { \
|
||||
@ -258,6 +295,17 @@ struct pfsyncreq {
|
||||
(d)->port = (s)->port; \
|
||||
} while (0)
|
||||
|
||||
#define pf_state_counter_hton(s,d) do { \
|
||||
d[0] = htonl((s>>32)&0xffffffff); \
|
||||
d[1] = htonl(s&0xffffffff); \
|
||||
} while (0)
|
||||
|
||||
#define pf_state_counter_ntoh(s,d) do { \
|
||||
d = ntohl(s[0]); \
|
||||
d = d<<32; \
|
||||
d += ntohl(s[1]); \
|
||||
} while (0)
|
||||
|
||||
#ifdef _KERNEL
|
||||
void pfsync_input(struct mbuf *, ...);
|
||||
int pfsync_clear_states(u_int32_t, char *);
|
||||
@ -267,7 +315,8 @@ int pfsync_pack_state(u_int8_t, struct pf_state *, int);
|
||||
(st->proto == IPPROTO_PFSYNC)) \
|
||||
st->sync_flags |= PFSTATE_NOSYNC; \
|
||||
else if (!st->sync_flags) \
|
||||
pfsync_pack_state(PFSYNC_ACT_INS, (st), 1); \
|
||||
pfsync_pack_state(PFSYNC_ACT_INS, (st), \
|
||||
PFSYNC_FLAG_COMPRESS); \
|
||||
st->sync_flags &= ~PFSTATE_FROMSYNC; \
|
||||
} while (0)
|
||||
#define pfsync_update_state(st) do { \
|
||||
@ -280,8 +329,8 @@ int pfsync_pack_state(u_int8_t, struct pf_state *, int);
|
||||
if (!st->sync_flags) \
|
||||
pfsync_pack_state(PFSYNC_ACT_DEL, (st), \
|
||||
PFSYNC_FLAG_COMPRESS); \
|
||||
st->sync_flags &= ~PFSTATE_FROMSYNC; \
|
||||
} while (0)
|
||||
int pfsync_update_tdb(struct tdb *, int);
|
||||
#endif
|
||||
|
||||
#endif /* _NET_IF_PFSYNC_H_ */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,8 @@
|
||||
/* $OpenBSD: pf_if.c,v 1.23 2004/12/22 17:17:55 dhartmei Exp $ */
|
||||
/* $OpenBSD: pf_if.c,v 1.46 2006/12/13 09:01:59 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 2005 Henning Brauer <henning@openbsd.org>
|
||||
* Copyright 2005 Ryan McBride <mcbride@openbsd.org>
|
||||
* Copyright (c) 2001 Daniel Hartmeier
|
||||
* Copyright (c) 2003 Cedric Berger
|
||||
* All rights reserved.
|
||||
@ -55,40 +57,25 @@
|
||||
#include <netinet/ip6.h>
|
||||
#endif /* INET6 */
|
||||
|
||||
#define ACCEPT_FLAGS(oklist) \
|
||||
do { \
|
||||
if ((flags & ~(oklist)) & \
|
||||
PFI_FLAG_ALLMASK) \
|
||||
return (EINVAL); \
|
||||
} while (0)
|
||||
|
||||
#define senderr(e) do { rv = (e); goto _bad; } while (0)
|
||||
|
||||
struct pfi_kif **pfi_index2kif;
|
||||
struct pfi_kif *pfi_self;
|
||||
int pfi_indexlim;
|
||||
struct pfi_ifhead pfi_ifs;
|
||||
struct pfi_kif *pfi_all = NULL;
|
||||
struct pfi_statehead pfi_statehead;
|
||||
int pfi_ifcnt;
|
||||
struct pool pfi_addr_pl;
|
||||
struct pfi_ifhead pfi_ifs;
|
||||
long pfi_update = 1;
|
||||
struct pfr_addr *pfi_buffer;
|
||||
int pfi_buffer_cnt;
|
||||
int pfi_buffer_max;
|
||||
|
||||
void pfi_dynaddr_update(void *);
|
||||
void pfi_kifaddr_update(void *);
|
||||
void pfi_kif_update(struct pfi_kif *);
|
||||
void pfi_dynaddr_update(struct pfi_dynaddr *dyn);
|
||||
void pfi_table_update(struct pfr_ktable *, struct pfi_kif *,
|
||||
int, int);
|
||||
void pfi_kifaddr_update(void *);
|
||||
void pfi_instance_add(struct ifnet *, int, int);
|
||||
void pfi_address_add(struct sockaddr *, int, int);
|
||||
int pfi_if_compare(struct pfi_kif *, struct pfi_kif *);
|
||||
struct pfi_kif *pfi_if_create(const char *, struct pfi_kif *, int);
|
||||
void pfi_copy_group(char *, const char *, int);
|
||||
void pfi_newgroup(const char *, int);
|
||||
int pfi_skip_if(const char *, struct pfi_kif *, int);
|
||||
int pfi_skip_if(const char *, struct pfi_kif *);
|
||||
int pfi_unmask(void *);
|
||||
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);
|
||||
@ -99,7 +86,7 @@ RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
|
||||
void
|
||||
pfi_initialize(void)
|
||||
{
|
||||
if (pfi_self != NULL) /* already initialized */
|
||||
if (pfi_all != NULL) /* already initialized */
|
||||
return;
|
||||
|
||||
TAILQ_INIT(&pfi_statehead);
|
||||
@ -108,173 +95,235 @@ pfi_initialize(void)
|
||||
pfi_buffer_max = 64;
|
||||
pfi_buffer = malloc(pfi_buffer_max * sizeof(*pfi_buffer),
|
||||
PFI_MTYPE, M_WAITOK);
|
||||
pfi_self = pfi_if_create("self", NULL, PFI_IFLAG_GROUP);
|
||||
|
||||
if ((pfi_all = pfi_kif_get(IFG_ALL)) == NULL)
|
||||
panic("pfi_kif_get for pfi_all failed");
|
||||
}
|
||||
|
||||
struct pfi_kif *
|
||||
pfi_kif_get(const char *kif_name)
|
||||
{
|
||||
struct pfi_kif *kif;
|
||||
struct pfi_kif_cmp s;
|
||||
|
||||
bzero(&s, sizeof(s));
|
||||
strlcpy(s.pfik_name, kif_name, sizeof(s.pfik_name));
|
||||
if ((kif = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&s)) != NULL)
|
||||
return (kif);
|
||||
|
||||
/* create new one */
|
||||
if ((kif = malloc(sizeof(*kif), PFI_MTYPE, M_DONTWAIT)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
bzero(kif, sizeof(*kif));
|
||||
strlcpy(kif->pfik_name, kif_name, sizeof(kif->pfik_name));
|
||||
kif->pfik_tzero = time_second;
|
||||
TAILQ_INIT(&kif->pfik_dynaddrs);
|
||||
|
||||
RB_INSERT(pfi_ifhead, &pfi_ifs, kif);
|
||||
return (kif);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_attach_clone(struct if_clone *ifc)
|
||||
pfi_kif_ref(struct pfi_kif *kif, enum pfi_kif_refs what)
|
||||
{
|
||||
pfi_initialize();
|
||||
pfi_newgroup(ifc->ifc_name, PFI_IFLAG_CLONABLE);
|
||||
switch (what) {
|
||||
case PFI_KIF_REF_RULE:
|
||||
kif->pfik_rules++;
|
||||
break;
|
||||
case PFI_KIF_REF_STATE:
|
||||
if (!kif->pfik_states++)
|
||||
TAILQ_INSERT_TAIL(&pfi_statehead, kif, pfik_w_states);
|
||||
break;
|
||||
default:
|
||||
panic("pfi_kif_ref with unknown type");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pfi_kif_unref(struct pfi_kif *kif, enum pfi_kif_refs what)
|
||||
{
|
||||
if (kif == NULL)
|
||||
return;
|
||||
|
||||
switch (what) {
|
||||
case PFI_KIF_REF_NONE:
|
||||
break;
|
||||
case PFI_KIF_REF_RULE:
|
||||
if (kif->pfik_rules <= 0) {
|
||||
printf("pfi_kif_unref: rules refcount <= 0\n");
|
||||
return;
|
||||
}
|
||||
kif->pfik_rules--;
|
||||
break;
|
||||
case PFI_KIF_REF_STATE:
|
||||
if (kif->pfik_states <= 0) {
|
||||
printf("pfi_kif_unref: state refcount <= 0\n");
|
||||
return;
|
||||
}
|
||||
if (!--kif->pfik_states)
|
||||
TAILQ_REMOVE(&pfi_statehead, kif, pfik_w_states);
|
||||
break;
|
||||
default:
|
||||
panic("pfi_kif_unref with unknown type");
|
||||
}
|
||||
|
||||
if (kif->pfik_ifp != NULL || kif->pfik_group != NULL || kif == pfi_all)
|
||||
return;
|
||||
|
||||
if (kif->pfik_rules || kif->pfik_states)
|
||||
return;
|
||||
|
||||
RB_REMOVE(pfi_ifhead, &pfi_ifs, kif);
|
||||
free(kif, PFI_MTYPE);
|
||||
}
|
||||
|
||||
int
|
||||
pfi_kif_match(struct pfi_kif *rule_kif, struct pfi_kif *packet_kif)
|
||||
{
|
||||
struct ifg_list *p;
|
||||
|
||||
if (rule_kif == NULL || rule_kif == packet_kif)
|
||||
return (1);
|
||||
|
||||
if (rule_kif->pfik_group != NULL)
|
||||
TAILQ_FOREACH(p, &packet_kif->pfik_ifp->if_groups, ifgl_next)
|
||||
if (p->ifgl_group == rule_kif->pfik_group)
|
||||
return (1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_attach_ifnet(struct ifnet *ifp)
|
||||
{
|
||||
struct pfi_kif *p, *q, key;
|
||||
int s;
|
||||
struct pfi_kif *kif;
|
||||
int s;
|
||||
|
||||
pfi_initialize();
|
||||
s = splsoftnet();
|
||||
pfi_update++;
|
||||
if (ifp->if_index >= pfi_indexlim) {
|
||||
/*
|
||||
* grow pfi_index2kif, similar to ifindex2ifnet code in if.c
|
||||
*/
|
||||
size_t m, n, oldlim;
|
||||
struct pfi_kif **mp, **np;
|
||||
if ((kif = pfi_kif_get(ifp->if_xname)) == NULL)
|
||||
panic("pfi_kif_get failed");
|
||||
|
||||
oldlim = pfi_indexlim;
|
||||
if (pfi_indexlim == 0)
|
||||
pfi_indexlim = 64;
|
||||
while (ifp->if_index >= pfi_indexlim)
|
||||
pfi_indexlim <<= 1;
|
||||
kif->pfik_ifp = ifp;
|
||||
ifp->if_pf_kif = (caddr_t)kif;
|
||||
|
||||
m = oldlim * sizeof(struct pfi_kif *);
|
||||
mp = pfi_index2kif;
|
||||
n = pfi_indexlim * sizeof(struct pfi_kif *);
|
||||
np = malloc(n, PFI_MTYPE, M_DONTWAIT);
|
||||
if (np == NULL)
|
||||
panic("pfi_attach_ifnet: "
|
||||
"cannot allocate translation table");
|
||||
bzero(np, n);
|
||||
if (mp != NULL)
|
||||
bcopy(mp, np, m);
|
||||
pfi_index2kif = np;
|
||||
if (mp != NULL)
|
||||
free(mp, PFI_MTYPE);
|
||||
}
|
||||
if ((kif->pfik_ah_cookie = hook_establish(ifp->if_addrhooks, 1,
|
||||
pfi_kifaddr_update, kif)) == NULL)
|
||||
panic("pfi_attach_ifnet: cannot allocate '%s' address hook",
|
||||
ifp->if_xname);
|
||||
|
||||
strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
|
||||
p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
|
||||
if (p == NULL) {
|
||||
/* add group */
|
||||
pfi_copy_group(key.pfik_name, ifp->if_xname,
|
||||
sizeof(key.pfik_name));
|
||||
q = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
|
||||
if (q == NULL)
|
||||
q = pfi_if_create(key.pfik_name, pfi_self, PFI_IFLAG_GROUP);
|
||||
if (q == NULL)
|
||||
panic("pfi_attach_ifnet: "
|
||||
"cannot allocate '%s' group", key.pfik_name);
|
||||
pfi_kif_update(kif);
|
||||
|
||||
/* add interface */
|
||||
p = pfi_if_create(ifp->if_xname, q, PFI_IFLAG_INSTANCE);
|
||||
if (p == NULL)
|
||||
panic("pfi_attach_ifnet: "
|
||||
"cannot allocate '%s' interface", ifp->if_xname);
|
||||
} else
|
||||
q = p->pfik_parent;
|
||||
p->pfik_ifp = ifp;
|
||||
p->pfik_flags |= PFI_IFLAG_ATTACHED;
|
||||
p->pfik_ah_cookie =
|
||||
hook_establish(ifp->if_addrhooks, 1, pfi_kifaddr_update, p);
|
||||
pfi_index2kif[ifp->if_index] = p;
|
||||
pfi_dohooks(p);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_detach_ifnet(struct ifnet *ifp)
|
||||
{
|
||||
struct pfi_kif *p, *q, key;
|
||||
int s;
|
||||
int s;
|
||||
struct pfi_kif *kif;
|
||||
|
||||
strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
|
||||
if ((kif = (struct pfi_kif *)ifp->if_pf_kif) == NULL)
|
||||
return;
|
||||
|
||||
s = splsoftnet();
|
||||
pfi_update++;
|
||||
p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
|
||||
if (p == NULL) {
|
||||
printf("pfi_detach_ifnet: cannot find %s", ifp->if_xname);
|
||||
splx(s);
|
||||
return;
|
||||
}
|
||||
hook_disestablish(p->pfik_ifp->if_addrhooks, p->pfik_ah_cookie);
|
||||
q = p->pfik_parent;
|
||||
p->pfik_ifp = NULL;
|
||||
p->pfik_flags &= ~PFI_IFLAG_ATTACHED;
|
||||
pfi_index2kif[ifp->if_index] = NULL;
|
||||
pfi_dohooks(p);
|
||||
pfi_maybe_destroy(p);
|
||||
hook_disestablish(ifp->if_addrhooks, kif->pfik_ah_cookie);
|
||||
pfi_kif_update(kif);
|
||||
|
||||
kif->pfik_ifp = NULL;
|
||||
ifp->if_pf_kif = NULL;
|
||||
pfi_kif_unref(kif, PFI_KIF_REF_NONE);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
struct pfi_kif *
|
||||
pfi_lookup_create(const char *name)
|
||||
void
|
||||
pfi_attach_ifgroup(struct ifg_group *ifg)
|
||||
{
|
||||
struct pfi_kif *p, *q, key;
|
||||
struct pfi_kif *kif;
|
||||
int s;
|
||||
|
||||
pfi_initialize();
|
||||
s = splsoftnet();
|
||||
p = pfi_lookup_if(name);
|
||||
if (p == NULL) {
|
||||
pfi_copy_group(key.pfik_name, name, sizeof(key.pfik_name));
|
||||
q = pfi_lookup_if(key.pfik_name);
|
||||
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);
|
||||
}
|
||||
pfi_update++;
|
||||
if ((kif = pfi_kif_get(ifg->ifg_group)) == NULL)
|
||||
panic("pfi_kif_get failed");
|
||||
|
||||
kif->pfik_group = ifg;
|
||||
ifg->ifg_pf_kif = (caddr_t)kif;
|
||||
|
||||
splx(s);
|
||||
return (p);
|
||||
}
|
||||
|
||||
struct pfi_kif *
|
||||
pfi_attach_rule(const char *name)
|
||||
{
|
||||
struct pfi_kif *p;
|
||||
|
||||
p = pfi_lookup_create(name);
|
||||
if (p != NULL)
|
||||
p->pfik_rules++;
|
||||
return (p);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_detach_rule(struct pfi_kif *p)
|
||||
pfi_detach_ifgroup(struct ifg_group *ifg)
|
||||
{
|
||||
if (p == NULL)
|
||||
int s;
|
||||
struct pfi_kif *kif;
|
||||
|
||||
if ((kif = (struct pfi_kif *)ifg->ifg_pf_kif) == NULL)
|
||||
return;
|
||||
if (p->pfik_rules > 0)
|
||||
p->pfik_rules--;
|
||||
else
|
||||
printf("pfi_detach_rule: reference count at 0\n");
|
||||
pfi_maybe_destroy(p);
|
||||
|
||||
s = splsoftnet();
|
||||
pfi_update++;
|
||||
|
||||
kif->pfik_group = NULL;
|
||||
ifg->ifg_pf_kif = NULL;
|
||||
pfi_kif_unref(kif, PFI_KIF_REF_NONE);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_attach_state(struct pfi_kif *p)
|
||||
pfi_group_change(const char *group)
|
||||
{
|
||||
if (!p->pfik_states++)
|
||||
TAILQ_INSERT_TAIL(&pfi_statehead, p, pfik_w_states);
|
||||
struct pfi_kif *kif;
|
||||
int s;
|
||||
|
||||
s = splsoftnet();
|
||||
pfi_update++;
|
||||
if ((kif = pfi_kif_get(group)) == NULL)
|
||||
panic("pfi_kif_get failed");
|
||||
|
||||
pfi_kif_update(kif);
|
||||
|
||||
splx(s);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_detach_state(struct pfi_kif *p)
|
||||
int
|
||||
pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
|
||||
{
|
||||
if (p == NULL)
|
||||
return;
|
||||
if (p->pfik_states <= 0) {
|
||||
printf("pfi_detach_state: reference count <= 0\n");
|
||||
return;
|
||||
switch (af) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
switch (dyn->pfid_acnt4) {
|
||||
case 0:
|
||||
return (0);
|
||||
case 1:
|
||||
return (PF_MATCHA(0, &dyn->pfid_addr4,
|
||||
&dyn->pfid_mask4, a, AF_INET));
|
||||
default:
|
||||
return (pfr_match_addr(dyn->pfid_kt, a, AF_INET));
|
||||
}
|
||||
break;
|
||||
#endif /* INET */
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
switch (dyn->pfid_acnt6) {
|
||||
case 0:
|
||||
return (0);
|
||||
case 1:
|
||||
return (PF_MATCHA(0, &dyn->pfid_addr6,
|
||||
&dyn->pfid_mask6, a, AF_INET6));
|
||||
default:
|
||||
return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6));
|
||||
}
|
||||
break;
|
||||
#endif /* INET6 */
|
||||
default:
|
||||
return (0);
|
||||
}
|
||||
if (!--p->pfik_states)
|
||||
TAILQ_REMOVE(&pfi_statehead, p, pfik_w_states);
|
||||
pfi_maybe_destroy(p);
|
||||
}
|
||||
|
||||
int
|
||||
@ -287,15 +336,20 @@ pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af)
|
||||
|
||||
if (aw->type != PF_ADDR_DYNIFTL)
|
||||
return (0);
|
||||
dyn = pool_get(&pfi_addr_pl, PR_NOWAIT);
|
||||
if (dyn == NULL)
|
||||
if ((dyn = pool_get(&pfi_addr_pl, PR_NOWAIT)) == NULL)
|
||||
return (1);
|
||||
bzero(dyn, sizeof(*dyn));
|
||||
|
||||
s = splsoftnet();
|
||||
dyn->pfid_kif = pfi_attach_rule(aw->v.ifname);
|
||||
if (dyn->pfid_kif == NULL)
|
||||
senderr(1);
|
||||
if (!strcmp(aw->v.ifname, "self"))
|
||||
dyn->pfid_kif = pfi_kif_get(IFG_ALL);
|
||||
else
|
||||
dyn->pfid_kif = pfi_kif_get(aw->v.ifname);
|
||||
if (dyn->pfid_kif == NULL) {
|
||||
rv = 1;
|
||||
goto _bad;
|
||||
}
|
||||
pfi_kif_ref(dyn->pfid_kif, PFI_KIF_REF_RULE);
|
||||
|
||||
dyn->pfid_net = pfi_unmask(&aw->v.a.mask);
|
||||
if (af == AF_INET && dyn->pfid_net == 32)
|
||||
@ -312,24 +366,23 @@ 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(PF_RESERVED_ANCHOR);
|
||||
if (ruleset == NULL)
|
||||
senderr(1);
|
||||
if ((ruleset = pf_find_or_create_ruleset(PF_RESERVED_ANCHOR)) == NULL) {
|
||||
rv = 1;
|
||||
goto _bad;
|
||||
}
|
||||
|
||||
dyn->pfid_kt = pfr_attach_table(ruleset, tblname);
|
||||
if (dyn->pfid_kt == NULL)
|
||||
senderr(1);
|
||||
if ((dyn->pfid_kt = pfr_attach_table(ruleset, tblname)) == NULL) {
|
||||
rv = 1;
|
||||
goto _bad;
|
||||
}
|
||||
|
||||
dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE;
|
||||
dyn->pfid_iflags = aw->iflags;
|
||||
dyn->pfid_af = af;
|
||||
dyn->pfid_hook_cookie = hook_establish(dyn->pfid_kif->pfik_ah_head, 1,
|
||||
pfi_dynaddr_update, dyn);
|
||||
if (dyn->pfid_hook_cookie == NULL)
|
||||
senderr(1);
|
||||
|
||||
TAILQ_INSERT_TAIL(&dyn->pfid_kif->pfik_dynaddrs, dyn, entry);
|
||||
aw->p.dyn = dyn;
|
||||
pfi_dynaddr_update(aw->p.dyn);
|
||||
pfi_kif_update(dyn->pfid_kif);
|
||||
splx(s);
|
||||
return (0);
|
||||
|
||||
@ -339,16 +392,32 @@ _bad:
|
||||
if (ruleset != NULL)
|
||||
pf_remove_if_empty_ruleset(ruleset);
|
||||
if (dyn->pfid_kif != NULL)
|
||||
pfi_detach_rule(dyn->pfid_kif);
|
||||
pfi_kif_unref(dyn->pfid_kif, PFI_KIF_REF_RULE);
|
||||
pool_put(&pfi_addr_pl, dyn);
|
||||
splx(s);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_dynaddr_update(void *p)
|
||||
pfi_kif_update(struct pfi_kif *kif)
|
||||
{
|
||||
struct ifg_list *ifgl;
|
||||
struct pfi_dynaddr *p;
|
||||
|
||||
/* update all dynaddr */
|
||||
TAILQ_FOREACH(p, &kif->pfik_dynaddrs, entry)
|
||||
pfi_dynaddr_update(p);
|
||||
|
||||
/* again for all groups kif is member of */
|
||||
if (kif->pfik_ifp != NULL)
|
||||
TAILQ_FOREACH(ifgl, &kif->pfik_ifp->if_groups, ifgl_next)
|
||||
pfi_kif_update((struct pfi_kif *)
|
||||
ifgl->ifgl_group->ifg_pf_kif);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_dynaddr_update(struct pfi_dynaddr *dyn)
|
||||
{
|
||||
struct pfi_dynaddr *dyn = (struct pfi_dynaddr *)p;
|
||||
struct pfi_kif *kif;
|
||||
struct pfr_ktable *kt;
|
||||
|
||||
@ -357,6 +426,7 @@ pfi_dynaddr_update(void *p)
|
||||
|
||||
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);
|
||||
@ -369,28 +439,18 @@ void
|
||||
pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags)
|
||||
{
|
||||
int e, size2 = 0;
|
||||
struct pfi_kif *p;
|
||||
struct pfr_table t;
|
||||
struct ifg_member *ifgm;
|
||||
|
||||
if ((kif->pfik_flags & PFI_IFLAG_INSTANCE) && kif->pfik_ifp == NULL) {
|
||||
pfr_clr_addrs(&kt->pfrkt_t, NULL, 0);
|
||||
return;
|
||||
}
|
||||
pfi_buffer_cnt = 0;
|
||||
if ((kif->pfik_flags & PFI_IFLAG_INSTANCE))
|
||||
|
||||
if (kif->pfik_ifp != NULL)
|
||||
pfi_instance_add(kif->pfik_ifp, net, flags);
|
||||
else if (strcmp(kif->pfik_name, "self")) {
|
||||
TAILQ_FOREACH(p, &kif->pfik_grouphead, pfik_instances)
|
||||
pfi_instance_add(p->pfik_ifp, net, flags);
|
||||
} else {
|
||||
RB_FOREACH(p, pfi_ifhead, &pfi_ifs)
|
||||
if (p->pfik_flags & PFI_IFLAG_INSTANCE)
|
||||
pfi_instance_add(p->pfik_ifp, net, flags);
|
||||
}
|
||||
t = kt->pfrkt_t;
|
||||
t.pfrt_flags = 0;
|
||||
if ((e = pfr_set_addrs(&t, pfi_buffer, pfi_buffer_cnt, &size2,
|
||||
NULL, NULL, NULL, 0)))
|
||||
else if (kif->pfik_group != NULL)
|
||||
TAILQ_FOREACH(ifgm, &kif->pfik_group->ifg_members, ifgm_next)
|
||||
pfi_instance_add(ifgm->ifgm_ifp, net, flags);
|
||||
|
||||
if ((e = pfr_set_addrs(&kt->pfrkt_t, pfi_buffer, pfi_buffer_cnt, &size2,
|
||||
NULL, NULL, NULL, 0, PFR_TFLAG_ALLMASK)))
|
||||
printf("pfi_table_update: cannot set %d new addresses "
|
||||
"into table %s: %d\n", pfi_buffer_cnt, kt->pfrkt_name, e);
|
||||
}
|
||||
@ -434,13 +494,12 @@ pfi_instance_add(struct ifnet *ifp, int net, int flags)
|
||||
got6 = 1;
|
||||
net2 = net;
|
||||
if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) {
|
||||
if (af == AF_INET) {
|
||||
if (af == AF_INET)
|
||||
net2 = pfi_unmask(&((struct sockaddr_in *)
|
||||
ia->ifa_netmask)->sin_addr);
|
||||
} else if (af == AF_INET6) {
|
||||
else if (af == AF_INET6)
|
||||
net2 = pfi_unmask(&((struct sockaddr_in6 *)
|
||||
ia->ifa_netmask)->sin6_addr);
|
||||
}
|
||||
}
|
||||
if (af == AF_INET && net2 > 32)
|
||||
net2 = 32;
|
||||
@ -488,9 +547,9 @@ pfi_address_add(struct sockaddr *sa, int af, int net)
|
||||
p->pfra_net = net;
|
||||
if (af == AF_INET)
|
||||
p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr;
|
||||
if (af == AF_INET6) {
|
||||
else if (af == AF_INET6) {
|
||||
p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr;
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&p->pfra_ip6addr))
|
||||
if (IN6_IS_SCOPE_EMBED(&p->pfra_ip6addr))
|
||||
p->pfra_ip6addr.s6_addr16[1] = 0;
|
||||
}
|
||||
/* mask network address bits */
|
||||
@ -510,9 +569,8 @@ pfi_dynaddr_remove(struct pf_addr_wrap *aw)
|
||||
return;
|
||||
|
||||
s = splsoftnet();
|
||||
hook_disestablish(aw->p.dyn->pfid_kif->pfik_ah_head,
|
||||
aw->p.dyn->pfid_hook_cookie);
|
||||
pfi_detach_rule(aw->p.dyn->pfid_kif);
|
||||
TAILQ_REMOVE(&aw->p.dyn->pfid_kif->pfik_dynaddrs, aw->p.dyn, entry);
|
||||
pfi_kif_unref(aw->p.dyn->pfid_kif, PFI_KIF_REF_RULE);
|
||||
aw->p.dyn->pfid_kif = NULL;
|
||||
pfr_detach_table(aw->p.dyn->pfid_kt);
|
||||
aw->p.dyn->pfid_kt = NULL;
|
||||
@ -533,11 +591,12 @@ pfi_dynaddr_copyout(struct pf_addr_wrap *aw)
|
||||
void
|
||||
pfi_kifaddr_update(void *v)
|
||||
{
|
||||
int s;
|
||||
int s;
|
||||
struct pfi_kif *kif = (struct pfi_kif *)v;
|
||||
|
||||
s = splsoftnet();
|
||||
pfi_update++;
|
||||
pfi_dohooks(v);
|
||||
pfi_kif_update(kif);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
@ -547,107 +606,16 @@ pfi_if_compare(struct pfi_kif *p, struct pfi_kif *q)
|
||||
return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ));
|
||||
}
|
||||
|
||||
struct pfi_kif *
|
||||
pfi_if_create(const char *name, struct pfi_kif *q, int flags)
|
||||
{
|
||||
struct pfi_kif *p;
|
||||
|
||||
p = malloc(sizeof(*p), PFI_MTYPE, M_DONTWAIT);
|
||||
if (p == NULL)
|
||||
return (NULL);
|
||||
bzero(p, sizeof(*p));
|
||||
p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE,
|
||||
M_DONTWAIT);
|
||||
if (p->pfik_ah_head == NULL) {
|
||||
free(p, PFI_MTYPE);
|
||||
return (NULL);
|
||||
}
|
||||
bzero(p->pfik_ah_head, sizeof(*p->pfik_ah_head));
|
||||
TAILQ_INIT(p->pfik_ah_head);
|
||||
TAILQ_INIT(&p->pfik_grouphead);
|
||||
strlcpy(p->pfik_name, name, sizeof(p->pfik_name));
|
||||
RB_INIT(&p->pfik_lan_ext);
|
||||
RB_INIT(&p->pfik_ext_gwy);
|
||||
p->pfik_flags = flags;
|
||||
p->pfik_parent = q;
|
||||
p->pfik_tzero = time_second;
|
||||
|
||||
RB_INSERT(pfi_ifhead, &pfi_ifs, p);
|
||||
if (q != NULL) {
|
||||
q->pfik_addcnt++;
|
||||
TAILQ_INSERT_TAIL(&q->pfik_grouphead, p, pfik_instances);
|
||||
}
|
||||
pfi_ifcnt++;
|
||||
return (p);
|
||||
}
|
||||
|
||||
int
|
||||
pfi_maybe_destroy(struct pfi_kif *p)
|
||||
{
|
||||
int i, j, k, s;
|
||||
struct pfi_kif *q = p->pfik_parent;
|
||||
|
||||
if ((p->pfik_flags & (PFI_IFLAG_ATTACHED | PFI_IFLAG_GROUP)) ||
|
||||
p->pfik_rules > 0 || p->pfik_states > 0)
|
||||
return (0);
|
||||
|
||||
s = splsoftnet();
|
||||
if (q != NULL) {
|
||||
for (i = 0; i < 2; i++)
|
||||
for (j = 0; j < 2; j++)
|
||||
for (k = 0; k < 2; k++) {
|
||||
q->pfik_bytes[i][j][k] +=
|
||||
p->pfik_bytes[i][j][k];
|
||||
q->pfik_packets[i][j][k] +=
|
||||
p->pfik_packets[i][j][k];
|
||||
}
|
||||
q->pfik_delcnt++;
|
||||
TAILQ_REMOVE(&q->pfik_grouphead, p, pfik_instances);
|
||||
}
|
||||
pfi_ifcnt--;
|
||||
RB_REMOVE(pfi_ifhead, &pfi_ifs, p);
|
||||
splx(s);
|
||||
|
||||
free(p->pfik_ah_head, PFI_MTYPE);
|
||||
free(p, PFI_MTYPE);
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_copy_group(char *p, const char *q, int m)
|
||||
{
|
||||
while (m > 1 && *q && !(*q >= '0' && *q <= '9')) {
|
||||
*p++ = *q++;
|
||||
m--;
|
||||
}
|
||||
if (m > 0)
|
||||
*p++ = '\0';
|
||||
}
|
||||
|
||||
void
|
||||
pfi_newgroup(const char *name, int flags)
|
||||
{
|
||||
struct pfi_kif *p;
|
||||
|
||||
p = pfi_lookup_if(name);
|
||||
if (p == NULL)
|
||||
p = pfi_if_create(name, pfi_self, PFI_IFLAG_GROUP);
|
||||
if (p == NULL) {
|
||||
printf("pfi_newgroup: cannot allocate '%s' group", name);
|
||||
return;
|
||||
}
|
||||
p->pfik_flags |= flags;
|
||||
}
|
||||
|
||||
void
|
||||
pfi_fill_oldstatus(struct pf_status *pfs)
|
||||
{
|
||||
struct pfi_kif *p, key;
|
||||
int i, j, k, s;
|
||||
struct pfi_kif *p;
|
||||
struct pfi_kif_cmp key;
|
||||
int i, j, k, s;
|
||||
|
||||
strlcpy(key.pfik_name, pfs->ifname, sizeof(key.pfik_name));
|
||||
s = splsoftnet();
|
||||
p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
|
||||
p = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&key);
|
||||
if (p == NULL) {
|
||||
splx(s);
|
||||
return;
|
||||
@ -666,40 +634,81 @@ pfi_fill_oldstatus(struct pf_status *pfs)
|
||||
}
|
||||
|
||||
int
|
||||
pfi_clr_istats(const char *name, int *nzero, int flags)
|
||||
pfi_clr_istats(const char *name)
|
||||
{
|
||||
struct pfi_kif *p;
|
||||
int n = 0, s;
|
||||
long tzero = time_second;
|
||||
int s;
|
||||
|
||||
ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE);
|
||||
s = splsoftnet();
|
||||
RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
|
||||
if (pfi_skip_if(name, p, flags))
|
||||
if (pfi_skip_if(name, p))
|
||||
continue;
|
||||
bzero(p->pfik_packets, sizeof(p->pfik_packets));
|
||||
bzero(p->pfik_bytes, sizeof(p->pfik_bytes));
|
||||
p->pfik_tzero = tzero;
|
||||
n++;
|
||||
p->pfik_tzero = time_second;
|
||||
}
|
||||
splx(s);
|
||||
if (nzero != NULL)
|
||||
*nzero = n;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size)
|
||||
{
|
||||
struct pfi_kif *p, *nextp;
|
||||
int s, n = 0;
|
||||
|
||||
s = splsoftnet();
|
||||
for (p = RB_MIN(pfi_ifhead, &pfi_ifs); p; p = nextp) {
|
||||
nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p);
|
||||
if (pfi_skip_if(name, p))
|
||||
continue;
|
||||
if (*size > n++) {
|
||||
if (!p->pfik_tzero)
|
||||
p->pfik_tzero = time_second;
|
||||
pfi_kif_ref(p, PFI_KIF_REF_RULE);
|
||||
if (copyout(p, buf++, sizeof(*buf))) {
|
||||
pfi_kif_unref(p, PFI_KIF_REF_RULE);
|
||||
splx(s);
|
||||
return (EFAULT);
|
||||
}
|
||||
nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p);
|
||||
pfi_kif_unref(p, PFI_KIF_REF_RULE);
|
||||
}
|
||||
}
|
||||
splx(s);
|
||||
*size = n;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfi_skip_if(const char *filter, struct pfi_kif *p)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (filter == NULL || !*filter)
|
||||
return (0);
|
||||
if (!strcmp(p->pfik_name, filter))
|
||||
return (0); /* exact match */
|
||||
n = strlen(filter);
|
||||
if (n < 1 || n >= IFNAMSIZ)
|
||||
return (1); /* sanity check */
|
||||
if (filter[n-1] >= '0' && filter[n-1] <= '9')
|
||||
return (1); /* only do exact match in that case */
|
||||
if (strncmp(p->pfik_name, filter, n))
|
||||
return (1); /* prefix doesn't match */
|
||||
return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9');
|
||||
}
|
||||
|
||||
int
|
||||
pfi_set_flags(const char *name, int flags)
|
||||
{
|
||||
struct pfi_kif *p;
|
||||
int s;
|
||||
|
||||
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))
|
||||
if (pfi_skip_if(name, p))
|
||||
continue;
|
||||
p->pfik_flags |= flags;
|
||||
}
|
||||
@ -713,12 +722,9 @@ 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))
|
||||
if (pfi_skip_if(name, p))
|
||||
continue;
|
||||
p->pfik_flags &= ~flags;
|
||||
}
|
||||
@ -726,64 +732,6 @@ pfi_clear_flags(const char *name, int flags)
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfi_get_ifaces(const char *name, struct pfi_if *buf, int *size, int flags)
|
||||
{
|
||||
struct pfi_kif *p;
|
||||
int s, n = 0;
|
||||
|
||||
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;
|
||||
if (*size > n++) {
|
||||
if (!p->pfik_tzero)
|
||||
p->pfik_tzero = time_second;
|
||||
if (copyout(p, buf++, sizeof(*buf))) {
|
||||
splx(s);
|
||||
return (EFAULT);
|
||||
}
|
||||
}
|
||||
}
|
||||
splx(s);
|
||||
*size = n;
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct pfi_kif *
|
||||
pfi_lookup_if(const char *name)
|
||||
{
|
||||
struct pfi_kif *p, key;
|
||||
|
||||
strlcpy(key.pfik_name, name, sizeof(key.pfik_name));
|
||||
p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
|
||||
return (p);
|
||||
}
|
||||
|
||||
int
|
||||
pfi_skip_if(const char *filter, struct pfi_kif *p, int f)
|
||||
{
|
||||
int n;
|
||||
|
||||
if ((p->pfik_flags & PFI_IFLAG_GROUP) && !(f & PFI_FLAG_GROUP))
|
||||
return (1);
|
||||
if ((p->pfik_flags & PFI_IFLAG_INSTANCE) && !(f & PFI_FLAG_INSTANCE))
|
||||
return (1);
|
||||
if (filter == NULL || !*filter)
|
||||
return (0);
|
||||
if (!strcmp(p->pfik_name, filter))
|
||||
return (0); /* exact match */
|
||||
n = strlen(filter);
|
||||
if (n < 1 || n >= IFNAMSIZ)
|
||||
return (1); /* sanity check */
|
||||
if (filter[n-1] >= '0' && filter[n-1] <= '9')
|
||||
return (1); /* only do exact match in that case */
|
||||
if (strncmp(p->pfik_name, filter, n))
|
||||
return (1); /* prefix doesn't match */
|
||||
return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9');
|
||||
}
|
||||
|
||||
/* from pf_print_state.c */
|
||||
int
|
||||
pfi_unmask(void *addr)
|
||||
@ -804,44 +752,3 @@ pfi_unmask(void *addr)
|
||||
return (b);
|
||||
}
|
||||
|
||||
void
|
||||
pfi_dohooks(struct pfi_kif *p)
|
||||
{
|
||||
for (; p != NULL; p = p->pfik_parent)
|
||||
dohooks(p->pfik_ah_head, 0);
|
||||
}
|
||||
|
||||
int
|
||||
pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
|
||||
{
|
||||
switch (af) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
switch (dyn->pfid_acnt4) {
|
||||
case 0:
|
||||
return (0);
|
||||
case 1:
|
||||
return (PF_MATCHA(0, &dyn->pfid_addr4,
|
||||
&dyn->pfid_mask4, a, AF_INET));
|
||||
default:
|
||||
return (pfr_match_addr(dyn->pfid_kt, a, AF_INET));
|
||||
}
|
||||
break;
|
||||
#endif /* INET */
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
switch (dyn->pfid_acnt6) {
|
||||
case 0:
|
||||
return (0);
|
||||
case 1:
|
||||
return (PF_MATCHA(0, &dyn->pfid_addr6,
|
||||
&dyn->pfid_mask6, a, AF_INET6));
|
||||
default:
|
||||
return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6));
|
||||
}
|
||||
break;
|
||||
#endif /* INET6 */
|
||||
default:
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: pf_norm.c,v 1.97 2004/09/21 16:59:12 aaron Exp $ */
|
||||
/* $OpenBSD: pf_norm.c,v 1.107 2006/04/16 00:59:52 pascoe Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 2001 Niels Provos <provos@citi.umich.edu>
|
||||
@ -412,7 +412,7 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag,
|
||||
break;
|
||||
}
|
||||
|
||||
/* This fragment is completely overlapped, loose it */
|
||||
/* This fragment is completely overlapped, lose it */
|
||||
next = LIST_NEXT(frea, fr_next);
|
||||
m_freem(frea->fr_m);
|
||||
LIST_REMOVE(frea, fr_next);
|
||||
@ -704,7 +704,7 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff,
|
||||
} else {
|
||||
hosed++;
|
||||
}
|
||||
} else {
|
||||
} else if (frp == NULL) {
|
||||
/* There is a gap between fragments */
|
||||
DPFPRINTF(("fragcache[%d]: gap %d %d-%d (%d-%d)\n",
|
||||
h->ip_id, -aftercut, off, max, fra->fr_off,
|
||||
@ -831,8 +831,7 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
|
||||
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr);
|
||||
while (r != NULL) {
|
||||
r->evaluations++;
|
||||
if (r->kif != NULL &&
|
||||
(r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
|
||||
if (pfi_kif_match(r->kif, kif) == r->ifnot)
|
||||
r = r->skip[PF_SKIP_IFP].ptr;
|
||||
else if (r->direction && r->direction != dir)
|
||||
r = r->skip[PF_SKIP_DIR].ptr;
|
||||
@ -841,19 +840,23 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
|
||||
else if (r->proto && r->proto != h->ip_p)
|
||||
r = r->skip[PF_SKIP_PROTO].ptr;
|
||||
else if (PF_MISMATCHAW(&r->src.addr,
|
||||
(struct pf_addr *)&h->ip_src.s_addr, AF_INET, r->src.neg))
|
||||
(struct pf_addr *)&h->ip_src.s_addr, AF_INET,
|
||||
r->src.neg, kif))
|
||||
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
|
||||
else if (PF_MISMATCHAW(&r->dst.addr,
|
||||
(struct pf_addr *)&h->ip_dst.s_addr, AF_INET, r->dst.neg))
|
||||
(struct pf_addr *)&h->ip_dst.s_addr, AF_INET,
|
||||
r->dst.neg, NULL))
|
||||
r = r->skip[PF_SKIP_DST_ADDR].ptr;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (r == NULL)
|
||||
if (r == NULL || r->action == PF_NOSCRUB)
|
||||
return (PF_PASS);
|
||||
else
|
||||
r->packets++;
|
||||
else {
|
||||
r->packets[dir == PF_OUT]++;
|
||||
r->bytes[dir == PF_OUT] += pd->tot_len;
|
||||
}
|
||||
|
||||
/* Check for illegal packets */
|
||||
if (hlen < (int)sizeof(struct ip))
|
||||
@ -863,8 +866,12 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
|
||||
goto drop;
|
||||
|
||||
/* Clear IP_DF if the rule uses the no-df option */
|
||||
if (r->rule_flag & PFRULE_NODF)
|
||||
if (r->rule_flag & PFRULE_NODF && h->ip_off & htons(IP_DF)) {
|
||||
u_int16_t ip_off = h->ip_off;
|
||||
|
||||
h->ip_off &= htons(~IP_DF);
|
||||
h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_off, h->ip_off, 0);
|
||||
}
|
||||
|
||||
/* We will need other tests here */
|
||||
if (!fragoff && !mff)
|
||||
@ -922,6 +929,18 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
|
||||
if (m == NULL)
|
||||
return (PF_DROP);
|
||||
|
||||
/* use mtag from concatenated mbuf chain */
|
||||
pd->pf_mtag = pf_find_mtag(m);
|
||||
#ifdef DIAGNOSTIC
|
||||
if (pd->pf_mtag == NULL) {
|
||||
printf("%s: pf_find_mtag returned NULL(1)\n", __func__);
|
||||
if ((pd->pf_mtag = pf_get_mtag(m)) == NULL) {
|
||||
m_freem(m);
|
||||
*m0 = NULL;
|
||||
goto no_mem;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (frag != NULL && (frag->fr_flags & PFFRAG_DROP))
|
||||
goto drop;
|
||||
|
||||
@ -930,15 +949,13 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
|
||||
/* non-buffering fragment cache (drops or masks overlaps) */
|
||||
int nomem = 0;
|
||||
|
||||
if (dir == PF_OUT) {
|
||||
if (m_tag_find(m, PACKET_TAG_PF_FRAGCACHE, NULL) !=
|
||||
NULL) {
|
||||
/* Already passed the fragment cache in the
|
||||
* input direction. If we continued, it would
|
||||
* appear to be a dup and would be dropped.
|
||||
*/
|
||||
goto fragment_pass;
|
||||
}
|
||||
if (dir == PF_OUT && pd->pf_mtag->flags & PF_TAG_FRAGCACHE) {
|
||||
/*
|
||||
* Already passed the fragment cache in the
|
||||
* input direction. If we continued, it would
|
||||
* appear to be a dup and would be dropped.
|
||||
*/
|
||||
goto fragment_pass;
|
||||
}
|
||||
|
||||
frag = pf_find_fragment(h, &pf_cache_tree);
|
||||
@ -959,14 +976,21 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
|
||||
goto drop;
|
||||
}
|
||||
|
||||
if (dir == PF_IN) {
|
||||
struct m_tag *mtag;
|
||||
|
||||
mtag = m_tag_get(PACKET_TAG_PF_FRAGCACHE, 0, M_NOWAIT);
|
||||
if (mtag == NULL)
|
||||
/* use mtag from copied and trimmed mbuf chain */
|
||||
pd->pf_mtag = pf_find_mtag(m);
|
||||
#ifdef DIAGNOSTIC
|
||||
if (pd->pf_mtag == NULL) {
|
||||
printf("%s: pf_find_mtag returned NULL(2)\n", __func__);
|
||||
if ((pd->pf_mtag = pf_get_mtag(m)) == NULL) {
|
||||
m_freem(m);
|
||||
*m0 = NULL;
|
||||
goto no_mem;
|
||||
m_tag_prepend(m, mtag);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (dir == PF_IN)
|
||||
pd->pf_mtag->flags |= PF_TAG_FRAGCACHE;
|
||||
|
||||
if (frag != NULL && (frag->fr_flags & PFFRAG_DROP))
|
||||
goto drop;
|
||||
goto fragment_pass;
|
||||
@ -974,11 +998,20 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
|
||||
|
||||
no_fragment:
|
||||
/* At this point, only IP_DF is allowed in ip_off */
|
||||
h->ip_off &= htons(IP_DF);
|
||||
if (h->ip_off & ~htons(IP_DF)) {
|
||||
u_int16_t ip_off = h->ip_off;
|
||||
|
||||
h->ip_off &= htons(IP_DF);
|
||||
h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_off, h->ip_off, 0);
|
||||
}
|
||||
|
||||
/* Enforce a minimum ttl, may cause endless packet loops */
|
||||
if (r->min_ttl && h->ip_ttl < r->min_ttl)
|
||||
if (r->min_ttl && h->ip_ttl < r->min_ttl) {
|
||||
u_int16_t ip_ttl = h->ip_ttl;
|
||||
|
||||
h->ip_ttl = r->min_ttl;
|
||||
h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_ttl, h->ip_ttl, 0);
|
||||
}
|
||||
|
||||
if (r->rule_flag & PFRULE_RANDOMID) {
|
||||
u_int16_t ip_id = h->ip_id;
|
||||
@ -993,8 +1026,12 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
|
||||
|
||||
fragment_pass:
|
||||
/* Enforce a minimum ttl, may cause endless packet loops */
|
||||
if (r->min_ttl && h->ip_ttl < r->min_ttl)
|
||||
if (r->min_ttl && h->ip_ttl < r->min_ttl) {
|
||||
u_int16_t ip_ttl = h->ip_ttl;
|
||||
|
||||
h->ip_ttl = r->min_ttl;
|
||||
h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_ttl, h->ip_ttl, 0);
|
||||
}
|
||||
if ((r->rule_flag & (PFRULE_FRAGCROP|PFRULE_FRAGDROP)) == 0)
|
||||
pd->flags |= PFDESC_IP_REAS;
|
||||
return (PF_PASS);
|
||||
@ -1002,13 +1039,13 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
|
||||
no_mem:
|
||||
REASON_SET(reason, PFRES_MEMORY);
|
||||
if (r != NULL && r->log)
|
||||
PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL);
|
||||
PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL, pd);
|
||||
return (PF_DROP);
|
||||
|
||||
drop:
|
||||
REASON_SET(reason, PFRES_NORM);
|
||||
if (r != NULL && r->log)
|
||||
PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL);
|
||||
PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL, pd);
|
||||
return (PF_DROP);
|
||||
|
||||
bad:
|
||||
@ -1020,7 +1057,7 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
|
||||
|
||||
REASON_SET(reason, PFRES_FRAG);
|
||||
if (r != NULL && r->log)
|
||||
PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL);
|
||||
PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL, pd);
|
||||
|
||||
return (PF_DROP);
|
||||
}
|
||||
@ -1048,8 +1085,7 @@ pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif,
|
||||
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr);
|
||||
while (r != NULL) {
|
||||
r->evaluations++;
|
||||
if (r->kif != NULL &&
|
||||
(r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
|
||||
if (pfi_kif_match(r->kif, kif) == r->ifnot)
|
||||
r = r->skip[PF_SKIP_IFP].ptr;
|
||||
else if (r->direction && r->direction != dir)
|
||||
r = r->skip[PF_SKIP_DIR].ptr;
|
||||
@ -1060,19 +1096,23 @@ pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif,
|
||||
r = r->skip[PF_SKIP_PROTO].ptr;
|
||||
#endif
|
||||
else if (PF_MISMATCHAW(&r->src.addr,
|
||||
(struct pf_addr *)&h->ip6_src, AF_INET6, r->src.neg))
|
||||
(struct pf_addr *)&h->ip6_src, AF_INET6,
|
||||
r->src.neg, kif))
|
||||
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
|
||||
else if (PF_MISMATCHAW(&r->dst.addr,
|
||||
(struct pf_addr *)&h->ip6_dst, AF_INET6, r->dst.neg))
|
||||
(struct pf_addr *)&h->ip6_dst, AF_INET6,
|
||||
r->dst.neg, NULL))
|
||||
r = r->skip[PF_SKIP_DST_ADDR].ptr;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (r == NULL)
|
||||
if (r == NULL || r->action == PF_NOSCRUB)
|
||||
return (PF_PASS);
|
||||
else
|
||||
r->packets++;
|
||||
else {
|
||||
r->packets[dir == PF_OUT]++;
|
||||
r->bytes[dir == PF_OUT] += pd->tot_len;
|
||||
}
|
||||
|
||||
/* Check for illegal packets */
|
||||
if (sizeof(struct ip6_hdr) + IPV6_MAXPACKET < m->m_pkthdr.len)
|
||||
@ -1184,19 +1224,19 @@ pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif,
|
||||
shortpkt:
|
||||
REASON_SET(reason, PFRES_SHORT);
|
||||
if (r != NULL && r->log)
|
||||
PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL);
|
||||
PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL, pd);
|
||||
return (PF_DROP);
|
||||
|
||||
drop:
|
||||
REASON_SET(reason, PFRES_NORM);
|
||||
if (r != NULL && r->log)
|
||||
PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL);
|
||||
PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL, pd);
|
||||
return (PF_DROP);
|
||||
|
||||
badfrag:
|
||||
REASON_SET(reason, PFRES_FRAG);
|
||||
if (r != NULL && r->log)
|
||||
PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL);
|
||||
PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL, pd);
|
||||
return (PF_DROP);
|
||||
}
|
||||
#endif /* INET6 */
|
||||
@ -1215,8 +1255,7 @@ pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff,
|
||||
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr);
|
||||
while (r != NULL) {
|
||||
r->evaluations++;
|
||||
if (r->kif != NULL &&
|
||||
(r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
|
||||
if (pfi_kif_match(r->kif, kif) == r->ifnot)
|
||||
r = r->skip[PF_SKIP_IFP].ptr;
|
||||
else if (r->direction && r->direction != dir)
|
||||
r = r->skip[PF_SKIP_DIR].ptr;
|
||||
@ -1224,12 +1263,14 @@ pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff,
|
||||
r = r->skip[PF_SKIP_AF].ptr;
|
||||
else if (r->proto && r->proto != pd->proto)
|
||||
r = r->skip[PF_SKIP_PROTO].ptr;
|
||||
else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg))
|
||||
else if (PF_MISMATCHAW(&r->src.addr, pd->src, af,
|
||||
r->src.neg, kif))
|
||||
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
|
||||
else if (r->src.port_op && !pf_match_port(r->src.port_op,
|
||||
r->src.port[0], r->src.port[1], th->th_sport))
|
||||
r = r->skip[PF_SKIP_SRC_PORT].ptr;
|
||||
else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg))
|
||||
else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af,
|
||||
r->dst.neg, NULL))
|
||||
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))
|
||||
@ -1246,8 +1287,10 @@ pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff,
|
||||
|
||||
if (rm == NULL || rm->action == PF_NOSCRUB)
|
||||
return (PF_PASS);
|
||||
else
|
||||
r->packets++;
|
||||
else {
|
||||
r->packets[dir == PF_OUT]++;
|
||||
r->bytes[dir == PF_OUT] += pd->tot_len;
|
||||
}
|
||||
|
||||
if (rm->rule_flag & PFRULE_REASSEMBLE_TCP)
|
||||
pd->flags |= PFDESC_TCP_NORM;
|
||||
@ -1309,7 +1352,7 @@ pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff,
|
||||
tcp_drop:
|
||||
REASON_SET(&reason, PFRES_NORM);
|
||||
if (rm != NULL && r->log)
|
||||
PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, r, NULL, NULL);
|
||||
PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, r, NULL, NULL, pd);
|
||||
return (PF_DROP);
|
||||
}
|
||||
|
||||
@ -1743,7 +1786,7 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd,
|
||||
* timestamps. And require all data packets to contain a timestamp
|
||||
* if the first does. PAWS implicitly requires that all data packets be
|
||||
* timestamped. But I think there are middle-man devices that hijack
|
||||
* TCP streams immedietly after the 3whs and don't timestamp their
|
||||
* TCP streams immediately 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 &
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: pf_osfp.c,v 1.10 2004/04/09 19:30:41 frantzen Exp $ */
|
||||
/* $OpenBSD: pf_osfp.c,v 1.12 2006/12/13 18:14:10 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003 Mike Frantzen <frantzen@w4g.org>
|
||||
@ -32,9 +32,10 @@
|
||||
#include <net/if.h>
|
||||
#include <net/pfvar.h>
|
||||
|
||||
#ifdef INET6
|
||||
#include <netinet/ip6.h>
|
||||
#endif /* INET6 */
|
||||
#ifdef _KERNEL
|
||||
#include <netinet6/in6_var.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _KERNEL
|
||||
@ -51,6 +52,7 @@ typedef struct pool pool_t;
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# include <netdb.h>
|
||||
# define pool_t int
|
||||
# define pool_get(pool, flags) malloc(*(pool))
|
||||
# define pool_put(pool, item) free(item)
|
||||
@ -87,38 +89,96 @@ pf_osfp_fingerprint(struct pf_pdesc *pd, struct mbuf *m, int off,
|
||||
const struct tcphdr *tcp)
|
||||
{
|
||||
struct ip *ip;
|
||||
struct ip6_hdr *ip6;
|
||||
char hdr[60];
|
||||
|
||||
/* XXX don't have a fingerprint database for IPv6 :-( */
|
||||
if (pd->af != PF_INET || pd->proto != IPPROTO_TCP || (tcp->th_off << 2)
|
||||
< sizeof(*tcp))
|
||||
if ((pd->af != PF_INET && pd->af != PF_INET6) ||
|
||||
pd->proto != IPPROTO_TCP || (tcp->th_off << 2) < sizeof(*tcp))
|
||||
return (NULL);
|
||||
|
||||
ip = mtod(m, struct ip *);
|
||||
if (!pf_pull_hdr(m, off, hdr, tcp->th_off << 2, NULL, NULL, pd->af))
|
||||
return (NULL);
|
||||
if (pd->af == PF_INET) {
|
||||
ip = mtod(m, struct ip *);
|
||||
ip6 = (struct ip6_hdr *)NULL;
|
||||
} else {
|
||||
ip = (struct ip *)NULL;
|
||||
ip6 = mtod(m, struct ip6_hdr *);
|
||||
}
|
||||
if (!pf_pull_hdr(m, off, hdr, tcp->th_off << 2, NULL, NULL,
|
||||
pd->af)) return (NULL);
|
||||
|
||||
return (pf_osfp_fingerprint_hdr(ip, (struct tcphdr *)hdr));
|
||||
return (pf_osfp_fingerprint_hdr(ip, ip6, (struct tcphdr *)hdr));
|
||||
}
|
||||
#endif /* _KERNEL */
|
||||
|
||||
struct pf_osfp_enlist *
|
||||
pf_osfp_fingerprint_hdr(const struct ip *ip, const struct tcphdr *tcp)
|
||||
pf_osfp_fingerprint_hdr(const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcp)
|
||||
{
|
||||
struct pf_os_fingerprint fp, *fpresult;
|
||||
int cnt, optlen = 0;
|
||||
const u_int8_t *optp;
|
||||
#ifdef _KERNEL
|
||||
char srcname[128];
|
||||
#else
|
||||
char srcname[NI_MAXHOST];
|
||||
#endif
|
||||
|
||||
if ((tcp->th_flags & (TH_SYN|TH_ACK)) != TH_SYN || (ip->ip_off &
|
||||
htons(IP_OFFMASK)))
|
||||
if ((tcp->th_flags & (TH_SYN|TH_ACK)) != TH_SYN)
|
||||
return (NULL);
|
||||
if (ip) {
|
||||
if ((ip->ip_off & htons(IP_OFFMASK)) != 0)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
memset(&fp, 0, sizeof(fp));
|
||||
|
||||
fp.fp_psize = ntohs(ip->ip_len);
|
||||
fp.fp_ttl = ip->ip_ttl;
|
||||
if (ip->ip_off & htons(IP_DF))
|
||||
if (ip) {
|
||||
#ifndef _KERNEL
|
||||
struct sockaddr_in sin;
|
||||
#endif
|
||||
|
||||
fp.fp_psize = ntohs(ip->ip_len);
|
||||
fp.fp_ttl = ip->ip_ttl;
|
||||
if (ip->ip_off & htons(IP_DF))
|
||||
fp.fp_flags |= PF_OSFP_DF;
|
||||
#ifdef _KERNEL
|
||||
strlcpy(srcname, inet_ntoa(ip->ip_src), sizeof(srcname));
|
||||
#else
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_len = sizeof(struct sockaddr_in);
|
||||
sin.sin_addr = ip->ip_src;
|
||||
(void)getnameinfo((struct sockaddr *)&sin,
|
||||
sizeof(struct sockaddr_in), srcname, sizeof(srcname),
|
||||
NULL, 0, NI_NUMERICHOST);
|
||||
#endif
|
||||
}
|
||||
#ifdef INET6
|
||||
else if (ip6) {
|
||||
#ifndef _KERNEL
|
||||
struct sockaddr_in6 sin6;
|
||||
#endif
|
||||
|
||||
/* jumbo payload? */
|
||||
fp.fp_psize = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen);
|
||||
fp.fp_ttl = ip6->ip6_hlim;
|
||||
fp.fp_flags |= PF_OSFP_DF;
|
||||
fp.fp_flags |= PF_OSFP_INET6;
|
||||
#ifdef _KERNEL
|
||||
strlcpy(srcname, ip6_sprintf((struct in6_addr *)&ip6->ip6_src),
|
||||
sizeof(srcname));
|
||||
#else
|
||||
memset(&sin6, 0, sizeof(sin6));
|
||||
sin6.sin6_family = AF_INET6;
|
||||
sin6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
sin6.sin6_addr = ip6->ip6_src;
|
||||
(void)getnameinfo((struct sockaddr *)&sin6,
|
||||
sizeof(struct sockaddr_in6), srcname, sizeof(srcname),
|
||||
NULL, 0, NI_NUMERICHOST);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
else
|
||||
return (NULL);
|
||||
fp.fp_wsize = ntohs(tcp->th_win);
|
||||
|
||||
|
||||
@ -181,7 +241,7 @@ pf_osfp_fingerprint_hdr(const struct ip *ip, const struct tcphdr *tcp)
|
||||
|
||||
DPFPRINTF("fingerprinted %s:%d %d:%d:%d:%d:%llx (%d) "
|
||||
"(TS=%s,M=%s%d,W=%s%d)\n",
|
||||
inet_ntoa(ip->ip_src), ntohs(tcp->th_sport),
|
||||
srcname, ntohs(tcp->th_sport),
|
||||
fp.fp_wsize, fp.fp_ttl, (fp.fp_flags & PF_OSFP_DF) != 0,
|
||||
fp.fp_psize, (long long int)fp.fp_tcpopts, fp.fp_optcnt,
|
||||
(fp.fp_flags & PF_OSFP_TS0) ? "0" : "",
|
||||
|
415
sys/contrib/pf/net/pf_ruleset.c
Normal file
415
sys/contrib/pf/net/pf_ruleset.c
Normal file
@ -0,0 +1,415 @@
|
||||
/* $OpenBSD: pf_ruleset.c,v 1.1 2006/10/27 13:56:51 mcbride Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 Daniel Hartmeier
|
||||
* Copyright (c) 2002,2003 Henning Brauer
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Effort sponsored in part by the Defense Advanced Research Projects
|
||||
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||
* Materiel Command, USAF, under agreement number F30602-01-2-0537.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#ifdef _KERNEL
|
||||
# include <sys/systm.h>
|
||||
#endif /* _KERNEL */
|
||||
#include <sys/mbuf.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/pfvar.h>
|
||||
|
||||
#ifdef INET6
|
||||
#include <netinet/ip6.h>
|
||||
#endif /* INET6 */
|
||||
|
||||
|
||||
#ifdef _KERNEL
|
||||
# define DPFPRINTF(format, x...) \
|
||||
if (pf_status.debug >= PF_DEBUG_NOISY) \
|
||||
printf(format , ##x)
|
||||
#define rs_malloc(x) malloc(x, M_TEMP, M_WAITOK)
|
||||
#define rs_free(x) free(x, M_TEMP)
|
||||
|
||||
#else
|
||||
/* Userland equivalents so we can lend code to pfctl et al. */
|
||||
|
||||
# include <arpa/inet.h>
|
||||
# include <errno.h>
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# define rs_malloc(x) malloc(x)
|
||||
# define rs_free(x) free(x)
|
||||
|
||||
# ifdef PFDEBUG
|
||||
# include <sys/stdarg.h>
|
||||
# define DPFPRINTF(format, x...) fprintf(stderr, format , ##x)
|
||||
# else
|
||||
# define DPFPRINTF(format, x...) ((void)0)
|
||||
# endif /* PFDEBUG */
|
||||
#endif /* _KERNEL */
|
||||
|
||||
|
||||
struct pf_anchor_global pf_anchors;
|
||||
struct pf_anchor pf_main_anchor;
|
||||
|
||||
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 *);
|
||||
|
||||
static __inline int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
|
||||
|
||||
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_anchor_compare(struct pf_anchor *a, struct pf_anchor *b)
|
||||
{
|
||||
int c = strcmp(a->path, b->path);
|
||||
|
||||
return (c ? (c < 0 ? -1 : 1) : 0);
|
||||
}
|
||||
|
||||
int
|
||||
pf_get_ruleset_number(u_int8_t action)
|
||||
{
|
||||
switch (action) {
|
||||
case PF_SCRUB:
|
||||
case PF_NOSCRUB:
|
||||
return (PF_RULESET_SCRUB);
|
||||
break;
|
||||
case PF_PASS:
|
||||
case PF_DROP:
|
||||
return (PF_RULESET_FILTER);
|
||||
break;
|
||||
case PF_NAT:
|
||||
case PF_NONAT:
|
||||
return (PF_RULESET_NAT);
|
||||
break;
|
||||
case PF_BINAT:
|
||||
case PF_NOBINAT:
|
||||
return (PF_RULESET_BINAT);
|
||||
break;
|
||||
case PF_RDR:
|
||||
case PF_NORDR:
|
||||
return (PF_RULESET_RDR);
|
||||
break;
|
||||
default:
|
||||
return (PF_RULESET_MAX);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pf_init_ruleset(struct pf_ruleset *ruleset)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(ruleset, 0, sizeof(struct pf_ruleset));
|
||||
for (i = 0; i < PF_RULESET_MAX; i++) {
|
||||
TAILQ_INIT(&ruleset->rules[i].queues[0]);
|
||||
TAILQ_INIT(&ruleset->rules[i].queues[1]);
|
||||
ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0];
|
||||
ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1];
|
||||
}
|
||||
}
|
||||
|
||||
struct pf_anchor *
|
||||
pf_find_anchor(const char *path)
|
||||
{
|
||||
struct pf_anchor *key, *found;
|
||||
|
||||
key = (struct pf_anchor *)rs_malloc(sizeof(*key));
|
||||
memset(key, 0, sizeof(*key));
|
||||
strlcpy(key->path, path, sizeof(key->path));
|
||||
found = RB_FIND(pf_anchor_global, &pf_anchors, key);
|
||||
rs_free(key);
|
||||
return (found);
|
||||
}
|
||||
|
||||
struct pf_ruleset *
|
||||
pf_find_ruleset(const char *path)
|
||||
{
|
||||
struct pf_anchor *anchor;
|
||||
|
||||
while (*path == '/')
|
||||
path++;
|
||||
if (!*path)
|
||||
return (&pf_main_ruleset);
|
||||
anchor = pf_find_anchor(path);
|
||||
if (anchor == NULL)
|
||||
return (NULL);
|
||||
else
|
||||
return (&anchor->ruleset);
|
||||
}
|
||||
|
||||
struct pf_ruleset *
|
||||
pf_find_or_create_ruleset(const char *path)
|
||||
{
|
||||
char *p, *q, *r;
|
||||
struct pf_ruleset *ruleset;
|
||||
struct pf_anchor *anchor, *dup, *parent = NULL;
|
||||
|
||||
if (path[0] == 0)
|
||||
return (&pf_main_ruleset);
|
||||
while (*path == '/')
|
||||
path++;
|
||||
ruleset = pf_find_ruleset(path);
|
||||
if (ruleset != NULL)
|
||||
return (ruleset);
|
||||
p = (char *)rs_malloc(MAXPATHLEN);
|
||||
bzero(p, MAXPATHLEN);
|
||||
strlcpy(p, path, MAXPATHLEN);
|
||||
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, MAXPATHLEN);
|
||||
if (!*q) {
|
||||
rs_free(p);
|
||||
return (NULL);
|
||||
}
|
||||
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)) {
|
||||
rs_free(p);
|
||||
return (NULL);
|
||||
}
|
||||
anchor = (struct pf_anchor *)rs_malloc(sizeof(*anchor));
|
||||
if (anchor == NULL) {
|
||||
rs_free(p);
|
||||
return (NULL);
|
||||
}
|
||||
memset(anchor, 0, sizeof(*anchor));
|
||||
RB_INIT(&anchor->children);
|
||||
strlcpy(anchor->name, q, sizeof(anchor->name));
|
||||
if (parent != NULL) {
|
||||
strlcpy(anchor->path, parent->path,
|
||||
sizeof(anchor->path));
|
||||
strlcat(anchor->path, "/", sizeof(anchor->path));
|
||||
}
|
||||
strlcat(anchor->path, anchor->name, sizeof(anchor->path));
|
||||
if ((dup = RB_INSERT(pf_anchor_global, &pf_anchors, anchor)) !=
|
||||
NULL) {
|
||||
printf("pf_find_or_create_ruleset: RB_INSERT1 "
|
||||
"'%s' '%s' collides with '%s' '%s'\n",
|
||||
anchor->path, anchor->name, dup->path, dup->name);
|
||||
rs_free(anchor);
|
||||
rs_free(p);
|
||||
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);
|
||||
rs_free(anchor);
|
||||
rs_free(p);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
pf_init_ruleset(&anchor->ruleset);
|
||||
anchor->ruleset.anchor = anchor;
|
||||
parent = anchor;
|
||||
if (r != NULL)
|
||||
q = r + 1;
|
||||
else
|
||||
*q = 0;
|
||||
}
|
||||
rs_free(p);
|
||||
return (&anchor->ruleset);
|
||||
}
|
||||
|
||||
void
|
||||
pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
|
||||
{
|
||||
struct pf_anchor *parent;
|
||||
int i;
|
||||
|
||||
while (ruleset != NULL) {
|
||||
if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL ||
|
||||
!RB_EMPTY(&ruleset->anchor->children) ||
|
||||
ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
|
||||
ruleset->topen)
|
||||
return;
|
||||
for (i = 0; i < PF_RULESET_MAX; ++i)
|
||||
if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
|
||||
!TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) ||
|
||||
ruleset->rules[i].inactive.open)
|
||||
return;
|
||||
RB_REMOVE(pf_anchor_global, &pf_anchors, ruleset->anchor);
|
||||
if ((parent = ruleset->anchor->parent) != NULL)
|
||||
RB_REMOVE(pf_anchor_node, &parent->children,
|
||||
ruleset->anchor);
|
||||
rs_free(ruleset->anchor);
|
||||
if (parent == NULL)
|
||||
return;
|
||||
ruleset = &parent->ruleset;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
pf_anchor_setup(struct pf_rule *r, const struct pf_ruleset *s,
|
||||
const char *name)
|
||||
{
|
||||
char *p, *path;
|
||||
struct pf_ruleset *ruleset;
|
||||
|
||||
r->anchor = NULL;
|
||||
r->anchor_relative = 0;
|
||||
r->anchor_wildcard = 0;
|
||||
if (!name[0])
|
||||
return (0);
|
||||
path = (char *)rs_malloc(MAXPATHLEN);
|
||||
bzero(path, MAXPATHLEN);
|
||||
if (name[0] == '/')
|
||||
strlcpy(path, name + 1, MAXPATHLEN);
|
||||
else {
|
||||
/* relative path */
|
||||
r->anchor_relative = 1;
|
||||
if (s->anchor == NULL || !s->anchor->path[0])
|
||||
path[0] = 0;
|
||||
else
|
||||
strlcpy(path, s->anchor->path, MAXPATHLEN);
|
||||
while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
|
||||
if (!path[0]) {
|
||||
printf("pf_anchor_setup: .. beyond root\n");
|
||||
rs_free(path);
|
||||
return (1);
|
||||
}
|
||||
if ((p = strrchr(path, '/')) != NULL)
|
||||
*p = 0;
|
||||
else
|
||||
path[0] = 0;
|
||||
r->anchor_relative++;
|
||||
name += 3;
|
||||
}
|
||||
if (path[0])
|
||||
strlcat(path, "/", MAXPATHLEN);
|
||||
strlcat(path, name, MAXPATHLEN);
|
||||
}
|
||||
if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
|
||||
r->anchor_wildcard = 1;
|
||||
*p = 0;
|
||||
}
|
||||
ruleset = pf_find_or_create_ruleset(path);
|
||||
rs_free(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, *p;
|
||||
int i;
|
||||
|
||||
a = (char *)rs_malloc(MAXPATHLEN);
|
||||
bzero(a, MAXPATHLEN);
|
||||
if (rs->anchor == NULL)
|
||||
a[0] = 0;
|
||||
else
|
||||
strlcpy(a, rs->anchor->path, MAXPATHLEN);
|
||||
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, r->anchor->path, strlen(a))) {
|
||||
printf("pf_anchor_copyout: '%s' '%s'\n", a,
|
||||
r->anchor->path);
|
||||
rs_free(a);
|
||||
return (1);
|
||||
}
|
||||
if (strlen(r->anchor->path) > strlen(a))
|
||||
strlcat(pr->anchor_call, r->anchor->path + (a[0] ?
|
||||
strlen(a) + 1 : 0), sizeof(pr->anchor_call));
|
||||
rs_free(a);
|
||||
}
|
||||
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\n");
|
||||
r->anchor = NULL;
|
||||
return;
|
||||
}
|
||||
if (!--r->anchor->refcnt)
|
||||
pf_remove_if_empty_ruleset(&r->anchor->ruleset);
|
||||
r->anchor = NULL;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: pf_table.c,v 1.62 2004/12/07 18:02:04 mcbride Exp $ */
|
||||
/* $OpenBSD: pf_table.c,v 1.68 2006/05/02 10:08:45 dhartmei Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002 Cedric Berger
|
||||
@ -404,7 +404,8 @@ _bad:
|
||||
|
||||
int
|
||||
pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
|
||||
int *size2, int *nadd, int *ndel, int *nchange, int flags)
|
||||
int *size2, int *nadd, int *ndel, int *nchange, int flags,
|
||||
u_int32_t ignore_pfrt_flags)
|
||||
{
|
||||
struct pfr_ktable *kt, *tmpkt;
|
||||
struct pfr_kentryworkq addq, delq, changeq;
|
||||
@ -414,7 +415,8 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
|
||||
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))
|
||||
if (pfr_validate_table(tbl, ignore_pfrt_flags, flags &
|
||||
PFR_FLAG_USERIOCTL))
|
||||
return (EINVAL);
|
||||
kt = pfr_lookup_table(tbl);
|
||||
if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
|
||||
@ -2047,7 +2049,7 @@ pfr_attach_table(struct pf_ruleset *rs, char *name)
|
||||
bzero(&tbl, sizeof(tbl));
|
||||
strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name));
|
||||
if (ac != NULL)
|
||||
strlcpy(tbl.pfrt_anchor, ac->name, sizeof(tbl.pfrt_anchor));
|
||||
strlcpy(tbl.pfrt_anchor, ac->path, sizeof(tbl.pfrt_anchor));
|
||||
kt = pfr_lookup_table(&tbl);
|
||||
if (kt == NULL) {
|
||||
kt = pfr_create_ktable(&tbl, time_second, 1);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: pfvar.h,v 1.213 2005/03/03 07:13:39 dhartmei Exp $ */
|
||||
/* $OpenBSD: pfvar.h,v 1.244 2007/02/23 21:31:51 deraadt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 Daniel Hartmeier
|
||||
@ -37,6 +37,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/tree.h>
|
||||
#include <sys/rwlock.h>
|
||||
|
||||
#include <net/radix.h>
|
||||
#include <net/route.h>
|
||||
@ -44,10 +45,18 @@
|
||||
#include <netinet/tcp_fsm.h>
|
||||
|
||||
struct ip;
|
||||
struct ip6_hdr;
|
||||
|
||||
#define PF_TCPS_PROXY_SRC ((TCP_NSTATES)+0)
|
||||
#define PF_TCPS_PROXY_DST ((TCP_NSTATES)+1)
|
||||
|
||||
#define PF_MD5_DIGEST_LENGTH 16
|
||||
#ifdef MD5_DIGEST_LENGTH
|
||||
#if PF_MD5_DIGEST_LENGTH != MD5_DIGEST_LENGTH
|
||||
#error
|
||||
#endif
|
||||
#endif
|
||||
|
||||
enum { PF_INOUT, PF_IN, PF_OUT };
|
||||
enum { PF_LAN_EXT, PF_EXT_GWY, PF_ID };
|
||||
enum { PF_PASS, PF_DROP, PF_SCRUB, PF_NOSCRUB, PF_NAT, PF_NONAT,
|
||||
@ -60,6 +69,8 @@ enum { PF_DEBUG_NONE, PF_DEBUG_URGENT, PF_DEBUG_MISC, PF_DEBUG_NOISY };
|
||||
enum { PF_CHANGE_NONE, PF_CHANGE_ADD_HEAD, PF_CHANGE_ADD_TAIL,
|
||||
PF_CHANGE_ADD_BEFORE, PF_CHANGE_ADD_AFTER,
|
||||
PF_CHANGE_REMOVE, PF_CHANGE_GET_TICKET };
|
||||
enum { PF_GET_NONE, PF_GET_CLR_CNTR };
|
||||
|
||||
/*
|
||||
* Note about PFTM_*: real indices into pf_rule.timeout[] come before
|
||||
* PFTM_MAX, special cases afterwards. See pf_state_expires().
|
||||
@ -71,7 +82,8 @@ enum { PFTM_TCP_FIRST_PACKET, PFTM_TCP_OPENING, PFTM_TCP_ESTABLISHED,
|
||||
PFTM_OTHER_FIRST_PACKET, PFTM_OTHER_SINGLE,
|
||||
PFTM_OTHER_MULTIPLE, PFTM_FRAG, PFTM_INTERVAL,
|
||||
PFTM_ADAPTIVE_START, PFTM_ADAPTIVE_END, PFTM_SRC_NODE,
|
||||
PFTM_TS_DIFF, PFTM_MAX, PFTM_PURGE, PFTM_UNTIL_PACKET };
|
||||
PFTM_TS_DIFF, PFTM_MAX, PFTM_PURGE, PFTM_UNLINKED,
|
||||
PFTM_UNTIL_PACKET };
|
||||
|
||||
/* PFTM default values */
|
||||
#define PFTM_TCP_FIRST_PACKET_VAL 120 /* First TCP packet */
|
||||
@ -94,17 +106,22 @@ enum { PFTM_TCP_FIRST_PACKET, PFTM_TCP_OPENING, PFTM_TCP_ESTABLISHED,
|
||||
#define PFTM_TS_DIFF_VAL 30 /* Allowed TS diff */
|
||||
|
||||
enum { PF_NOPFROUTE, PF_FASTROUTE, PF_ROUTETO, PF_DUPTO, PF_REPLYTO };
|
||||
enum { PF_LIMIT_STATES, PF_LIMIT_SRC_NODES, PF_LIMIT_FRAGS, PF_LIMIT_MAX };
|
||||
enum { PF_LIMIT_STATES, PF_LIMIT_SRC_NODES, PF_LIMIT_FRAGS,
|
||||
PF_LIMIT_TABLES, PF_LIMIT_TABLE_ENTRIES, PF_LIMIT_MAX };
|
||||
#define PF_POOL_IDMASK 0x0f
|
||||
enum { PF_POOL_NONE, PF_POOL_BITMASK, PF_POOL_RANDOM,
|
||||
PF_POOL_SRCHASH, PF_POOL_ROUNDROBIN };
|
||||
enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL,
|
||||
PF_ADDR_TABLE, PF_ADDR_RTLABEL };
|
||||
PF_ADDR_TABLE, PF_ADDR_RTLABEL, PF_ADDR_URPFFAILED };
|
||||
#define PF_POOL_TYPEMASK 0x0f
|
||||
#define PF_POOL_STICKYADDR 0x20
|
||||
#define PF_WSCALE_FLAG 0x80
|
||||
#define PF_WSCALE_MASK 0x0f
|
||||
|
||||
#define PF_LOG 0x01
|
||||
#define PF_LOG_ALL 0x02
|
||||
#define PF_LOG_SOCKET_LOOKUP 0x04
|
||||
|
||||
struct pf_addr {
|
||||
union {
|
||||
struct in_addr v4;
|
||||
@ -152,18 +169,19 @@ struct pf_addr_wrap {
|
||||
#ifdef _KERNEL
|
||||
|
||||
struct pfi_dynaddr {
|
||||
struct pf_addr pfid_addr4;
|
||||
struct pf_addr pfid_mask4;
|
||||
struct pf_addr pfid_addr6;
|
||||
struct pf_addr pfid_mask6;
|
||||
struct pfr_ktable *pfid_kt;
|
||||
struct pfi_kif *pfid_kif;
|
||||
void *pfid_hook_cookie;
|
||||
int pfid_net; /* optional mask, or 128 */
|
||||
int pfid_acnt4; /* address count, IPv4 */
|
||||
int pfid_acnt6; /* address count, IPv6 */
|
||||
sa_family_t pfid_af; /* rule address family */
|
||||
u_int8_t pfid_iflags; /* PFI_AFLAG_* */
|
||||
TAILQ_ENTRY(pfi_dynaddr) entry;
|
||||
struct pf_addr pfid_addr4;
|
||||
struct pf_addr pfid_mask4;
|
||||
struct pf_addr pfid_addr6;
|
||||
struct pf_addr pfid_mask6;
|
||||
struct pfr_ktable *pfid_kt;
|
||||
struct pfi_kif *pfid_kif;
|
||||
void *pfid_hook_cookie;
|
||||
int pfid_net; /* mask or 128 */
|
||||
int pfid_acnt4; /* address count IPv4 */
|
||||
int pfid_acnt6; /* address count IPv6 */
|
||||
sa_family_t pfid_af; /* rule af */
|
||||
u_int8_t pfid_iflags; /* PFI_AFLAG_* */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -299,23 +317,26 @@ struct pfi_dynaddr {
|
||||
#endif /* PF_INET6_ONLY */
|
||||
#endif /* PF_INET_INET6 */
|
||||
|
||||
#define PF_MISMATCHAW(aw, x, af, neg) \
|
||||
( \
|
||||
(((aw)->type == PF_ADDR_NOROUTE && \
|
||||
pf_routable((x), (af))) || \
|
||||
((aw)->type == PF_ADDR_RTLABEL && \
|
||||
!pf_rtlabel_match((x), (af), (aw))) || \
|
||||
((aw)->type == PF_ADDR_TABLE && \
|
||||
!pfr_match_addr((aw)->p.tbl, (x), (af))) || \
|
||||
((aw)->type == PF_ADDR_DYNIFTL && \
|
||||
!pfi_match_addr((aw)->p.dyn, (x), (af))) || \
|
||||
((aw)->type == PF_ADDR_ADDRMASK && \
|
||||
!PF_AZERO(&(aw)->v.a.mask, (af)) && \
|
||||
!PF_MATCHA(0, &(aw)->v.a.addr, \
|
||||
&(aw)->v.a.mask, (x), (af)))) != \
|
||||
(neg) \
|
||||
#define PF_MISMATCHAW(aw, x, af, neg, ifp) \
|
||||
( \
|
||||
(((aw)->type == PF_ADDR_NOROUTE && \
|
||||
pf_routable((x), (af), NULL)) || \
|
||||
(((aw)->type == PF_ADDR_URPFFAILED && (ifp) != NULL && \
|
||||
pf_routable((x), (af), (ifp))) || \
|
||||
((aw)->type == PF_ADDR_RTLABEL && \
|
||||
!pf_rtlabel_match((x), (af), (aw))) || \
|
||||
((aw)->type == PF_ADDR_TABLE && \
|
||||
!pfr_match_addr((aw)->p.tbl, (x), (af))) || \
|
||||
((aw)->type == PF_ADDR_DYNIFTL && \
|
||||
!pfi_match_addr((aw)->p.dyn, (x), (af))) || \
|
||||
((aw)->type == PF_ADDR_ADDRMASK && \
|
||||
!PF_AZERO(&(aw)->v.a.mask, (af)) && \
|
||||
!PF_MATCHA(0, &(aw)->v.a.addr, \
|
||||
&(aw)->v.a.mask, (x), (af))))) != \
|
||||
(neg) \
|
||||
)
|
||||
|
||||
|
||||
struct pf_rule_uid {
|
||||
uid_t uid[2];
|
||||
u_int8_t op;
|
||||
@ -433,6 +454,7 @@ struct pf_os_fingerprint {
|
||||
#define PF_OSFP_MSS_DC 0x0800 /* TCP MSS dont-care */
|
||||
#define PF_OSFP_DF 0x1000 /* IPv4 don't fragment bit */
|
||||
#define PF_OSFP_TS0 0x2000 /* Zero timestamp */
|
||||
#define PF_OSFP_INET6 0x4000 /* IPv6 */
|
||||
u_int8_t fp_optcnt; /* TCP option count */
|
||||
u_int8_t fp_wscale; /* TCP window scaling */
|
||||
u_int8_t fp_ttl; /* IPv4 TTL */
|
||||
@ -488,11 +510,11 @@ struct pf_rule {
|
||||
union pf_rule_ptr skip[PF_SKIP_COUNT];
|
||||
#define PF_RULE_LABEL_SIZE 64
|
||||
char label[PF_RULE_LABEL_SIZE];
|
||||
#define PF_QNAME_SIZE 16
|
||||
#define PF_QNAME_SIZE 64
|
||||
char ifname[IFNAMSIZ];
|
||||
char qname[PF_QNAME_SIZE];
|
||||
char pqname[PF_QNAME_SIZE];
|
||||
#define PF_TAG_NAME_SIZE 16
|
||||
#define PF_TAG_NAME_SIZE 64
|
||||
char tagname[PF_TAG_NAME_SIZE];
|
||||
char match_tagname[PF_TAG_NAME_SIZE];
|
||||
|
||||
@ -502,8 +524,8 @@ struct pf_rule {
|
||||
struct pf_pool rpool;
|
||||
|
||||
u_int64_t evaluations;
|
||||
u_int64_t packets;
|
||||
u_int64_t bytes;
|
||||
u_int64_t packets[2];
|
||||
u_int64_t bytes[2];
|
||||
|
||||
struct pfi_kif *kif;
|
||||
struct pf_anchor *anchor;
|
||||
@ -511,6 +533,7 @@ struct pf_rule {
|
||||
|
||||
pf_osfp_t os_fingerprint;
|
||||
|
||||
int rtableid;
|
||||
u_int32_t timeout[PFTM_MAX];
|
||||
u_int32_t states;
|
||||
u_int32_t max_states;
|
||||
@ -527,6 +550,8 @@ struct pf_rule {
|
||||
u_int32_t rt_listid;
|
||||
u_int32_t nr;
|
||||
u_int32_t prob;
|
||||
uid_t cuid;
|
||||
pid_t cpid;
|
||||
|
||||
u_int16_t return_icmp;
|
||||
u_int16_t return_icmp6;
|
||||
@ -541,6 +566,7 @@ struct pf_rule {
|
||||
u_int8_t action;
|
||||
u_int8_t direction;
|
||||
u_int8_t log;
|
||||
u_int8_t logif;
|
||||
u_int8_t quick;
|
||||
u_int8_t ifnot;
|
||||
u_int8_t match_tag_not;
|
||||
@ -588,9 +614,10 @@ struct pf_rule {
|
||||
|
||||
/* rule flags again */
|
||||
#define PFRULE_IFBOUND 0x00010000 /* if-bound */
|
||||
#define PFRULE_GRBOUND 0x00020000 /* group-bound */
|
||||
|
||||
#define PFSTATE_HIWAT 10000 /* default state table size */
|
||||
#define PFSTATE_ADAPT_START 6000 /* default adaptive timeout start */
|
||||
#define PFSTATE_ADAPT_END 12000 /* default adaptive timeout end */
|
||||
|
||||
|
||||
struct pf_threshold {
|
||||
@ -608,8 +635,8 @@ struct pf_src_node {
|
||||
struct pf_addr raddr;
|
||||
union pf_rule_ptr rule;
|
||||
struct pfi_kif *kif;
|
||||
u_int32_t bytes;
|
||||
u_int32_t packets;
|
||||
u_int64_t bytes[2];
|
||||
u_int64_t packets[2];
|
||||
u_int32_t states;
|
||||
u_int32_t conn;
|
||||
struct pf_threshold conn_rate;
|
||||
@ -651,26 +678,53 @@ struct pf_state_peer {
|
||||
u_int8_t state; /* active state level */
|
||||
u_int8_t wscale; /* window scaling factor */
|
||||
u_int16_t mss; /* Maximum segment size option */
|
||||
u_int8_t tcp_est; /* Did we reach TCPS_ESTABLISHED */
|
||||
struct pf_state_scrub *scrub; /* state is scrubbed */
|
||||
u_int8_t pad[3];
|
||||
};
|
||||
|
||||
TAILQ_HEAD(pf_state_queue, pf_state);
|
||||
|
||||
/* keep synced with struct pf_state, used in RB_FIND */
|
||||
struct pf_state_cmp {
|
||||
u_int64_t id;
|
||||
u_int32_t creatorid;
|
||||
struct pf_state_host lan;
|
||||
struct pf_state_host gwy;
|
||||
struct pf_state_host ext;
|
||||
sa_family_t af;
|
||||
u_int8_t proto;
|
||||
u_int8_t direction;
|
||||
u_int8_t pad;
|
||||
};
|
||||
|
||||
struct pf_state {
|
||||
u_int64_t id;
|
||||
u_int32_t creatorid;
|
||||
struct pf_state_host lan;
|
||||
struct pf_state_host gwy;
|
||||
struct pf_state_host ext;
|
||||
sa_family_t af;
|
||||
u_int8_t proto;
|
||||
u_int8_t direction;
|
||||
u_int8_t pad;
|
||||
u_int8_t log;
|
||||
u_int8_t allow_opts;
|
||||
u_int8_t timeout;
|
||||
u_int8_t sync_flags;
|
||||
#define PFSTATE_NOSYNC 0x01
|
||||
#define PFSTATE_FROMSYNC 0x02
|
||||
#define PFSTATE_STALE 0x04
|
||||
union {
|
||||
struct {
|
||||
RB_ENTRY(pf_state) entry_lan_ext;
|
||||
RB_ENTRY(pf_state) entry_ext_gwy;
|
||||
RB_ENTRY(pf_state) entry_id;
|
||||
TAILQ_ENTRY(pf_state) entry_updates;
|
||||
TAILQ_ENTRY(pf_state) entry_list;
|
||||
struct pfi_kif *kif;
|
||||
} s;
|
||||
char ifname[IFNAMSIZ];
|
||||
} u;
|
||||
struct pf_state_host lan;
|
||||
struct pf_state_host gwy;
|
||||
struct pf_state_host ext;
|
||||
struct pf_state_peer src;
|
||||
struct pf_state_peer dst;
|
||||
union pf_rule_ptr rule;
|
||||
@ -680,24 +734,12 @@ struct pf_state {
|
||||
struct pfi_kif *rt_kif;
|
||||
struct pf_src_node *src_node;
|
||||
struct pf_src_node *nat_src_node;
|
||||
u_int64_t packets[2];
|
||||
u_int64_t bytes[2];
|
||||
u_int32_t creation;
|
||||
u_int32_t expire;
|
||||
u_int32_t pfsync_time;
|
||||
u_int32_t packets[2];
|
||||
u_int32_t bytes[2];
|
||||
u_int32_t creatorid;
|
||||
u_int16_t tag;
|
||||
sa_family_t af;
|
||||
u_int8_t proto;
|
||||
u_int8_t direction;
|
||||
u_int8_t log;
|
||||
u_int8_t allow_opts;
|
||||
u_int8_t timeout;
|
||||
u_int8_t sync_flags;
|
||||
#define PFSTATE_NOSYNC 0x01
|
||||
#define PFSTATE_FROMSYNC 0x02
|
||||
#define PFSTATE_STALE 0x04
|
||||
u_int8_t pad;
|
||||
};
|
||||
|
||||
TAILQ_HEAD(pf_rulequeue, pf_rule);
|
||||
@ -709,6 +751,8 @@ struct pf_ruleset {
|
||||
struct pf_rulequeue queues[2];
|
||||
struct {
|
||||
struct pf_rulequeue *ptr;
|
||||
struct pf_rule **ptr_array;
|
||||
u_int32_t rcount;
|
||||
u_int32_t ticket;
|
||||
int open;
|
||||
} active, inactive;
|
||||
@ -730,6 +774,7 @@ struct pf_anchor {
|
||||
char path[MAXPATHLEN];
|
||||
struct pf_ruleset ruleset;
|
||||
int refcnt; /* anchor rules */
|
||||
int match;
|
||||
};
|
||||
RB_PROTOTYPE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare);
|
||||
RB_PROTOTYPE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare);
|
||||
@ -846,55 +891,47 @@ RB_HEAD(pf_state_tree_ext_gwy, pf_state);
|
||||
RB_PROTOTYPE(pf_state_tree_ext_gwy, pf_state,
|
||||
u.s.entry_ext_gwy, pf_state_compare_ext_gwy);
|
||||
|
||||
struct pfi_if {
|
||||
char pfif_name[IFNAMSIZ];
|
||||
u_int64_t pfif_packets[2][2][2];
|
||||
u_int64_t pfif_bytes[2][2][2];
|
||||
u_int64_t pfif_addcnt;
|
||||
u_int64_t pfif_delcnt;
|
||||
long pfif_tzero;
|
||||
int pfif_states;
|
||||
int pfif_rules;
|
||||
int pfif_flags;
|
||||
};
|
||||
|
||||
TAILQ_HEAD(pfi_grouphead, pfi_kif);
|
||||
TAILQ_HEAD(pfi_statehead, pfi_kif);
|
||||
RB_HEAD(pfi_ifhead, pfi_kif);
|
||||
|
||||
/* keep synced with pfi_kif, used in RB_FIND */
|
||||
struct pfi_kif_cmp {
|
||||
char pfik_name[IFNAMSIZ];
|
||||
};
|
||||
|
||||
struct pfi_kif {
|
||||
struct pfi_if pfik_if;
|
||||
char pfik_name[IFNAMSIZ];
|
||||
RB_ENTRY(pfi_kif) pfik_tree;
|
||||
u_int64_t pfik_packets[2][2][2];
|
||||
u_int64_t pfik_bytes[2][2][2];
|
||||
u_int32_t pfik_tzero;
|
||||
int pfik_flags;
|
||||
struct pf_state_tree_lan_ext pfik_lan_ext;
|
||||
struct pf_state_tree_ext_gwy pfik_ext_gwy;
|
||||
struct pfi_grouphead pfik_grouphead;
|
||||
TAILQ_ENTRY(pfi_kif) pfik_instances;
|
||||
TAILQ_ENTRY(pfi_kif) pfik_w_states;
|
||||
struct hook_desc_head *pfik_ah_head;
|
||||
void *pfik_ah_cookie;
|
||||
struct pfi_kif *pfik_parent;
|
||||
struct ifnet *pfik_ifp;
|
||||
struct ifg_group *pfik_group;
|
||||
int pfik_states;
|
||||
int pfik_rules;
|
||||
TAILQ_HEAD(, pfi_dynaddr) pfik_dynaddrs;
|
||||
};
|
||||
|
||||
enum pfi_kif_refs {
|
||||
PFI_KIF_REF_NONE,
|
||||
PFI_KIF_REF_STATE,
|
||||
PFI_KIF_REF_RULE
|
||||
};
|
||||
#define pfik_name pfik_if.pfif_name
|
||||
#define pfik_packets pfik_if.pfif_packets
|
||||
#define pfik_bytes pfik_if.pfif_bytes
|
||||
#define pfik_tzero pfik_if.pfif_tzero
|
||||
#define pfik_flags pfik_if.pfif_flags
|
||||
#define pfik_addcnt pfik_if.pfif_addcnt
|
||||
#define pfik_delcnt pfik_if.pfif_delcnt
|
||||
#define pfik_states pfik_if.pfif_states
|
||||
#define pfik_rules pfik_if.pfif_rules
|
||||
|
||||
#define PFI_IFLAG_GROUP 0x0001 /* group of interfaces */
|
||||
#define PFI_IFLAG_INSTANCE 0x0002 /* single instance */
|
||||
#define PFI_IFLAG_CLONABLE 0x0010 /* clonable group */
|
||||
#define PFI_IFLAG_DYNAMIC 0x0020 /* dynamic group */
|
||||
#define PFI_IFLAG_ATTACHED 0x0040 /* interface attached */
|
||||
#define PFI_IFLAG_SKIP 0x0100 /* skip filtering on interface */
|
||||
#define PFI_IFLAG_SETABLE_MASK 0x0100 /* setable via DIOC{SET,CLR}IFFLAG */
|
||||
|
||||
struct pf_pdesc {
|
||||
struct {
|
||||
int done;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
pid_t pid;
|
||||
} lookup;
|
||||
u_int64_t tot_len; /* Make Mickey money */
|
||||
union {
|
||||
struct tcphdr *tcp;
|
||||
@ -912,6 +949,7 @@ struct pf_pdesc {
|
||||
struct pf_addr *dst;
|
||||
struct ether_header
|
||||
*eh;
|
||||
struct pf_mtag *pf_mtag;
|
||||
u_int16_t *ip_sum;
|
||||
u_int32_t p_len; /* total length of payload */
|
||||
u_int16_t flags; /* Let SCRUB trigger behavior in
|
||||
@ -1052,6 +1090,7 @@ struct pf_status {
|
||||
u_int32_t debug;
|
||||
u_int32_t hostid;
|
||||
char ifname[IFNAMSIZ];
|
||||
u_int8_t pf_chksum[PF_MD5_DIGEST_LENGTH];
|
||||
};
|
||||
|
||||
struct cbq_opts {
|
||||
@ -1114,6 +1153,20 @@ struct pf_altq {
|
||||
u_int32_t qid; /* return value */
|
||||
};
|
||||
|
||||
#define PF_TAG_GENERATED 0x01
|
||||
#define PF_TAG_FRAGCACHE 0x02
|
||||
#define PF_TAG_TRANSLATE_LOCALHOST 0x04
|
||||
|
||||
struct pf_mtag {
|
||||
void *hdr; /* saved hdr pos in mbuf, for ECN */
|
||||
u_int rtableid; /* alternate routing table id */
|
||||
u_int32_t qid; /* queue id */
|
||||
u_int16_t tag; /* tag id */
|
||||
u_int8_t flags;
|
||||
u_int8_t routed;
|
||||
sa_family_t af; /* for ECN */
|
||||
};
|
||||
|
||||
struct pf_tag {
|
||||
u_int16_t tag; /* tag id */
|
||||
};
|
||||
@ -1130,6 +1183,10 @@ struct pf_tagname {
|
||||
#define PFFRAG_FRCENT_HIWAT 50000 /* Number of fragment cache entries */
|
||||
#define PFFRAG_FRCACHE_HIWAT 10000 /* Number of fragment descriptors */
|
||||
|
||||
#define PFR_KTABLE_HIWAT 1000 /* Number of tables */
|
||||
#define PFR_KENTRY_HIWAT 200000 /* Number of table entries */
|
||||
#define PFR_KENTRY_HIWAT_SMALL 100000 /* Number of table entries (tiny hosts) */
|
||||
|
||||
/*
|
||||
* ioctl parameter structures
|
||||
*/
|
||||
@ -1175,6 +1232,13 @@ struct pfioc_state {
|
||||
struct pf_state state;
|
||||
};
|
||||
|
||||
struct pfioc_src_node_kill {
|
||||
/* XXX returns the number of src nodes killed in psnk_af */
|
||||
sa_family_t psnk_af;
|
||||
struct pf_rule_addr psnk_src;
|
||||
struct pf_rule_addr psnk_dst;
|
||||
};
|
||||
|
||||
struct pfioc_state_kill {
|
||||
/* XXX returns the number of states killed in psk_af */
|
||||
sa_family_t psk_af;
|
||||
@ -1282,11 +1346,6 @@ struct pfioc_table {
|
||||
#define pfrio_setflag pfrio_size2
|
||||
#define pfrio_clrflag pfrio_nadd
|
||||
|
||||
|
||||
#define PFI_FLAG_GROUP 0x0001 /* gets groups of interfaces */
|
||||
#define PFI_FLAG_INSTANCE 0x0002 /* gets single interfaces */
|
||||
#define PFI_FLAG_ALLMASK 0x0003
|
||||
|
||||
struct pfioc_iface {
|
||||
char pfiio_name[IFNAMSIZ];
|
||||
void *pfiio_buffer;
|
||||
@ -1365,9 +1424,9 @@ struct pfioc_iface {
|
||||
#define DIOCCLRSRCNODES _IO('D', 85)
|
||||
#define DIOCSETHOSTID _IOWR('D', 86, u_int32_t)
|
||||
#define DIOCIGETIFACES _IOWR('D', 87, struct pfioc_iface)
|
||||
#define DIOCICLRISTATS _IOWR('D', 88, struct pfioc_iface)
|
||||
#define DIOCSETIFFLAG _IOWR('D', 89, struct pfioc_iface)
|
||||
#define DIOCCLRIFFLAG _IOWR('D', 90, struct pfioc_iface)
|
||||
#define DIOCKILLSRCNODES _IOWR('D', 91, struct pfioc_src_node_kill)
|
||||
|
||||
#ifdef _KERNEL
|
||||
RB_HEAD(pf_src_tree, pf_src_node);
|
||||
@ -1378,16 +1437,13 @@ RB_HEAD(pf_state_tree_id, pf_state);
|
||||
RB_PROTOTYPE(pf_state_tree_id, pf_state,
|
||||
entry_id, pf_state_compare_id);
|
||||
extern struct pf_state_tree_id tree_id;
|
||||
extern struct pf_state_queue state_updates;
|
||||
extern struct pf_state_queue state_list;
|
||||
|
||||
extern struct pf_anchor_global pf_anchors;
|
||||
extern struct pf_ruleset pf_main_ruleset;
|
||||
TAILQ_HEAD(pf_poolqueue, pf_pool);
|
||||
extern struct pf_poolqueue pf_pools[2];
|
||||
TAILQ_HEAD(pf_altqqueue, pf_altq);
|
||||
extern struct pf_altqqueue pf_altqs[2];
|
||||
extern struct pf_palist pf_pabuf;
|
||||
extern struct pfi_kif **pfi_index2kif;
|
||||
|
||||
extern u_int32_t ticket_altqs_active;
|
||||
extern u_int32_t ticket_altqs_inactive;
|
||||
@ -1405,26 +1461,22 @@ extern void pf_calc_skip_steps(struct pf_rulequeue *);
|
||||
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 void pf_purge_thread(void *);
|
||||
extern void pf_purge_expired_src_nodes(int);
|
||||
extern void pf_purge_expired_states(u_int32_t);
|
||||
extern void pf_unlink_state(struct pf_state *);
|
||||
extern void pf_free_state(struct pf_state *);
|
||||
extern int pf_insert_state(struct pfi_kif *,
|
||||
struct pf_state *);
|
||||
extern int pf_insert_src_node(struct pf_src_node **,
|
||||
struct pf_rule *, struct pf_addr *,
|
||||
sa_family_t);
|
||||
void pf_src_tree_remove_state(struct pf_state *);
|
||||
extern struct pf_state *pf_find_state_byid(struct pf_state *);
|
||||
extern struct pf_state *pf_find_state_all(struct pf_state *key,
|
||||
extern struct pf_state *pf_find_state_byid(struct pf_state_cmp *);
|
||||
extern struct pf_state *pf_find_state_all(struct pf_state_cmp *key,
|
||||
u_int8_t tree, int *more);
|
||||
extern void pf_print_state(struct pf_state *);
|
||||
extern void pf_print_flags(u_int8_t);
|
||||
extern struct pf_anchor *pf_find_anchor(const char *);
|
||||
extern struct pf_ruleset *pf_find_ruleset(const char *);
|
||||
extern struct pf_ruleset *pf_find_or_create_ruleset(const char *);
|
||||
extern void pf_remove_if_empty_ruleset(
|
||||
struct pf_ruleset *);
|
||||
extern u_int16_t pf_cksum_fixup(u_int16_t, u_int16_t, u_int16_t,
|
||||
u_int8_t);
|
||||
|
||||
@ -1450,7 +1502,8 @@ void *pf_pull_hdr(struct mbuf *, int, void *, int, u_short *, u_short *,
|
||||
sa_family_t);
|
||||
void pf_change_a(void *, u_int16_t *, u_int32_t, u_int8_t);
|
||||
int pflog_packet(struct pfi_kif *, struct mbuf *, sa_family_t, u_int8_t,
|
||||
u_int8_t, struct pf_rule *, struct pf_rule *, struct pf_ruleset *);
|
||||
u_int8_t, struct pf_rule *, struct pf_rule *, struct pf_ruleset *,
|
||||
struct pf_pdesc *);
|
||||
int pf_match_addr(u_int8_t, struct pf_addr *, struct pf_addr *,
|
||||
struct pf_addr *, sa_family_t);
|
||||
int pf_match(u_int8_t, u_int32_t, u_int32_t, u_int32_t);
|
||||
@ -1474,8 +1527,9 @@ int pf_normalize_tcp_stateful(struct mbuf *, int, struct pf_pdesc *,
|
||||
u_int32_t
|
||||
pf_state_expires(const struct pf_state *);
|
||||
void pf_purge_expired_fragments(void);
|
||||
int pf_routable(struct pf_addr *addr, sa_family_t af);
|
||||
int pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *);
|
||||
int pf_rtlabel_match(struct pf_addr *, sa_family_t, struct pf_addr_wrap *);
|
||||
int pf_socket_lookup(int, struct pf_pdesc *);
|
||||
void pfr_initialize(void);
|
||||
int pfr_match_addr(struct pfr_ktable *, struct pf_addr *, sa_family_t);
|
||||
void pfr_update_stats(struct pfr_ktable *, struct pf_addr *, sa_family_t,
|
||||
@ -1500,7 +1554,7 @@ int pfr_add_addrs(struct pfr_table *, struct pfr_addr *, int, int *,
|
||||
int pfr_del_addrs(struct pfr_table *, struct pfr_addr *, int, int *,
|
||||
int);
|
||||
int pfr_set_addrs(struct pfr_table *, struct pfr_addr *, int, int *,
|
||||
int *, int *, int *, int);
|
||||
int *, int *, int *, int, u_int32_t);
|
||||
int pfr_get_addrs(struct pfr_table *, struct pfr_addr *, int *, int);
|
||||
int pfr_get_astats(struct pfr_table *, struct pfr_astats *, int *, int);
|
||||
int pfr_clr_astats(struct pfr_table *, struct pfr_addr *, int, int *,
|
||||
@ -1513,41 +1567,44 @@ int pfr_ina_commit(struct pfr_table *, u_int32_t, int *, int *, int);
|
||||
int pfr_ina_define(struct pfr_table *, struct pfr_addr *, int, int *,
|
||||
int *, u_int32_t, int);
|
||||
|
||||
extern struct pfi_statehead pfi_statehead;
|
||||
extern struct pfi_kif *pfi_all;
|
||||
|
||||
void pfi_initialize(void);
|
||||
void pfi_attach_clone(struct if_clone *);
|
||||
struct pfi_kif *pfi_kif_get(const char *);
|
||||
void pfi_kif_ref(struct pfi_kif *, enum pfi_kif_refs);
|
||||
void pfi_kif_unref(struct pfi_kif *, enum pfi_kif_refs);
|
||||
int pfi_kif_match(struct pfi_kif *, struct pfi_kif *);
|
||||
void pfi_attach_ifnet(struct ifnet *);
|
||||
void pfi_detach_ifnet(struct ifnet *);
|
||||
struct pfi_kif *pfi_lookup_create(const char *);
|
||||
struct pfi_kif *pfi_lookup_if(const char *);
|
||||
int pfi_maybe_destroy(struct pfi_kif *);
|
||||
struct pfi_kif *pfi_attach_rule(const char *);
|
||||
void pfi_detach_rule(struct pfi_kif *);
|
||||
void pfi_attach_state(struct pfi_kif *);
|
||||
void pfi_detach_state(struct pfi_kif *);
|
||||
int pfi_dynaddr_setup(struct pf_addr_wrap *, sa_family_t);
|
||||
void pfi_dynaddr_copyout(struct pf_addr_wrap *);
|
||||
void pfi_dynaddr_remove(struct pf_addr_wrap *);
|
||||
void pfi_fill_oldstatus(struct pf_status *);
|
||||
int pfi_clr_istats(const char *, int *, int);
|
||||
int pfi_get_ifaces(const char *, struct pfi_if *, int *, int);
|
||||
int pfi_set_flags(const char *, int);
|
||||
int pfi_clear_flags(const char *, int);
|
||||
void pfi_attach_ifgroup(struct ifg_group *);
|
||||
void pfi_detach_ifgroup(struct ifg_group *);
|
||||
void pfi_group_change(const char *);
|
||||
int pfi_match_addr(struct pfi_dynaddr *, struct pf_addr *,
|
||||
sa_family_t);
|
||||
int pfi_dynaddr_setup(struct pf_addr_wrap *, sa_family_t);
|
||||
void pfi_dynaddr_remove(struct pf_addr_wrap *);
|
||||
void pfi_dynaddr_copyout(struct pf_addr_wrap *);
|
||||
void pfi_fill_oldstatus(struct pf_status *);
|
||||
int pfi_clr_istats(const char *);
|
||||
int pfi_get_ifaces(const char *, struct pfi_kif *, int *);
|
||||
int pfi_set_flags(const char *, int);
|
||||
int pfi_clear_flags(const char *, int);
|
||||
|
||||
extern struct pfi_statehead pfi_statehead;
|
||||
|
||||
u_int16_t pf_tagname2tag(char *);
|
||||
void pf_tag2tagname(u_int16_t, char *);
|
||||
void pf_tag_ref(u_int16_t);
|
||||
void pf_tag_unref(u_int16_t);
|
||||
int pf_tag_packet(struct mbuf *, struct pf_tag *, int);
|
||||
u_int32_t pf_qname2qid(char *);
|
||||
void pf_qid2qname(u_int32_t, char *);
|
||||
void pf_qid_unref(u_int32_t);
|
||||
u_int16_t pf_tagname2tag(char *);
|
||||
void pf_tag2tagname(u_int16_t, char *);
|
||||
void pf_tag_ref(u_int16_t);
|
||||
void pf_tag_unref(u_int16_t);
|
||||
int pf_tag_packet(struct mbuf *, struct pf_mtag *, int, int);
|
||||
u_int32_t pf_qname2qid(char *);
|
||||
void pf_qid2qname(u_int32_t, char *);
|
||||
void pf_qid_unref(u_int32_t);
|
||||
struct pf_mtag *pf_find_mtag(struct mbuf *);
|
||||
struct pf_mtag *pf_get_mtag(struct mbuf *);
|
||||
|
||||
extern struct pf_status pf_status;
|
||||
extern struct pool pf_frent_pl, pf_frag_pl;
|
||||
extern struct rwlock pf_consistency_lock;
|
||||
|
||||
struct pf_pool_limit {
|
||||
void *pp;
|
||||
@ -1557,6 +1614,31 @@ extern struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX];
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
extern struct pf_anchor_global pf_anchors;
|
||||
extern struct pf_anchor pf_main_anchor;
|
||||
#define pf_main_ruleset pf_main_anchor.ruleset
|
||||
|
||||
/* these ruleset functions can be linked into userland programs (pfctl) */
|
||||
int pf_get_ruleset_number(u_int8_t);
|
||||
void pf_init_ruleset(struct pf_ruleset *);
|
||||
int pf_anchor_setup(struct pf_rule *,
|
||||
const struct pf_ruleset *, const char *);
|
||||
int pf_anchor_copyout(const struct pf_ruleset *,
|
||||
const struct pf_rule *, struct pfioc_rule *);
|
||||
void pf_anchor_remove(struct pf_rule *);
|
||||
void pf_remove_if_empty_ruleset(struct pf_ruleset *);
|
||||
struct pf_anchor *pf_find_anchor(const char *);
|
||||
struct pf_ruleset *pf_find_ruleset(const char *);
|
||||
struct pf_ruleset *pf_find_or_create_ruleset(const char *);
|
||||
void pf_rs_initialize(void);
|
||||
|
||||
#ifdef _KERNEL
|
||||
int pf_anchor_copyout(const struct pf_ruleset *,
|
||||
const struct pf_rule *, struct pfioc_rule *);
|
||||
void pf_anchor_remove(struct pf_rule *);
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
/* The fingerprint functions can be linked into userland programs (tcpdump) */
|
||||
int pf_osfp_add(struct pf_osfp_ioctl *);
|
||||
#ifdef _KERNEL
|
||||
@ -1565,7 +1647,8 @@ struct pf_osfp_enlist *
|
||||
const struct tcphdr *);
|
||||
#endif /* _KERNEL */
|
||||
struct pf_osfp_enlist *
|
||||
pf_osfp_fingerprint_hdr(const struct ip *, const struct tcphdr *);
|
||||
pf_osfp_fingerprint_hdr(const struct ip *, const struct ip6_hdr *,
|
||||
const struct tcphdr *);
|
||||
void pf_osfp_flush(void);
|
||||
int pf_osfp_get(struct pf_osfp_ioctl *);
|
||||
void pf_osfp_initialize(void);
|
||||
|
Loading…
x
Reference in New Issue
Block a user