summaryrefslogtreecommitdiffstats
path: root/sys/contrib/pf
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/pf')
-rw-r--r--sys/contrib/pf/net/if_pflog.c289
-rw-r--r--sys/contrib/pf/net/if_pflog.h38
-rw-r--r--sys/contrib/pf/net/if_pfsync.c1046
-rw-r--r--sys/contrib/pf/net/if_pfsync.h96
-rw-r--r--sys/contrib/pf/net/pf.c2074
-rw-r--r--sys/contrib/pf/net/pf_if.c959
-rw-r--r--sys/contrib/pf/net/pf_ioctl.c1817
-rw-r--r--sys/contrib/pf/net/pf_norm.c291
-rw-r--r--sys/contrib/pf/net/pf_osfp.c135
-rw-r--r--sys/contrib/pf/net/pf_subr.c127
-rw-r--r--sys/contrib/pf/net/pf_table.c200
-rw-r--r--sys/contrib/pf/net/pfvar.h533
-rw-r--r--sys/contrib/pf/netinet/in4_cksum.c127
13 files changed, 5094 insertions, 2638 deletions
diff --git a/sys/contrib/pf/net/if_pflog.c b/sys/contrib/pf/net/if_pflog.c
index 561a2f6..6ddf212 100644
--- a/sys/contrib/pf/net/if_pflog.c
+++ b/sys/contrib/pf/net/if_pflog.c
@@ -1,4 +1,6 @@
-/* $OpenBSD: if_pflog.c,v 1.22 2006/12/15 09:31:20 otto Exp $ */
+/* $FreeBSD$ */
+/* $OpenBSD: if_pflog.c,v 1.12 2004/05/19 17:50:51 dhartmei Exp $ */
+
/*
* The authors of this code are John Ioannidis (ji@tla.org),
* Angelos D. Keromytis (kermit@csd.uch.gr) and
@@ -33,17 +35,49 @@
* PURPOSE.
*/
+#ifdef __FreeBSD__
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#endif
+
+#ifndef __FreeBSD__
#include "bpfilter.h"
#include "pflog.h"
+#elif __FreeBSD__ >= 5
+#include "opt_bpf.h"
+#include "opt_pf.h"
+
+#ifdef DEV_BPF
+#define NBPFILTER DEV_BPF
+#else
+#define NBPFILTER 0
+#endif
+
+#ifdef DEV_PFLOG
+#define NPFLOG DEV_PFLOG
+#else
+#define NPFLOG 0
+#endif
+
+#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
-#include <sys/proc.h>
#include <sys/socket.h>
+#ifdef __FreeBSD__
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/sockio.h>
+#else
#include <sys/ioctl.h>
+#endif
#include <net/if.h>
+#if defined(__FreeBSD__)
+#include <net/if_clone.h>
+#endif
#include <net/if_types.h>
#include <net/route.h>
#include <net/bpf.h>
@@ -55,6 +89,10 @@
#include <netinet/ip.h>
#endif
+#ifdef __FreeBSD__
+#include <machine/in_cksum.h>
+#endif
+
#ifdef INET6
#ifndef INET
#include <netinet/in.h>
@@ -65,6 +103,10 @@
#include <net/pfvar.h>
#include <net/if_pflog.h>
+#ifdef __FreeBSD__
+#define PFLOGNAME "pflog"
+#endif
+
#define PFLOGMTU (32768 + MHLEN + MLEN)
#ifdef PFLOGDEBUG
@@ -73,91 +115,115 @@
#define DPRINTF(x)
#endif
+#ifndef __FreeBSD__
+struct pflog_softc pflogif[NPFLOG];
+#endif
+
+#ifdef __FreeBSD__
+static void pflog_clone_destroy(struct ifnet *);
+static int pflog_clone_create(struct if_clone *, int, caddr_t);
+#else
void pflogattach(int);
+#endif
int pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
int pflogioctl(struct ifnet *, u_long, caddr_t);
+void pflogrtrequest(int, struct rtentry *, struct sockaddr *);
void pflogstart(struct ifnet *);
-int pflog_clone_create(struct if_clone *, int);
-int pflog_clone_destroy(struct ifnet *);
-
-LIST_HEAD(, pflog_softc) pflogif_list;
-struct if_clone pflog_cloner =
- IF_CLONE_INITIALIZER("pflog", pflog_clone_create, pflog_clone_destroy);
-
-struct ifnet *pflogifs[PFLOGIFS_MAX]; /* for fast access */
+#ifndef __FreeBSD__
extern int ifqmaxlen;
+#endif
-void
-pflogattach(int npflog)
+#ifdef __FreeBSD__
+static MALLOC_DEFINE(M_PFLOG, PFLOGNAME, "Packet Filter Logging Interface");
+static LIST_HEAD(pflog_list, pflog_softc) pflog_list;
+#define SCP2IFP(sc) ((sc)->sc_ifp)
+IFC_SIMPLE_DECLARE(pflog, 1);
+
+static void
+pflog_clone_destroy(struct ifnet *ifp)
{
- int i;
- LIST_INIT(&pflogif_list);
- for (i = 0; i < PFLOGIFS_MAX; i++)
- pflogifs[i] = NULL;
- (void) pflog_clone_create(&pflog_cloner, 0);
- if_clone_attach(&pflog_cloner);
+ struct pflog_softc *sc;
+
+ sc = ifp->if_softc;
+
+ /*
+ * Does we really need this?
+ */
+ IF_DRAIN(&ifp->if_snd);
+
+ bpfdetach(ifp);
+ if_detach(ifp);
+ if_free(ifp);
+ LIST_REMOVE(sc, sc_next);
+ free(sc, M_PFLOG);
}
-int
+static int
+#ifdef __FreeBSD__
+pflog_clone_create(struct if_clone *ifc, int unit, caddr_t params)
+#else
pflog_clone_create(struct if_clone *ifc, int unit)
+#endif
{
+ struct pflog_softc *sc;
struct ifnet *ifp;
- struct pflog_softc *pflogif;
- int s;
- if (unit >= PFLOGIFS_MAX)
- return (EINVAL);
-
- if ((pflogif = malloc(sizeof(*pflogif), M_DEVBUF, M_NOWAIT)) == NULL)
- return (ENOMEM);
- bzero(pflogif, sizeof(*pflogif));
+ MALLOC(sc, struct pflog_softc *, sizeof(*sc), M_PFLOG, M_WAITOK|M_ZERO);
+ ifp = sc->sc_ifp = if_alloc(IFT_PFLOG);
+ if (ifp == NULL) {
+ free(sc, M_PFLOG);
+ return (ENOSPC);
+ }
- pflogif->sc_unit = unit;
- ifp = &pflogif->sc_if;
- snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", unit);
- ifp->if_softc = pflogif;
+ if_initname(ifp, ifc->ifc_name, unit);
ifp->if_mtu = PFLOGMTU;
ifp->if_ioctl = pflogioctl;
ifp->if_output = pflogoutput;
ifp->if_start = pflogstart;
- ifp->if_type = IFT_PFLOG;
ifp->if_snd.ifq_maxlen = ifqmaxlen;
ifp->if_hdrlen = PFLOG_HDRLEN;
+ ifp->if_softc = sc;
if_attach(ifp);
- if_alloc_sadl(ifp);
+ LIST_INSERT_HEAD(&pflog_list, sc, sc_next);
#if NBPFILTER > 0
- bpfattach(&pflogif->sc_if.if_bpf, ifp, DLT_PFLOG, PFLOG_HDRLEN);
+ bpfattach(ifp, DLT_PFLOG, PFLOG_HDRLEN);
#endif
- s = splnet();
- LIST_INSERT_HEAD(&pflogif_list, pflogif, sc_list);
- pflogifs[unit] = ifp;
- splx(s);
-
return (0);
}
-
-int
-pflog_clone_destroy(struct ifnet *ifp)
+#else /* !__FreeBSD__ */
+void
+pflogattach(int npflog)
{
- struct pflog_softc *pflogif = ifp->if_softc;
- int s;
-
- s = splnet();
- pflogifs[pflogif->sc_unit] = NULL;
- LIST_REMOVE(pflogif, sc_list);
- splx(s);
+ struct ifnet *ifp;
+ int i;
+
+ bzero(pflogif, sizeof(pflogif));
+
+ for (i = 0; i < NPFLOG; i++) {
+ ifp = &pflogif[i].sc_if;
+ snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", i);
+ ifp->if_softc = &pflogif[i];
+ ifp->if_mtu = PFLOGMTU;
+ ifp->if_ioctl = pflogioctl;
+ ifp->if_output = pflogoutput;
+ ifp->if_start = pflogstart;
+ ifp->if_type = IFT_PFLOG;
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+ ifp->if_hdrlen = PFLOG_HDRLEN;
+ if_attach(ifp);
+ if_alloc_sadl(ifp);
#if NBPFILTER > 0
- bpfdetach(ifp);
+ bpfattach(&pflogif[i].sc_if.if_bpf, ifp, DLT_PFLOG,
+ PFLOG_HDRLEN);
#endif
- if_detach(ifp);
- free(pflogif, M_DEVBUF);
- return (0);
+ }
}
+#endif /* __FreeBSD__ */
/*
* Start output on the pflog interface.
@@ -166,18 +232,32 @@ void
pflogstart(struct ifnet *ifp)
{
struct mbuf *m;
+#ifndef __FreeBSD__
int s;
+#endif
for (;;) {
- s = splnet();
+#ifdef __FreeBSD__
+ IF_LOCK(&ifp->if_snd);
+ _IF_DROP(&ifp->if_snd);
+ _IF_DEQUEUE(&ifp->if_snd, m);
+ if (m == NULL) {
+ IF_UNLOCK(&ifp->if_snd);
+ return;
+ }
+ else
+ m_freem(m);
+ IF_UNLOCK(&ifp->if_snd);
+#else
+ s = splimp();
IF_DROP(&ifp->if_snd);
IF_DEQUEUE(&ifp->if_snd, m);
splx(s);
-
if (m == NULL)
return;
else
m_freem(m);
+#endif
}
}
@@ -190,6 +270,14 @@ pflogoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
}
/* ARGSUSED */
+void
+pflogrtrequest(int cmd, struct rtentry *rt, struct sockaddr *sa)
+{
+ if (rt)
+ rt->rt_rmx.rmx_mtu = PFLOGMTU;
+}
+
+/* ARGSUSED */
int
pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
@@ -198,10 +286,17 @@ pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
case SIOCAIFADDR:
case SIOCSIFDSTADDR:
case SIOCSIFFLAGS:
+#ifdef __FreeBSD__
+ if (ifp->if_flags & IFF_UP)
+ ifp->if_drv_flags |= IFF_DRV_RUNNING;
+ else
+ ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+#else
if (ifp->if_flags & IFF_UP)
ifp->if_flags |= IFF_RUNNING;
else
ifp->if_flags &= ~IFF_RUNNING;
+#endif
break;
default:
return (EINVAL);
@@ -213,18 +308,18 @@ pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
int
pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
u_int8_t reason, struct pf_rule *rm, struct pf_rule *am,
- struct pf_ruleset *ruleset, struct pf_pdesc *pd)
+ struct pf_ruleset *ruleset)
{
#if NBPFILTER > 0
struct ifnet *ifn;
struct pfloghdr hdr;
+#ifndef __FreeBSD__
+ struct mbuf m1;
+#endif
- if (kif == NULL || m == NULL || rm == NULL || pd == NULL)
+ if (kif == NULL || m == NULL || rm == NULL)
return (-1);
- if ((ifn = pflogifs[rm->logif]) == NULL || !ifn->if_bpf)
- return (0);
-
bzero(&hdr, sizeof(hdr));
hdr.length = PFLOG_REAL_HDRLEN;
hdr.af = af;
@@ -242,17 +337,6 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
strlcpy(hdr.ruleset, ruleset->anchor->name,
sizeof(hdr.ruleset));
}
- if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done)
- pd->lookup.done = pf_socket_lookup(dir, pd);
- if (pd->lookup.done > 0) {
- hdr.uid = pd->lookup.uid;
- hdr.pid = pd->lookup.pid;
- } else {
- hdr.uid = UID_MAX;
- hdr.pid = NO_PID;
- }
- hdr.rule_uid = rm->cuid;
- hdr.rule_pid = rm->cpid;
hdr.dir = dir;
#ifdef INET
@@ -265,11 +349,66 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
}
#endif /* INET */
- ifn->if_opackets++;
- ifn->if_obytes += m->m_pkthdr.len;
- bpf_mtap_hdr(ifn->if_bpf, (char *)&hdr, PFLOG_HDRLEN, m,
- BPF_DIRECTION_OUT);
+#ifndef __FreeBSD__
+ m1.m_next = m;
+ m1.m_len = PFLOG_HDRLEN;
+ m1.m_data = (char *) &hdr;
+#endif
+
+#ifdef __FreeBSD__
+ KASSERT((!LIST_EMPTY(&pflog_list)), ("pflog: no interface"));
+ ifn = SCP2IFP(LIST_FIRST(&pflog_list));
+ BPF_MTAP2(ifn, &hdr, sizeof(hdr), m);
+#else
+ ifn = &(pflogif[0].sc_if);
+
+ if (ifn->if_bpf)
+ bpf_mtap(ifn->if_bpf, &m1);
+#endif
#endif
return (0);
}
+
+#ifdef __FreeBSD__
+static int
+pflog_modevent(module_t mod, int type, void *data)
+{
+ int error = 0;
+
+ switch (type) {
+ case MOD_LOAD:
+ LIST_INIT(&pflog_list);
+ if_clone_attach(&pflog_cloner);
+ PF_LOCK();
+ pflog_packet_ptr = pflog_packet;
+ PF_UNLOCK();
+ break;
+
+ case MOD_UNLOAD:
+ PF_LOCK();
+ pflog_packet_ptr = NULL;
+ PF_UNLOCK();
+ if_clone_detach(&pflog_cloner);
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return error;
+}
+
+static moduledata_t pflog_mod = {
+ "pflog",
+ pflog_modevent,
+ 0
+};
+
+#define PFLOG_MODVER 1
+
+DECLARE_MODULE(pflog, pflog_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
+MODULE_VERSION(pflog, PFLOG_MODVER);
+MODULE_DEPEND(pflog, pf, PF_MODVER, PF_MODVER, PF_MODVER);
+#endif /* __FreeBSD__ */
diff --git a/sys/contrib/pf/net/if_pflog.h b/sys/contrib/pf/net/if_pflog.h
index e9e0b01..4e160a7 100644
--- a/sys/contrib/pf/net/if_pflog.h
+++ b/sys/contrib/pf/net/if_pflog.h
@@ -1,4 +1,6 @@
-/* $OpenBSD: if_pflog.h,v 1.14 2006/10/25 11:27:01 henning Exp $ */
+/* $FreeBSD$ */
+/* $OpenBSD: if_pflog.h,v 1.11 2004/05/19 17:50:51 dhartmei Exp $ */
+
/*
* Copyright 2001 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -27,12 +29,13 @@
#ifndef _NET_IF_PFLOG_H_
#define _NET_IF_PFLOG_H_
-#define PFLOGIFS_MAX 16
-
struct pflog_softc {
- struct ifnet sc_if; /* the interface */
- int sc_unit;
- LIST_ENTRY(pflog_softc) sc_list;
+#ifdef __FreeBSD__
+ struct ifnet *sc_ifp; /* the interface */
+ LIST_ENTRY(pflog_softc) sc_next;
+#else
+ struct ifnet sc_if; /* the interface */
+#endif
};
#define PFLOG_RULESET_NAME_SIZE 16
@@ -46,10 +49,6 @@ struct pfloghdr {
char ruleset[PFLOG_RULESET_NAME_SIZE];
u_int32_t rulenr;
u_int32_t subrulenr;
- uid_t uid;
- pid_t pid;
- uid_t rule_uid;
- pid_t rule_pid;
u_int8_t dir;
u_int8_t pad[3];
};
@@ -71,10 +70,25 @@ struct old_pfloghdr {
#ifdef _KERNEL
+#ifdef __FreeBSD__
+struct pf_rule;
+struct pf_ruleset;
+struct pfi_kif;
+
+typedef int pflog_packet_t(struct pfi_kif *, struct mbuf *, sa_family_t,
+ u_int8_t, u_int8_t, struct pf_rule *, struct pf_rule *,
+ struct pf_ruleset *);
+extern pflog_packet_t *pflog_packet_ptr;
+#define PFLOG_PACKET(i,x,a,b,c,d,e,f,g) do { \
+ if (pflog_packet_ptr != NULL) \
+ pflog_packet_ptr(i,a,b,c,d,e,f,g); \
+} while (0)
+#else
#if NPFLOG > 0
-#define PFLOG_PACKET(i,x,a,b,c,d,e,f,g,h) pflog_packet(i,a,b,c,d,e,f,g,h)
+#define PFLOG_PACKET(i,x,a,b,c,d,e,f,g) pflog_packet(i,a,b,c,d,e,f,g)
#else
-#define PFLOG_PACKET(i,x,a,b,c,d,e,f,g,h) ((void)0)
+#define PFLOG_PACKET(i,x,a,b,c,d,e,f,g) ((void)0)
#endif /* NPFLOG > 0 */
+#endif /* __FreeBSD__ */
#endif /* _KERNEL */
#endif /* _NET_IF_PFLOG_H_ */
diff --git a/sys/contrib/pf/net/if_pfsync.c b/sys/contrib/pf/net/if_pfsync.c
index 1106339..0f5c344 100644
--- a/sys/contrib/pf/net/if_pfsync.c
+++ b/sys/contrib/pf/net/if_pfsync.c
@@ -1,4 +1,5 @@
-/* $OpenBSD: if_pfsync.c,v 1.73 2006/11/16 13:13:38 henning Exp $ */
+/* $FreeBSD$ */
+/* $OpenBSD: if_pfsync.c,v 1.46 2005/02/20 15:58:38 mcbride Exp $ */
/*
* Copyright (c) 2002 Michael Shalayeff
@@ -26,27 +27,67 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
+#ifdef __FreeBSD__
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#endif
+
+#ifndef __FreeBSD__
+#include "bpfilter.h"
+#include "pfsync.h"
+#elif __FreeBSD__ >= 5
+#include "opt_bpf.h"
+#include "opt_pf.h"
+
+#ifdef DEV_BPF
+#define NBPFILTER DEV_BPF
+#else
+#define NBPFILTER 0
+#endif
+
+#ifdef DEV_PFSYNC
+#define NPFSYNC DEV_PFSYNC
+#else
+#define NPFSYNC 0
+#endif
+
+#endif
#include <sys/param.h>
+#ifdef __FreeBSD__
+#include <sys/priv.h>
+#endif
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
+#include <sys/kernel.h>
+#ifdef __FreeBSD__
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/sockio.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
+#else
#include <sys/ioctl.h>
#include <sys/timeout.h>
-#include <sys/kernel.h>
+#endif
#include <net/if.h>
+#if defined(__FreeBSD__)
+#include <net/if_clone.h>
+#endif
#include <net/if_types.h>
#include <net/route.h>
#include <net/bpf.h>
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
#include <netinet/tcp.h>
#include <netinet/tcp_seq.h>
#ifdef INET
+#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
@@ -54,19 +95,32 @@
#endif
#ifdef INET6
+#ifndef INET
+#include <netinet/in.h>
+#endif
#include <netinet6/nd6.h>
#endif /* INET6 */
+#ifdef __FreeBSD__
+#include "opt_carp.h"
+#ifdef DEV_CARP
+#define NCARP 1
+#else
+#define NCARP 0
+#endif
+#else
#include "carp.h"
+#endif
#if NCARP > 0
-#include <netinet/ip_carp.h>
+extern int carp_suppress_preempt;
#endif
#include <net/pfvar.h>
#include <net/if_pfsync.h>
-#include "bpfilter.h"
-#include "pfsync.h"
+#ifdef __FreeBSD__
+#define PFSYNCNAME "pfsync"
+#endif
#define PFSYNC_MINMTU \
(sizeof(struct pfsync_header) + sizeof(struct pf_state))
@@ -78,17 +132,32 @@ int pfsyncdebug;
#define DPRINTF(x)
#endif
-struct pfsync_softc *pfsyncif = NULL;
-struct pfsyncstats pfsyncstats;
+#ifndef __FreeBSD__
+struct pfsync_softc pfsyncif;
+#endif
+struct pfsyncstats pfsyncstats;
+#ifdef __FreeBSD__
+SYSCTL_DECL(_net_inet_pfsync);
+SYSCTL_STRUCT(_net_inet_pfsync, 0, stats, CTLFLAG_RW,
+ &pfsyncstats, pfsyncstats,
+ "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)");
+/*
+ * Locking notes:
+ * Whenever we really touch/look at the state table we have to hold the
+ * PF_LOCK. Functions that do just the interface handling, grab the per
+ * softc lock instead.
+ *
+ */
+
+static void pfsync_clone_destroy(struct ifnet *);
+static int pfsync_clone_create(struct if_clone *, int, caddr_t params);
+static void pfsync_senddef(void *);
+#else
void pfsyncattach(int);
-int pfsync_clone_create(struct if_clone *, int);
-int pfsync_clone_destroy(struct ifnet *);
+#endif
void pfsync_setmtu(struct pfsync_softc *, int);
-int pfsync_alloc_scrub_memory(struct pfsync_state_peer *,
- struct pf_state_peer *);
-int pfsync_insert_net_state(struct pfsync_state *, u_int8_t);
-void pfsync_update_net_tdb(struct pfsync_tdb *);
+int pfsync_insert_net_state(struct pfsync_state *);
int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
int pfsyncioctl(struct ifnet *, u_long, caddr_t);
@@ -97,89 +166,160 @@ void pfsyncstart(struct ifnet *);
struct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **);
int pfsync_request_update(struct pfsync_state_upd *, struct in_addr *);
int pfsync_sendout(struct pfsync_softc *);
-int pfsync_tdb_sendout(struct pfsync_softc *);
-int pfsync_sendout_mbuf(struct pfsync_softc *, struct mbuf *);
void pfsync_timeout(void *);
-void pfsync_tdb_timeout(void *);
void pfsync_send_bus(struct pfsync_softc *, u_int8_t);
void pfsync_bulk_update(void *);
void pfsync_bulkfail(void *);
+#ifdef __FreeBSD__
+static void pfsync_ifdetach(void *, struct ifnet *);
+#endif
int pfsync_sync_ok;
+#ifndef __FreeBSD__
extern int ifqmaxlen;
+extern struct timeval time;
+extern struct timeval mono_time;
+extern int hz;
+#endif
-struct if_clone pfsync_cloner =
- IF_CLONE_INITIALIZER("pfsync", pfsync_clone_create, pfsync_clone_destroy);
+#ifdef __FreeBSD__
+static MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface");
+static LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list;
+#define SCP2IFP(sc) ((sc)->sc_ifp)
+IFC_SIMPLE_DECLARE(pfsync, 1);
-void
-pfsyncattach(int npfsync)
+static void
+pfsync_clone_destroy(struct ifnet *ifp)
{
- if_clone_attach(&pfsync_cloner);
+ struct pfsync_softc *sc;
+
+ sc = ifp->if_softc;
+#ifdef __FreeBSD__
+ EVENTHANDLER_DEREGISTER(ifnet_departure_event, sc->sc_detachtag);
+#endif
+ callout_stop(&sc->sc_tmo);
+ callout_stop(&sc->sc_bulk_tmo);
+ callout_stop(&sc->sc_bulkfail_tmo);
+
+ callout_stop(&sc->sc_send_tmo);
+
+#if NBPFILTER > 0
+ bpfdetach(ifp);
+#endif
+ if_detach(ifp);
+ if_free(ifp);
+ LIST_REMOVE(sc, sc_next);
+ free(sc->sc_imo.imo_membership, M_PFSYNC);
+ free(sc, M_PFSYNC);
}
-int
+
+static int
+#ifdef __FreeBSD__
+pfsync_clone_create(struct if_clone *ifc, int unit, caddr_t params)
+#else
pfsync_clone_create(struct if_clone *ifc, int unit)
+#endif
{
+ struct pfsync_softc *sc;
struct ifnet *ifp;
- if (unit != 0)
- return (EINVAL);
+ MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC,
+ M_WAITOK|M_ZERO);
+ ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC);
+ if (ifp == NULL) {
+ free(sc, M_PFSYNC);
+ return (ENOSPC);
+ }
+
+#ifdef __FreeBSD__
+ sc->sc_detachtag = EVENTHANDLER_REGISTER(ifnet_departure_event,
+ pfsync_ifdetach, sc, EVENTHANDLER_PRI_ANY);
+ if (sc->sc_detachtag == NULL) {
+ if_free(ifp);
+ free(sc, M_PFSYNC);
+ return (ENOSPC);
+ }
+#endif
pfsync_sync_ok = 1;
- if ((pfsyncif = malloc(sizeof(*pfsyncif), M_DEVBUF, M_NOWAIT)) == NULL)
- return (ENOMEM);
- bzero(pfsyncif, sizeof(*pfsyncif));
- pfsyncif->sc_mbuf = NULL;
- pfsyncif->sc_mbuf_net = NULL;
- pfsyncif->sc_mbuf_tdb = NULL;
- pfsyncif->sc_statep.s = NULL;
- pfsyncif->sc_statep_net.s = NULL;
- pfsyncif->sc_statep_tdb.t = NULL;
- pfsyncif->sc_maxupdates = 128;
- pfsyncif->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
- pfsyncif->sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
- pfsyncif->sc_ureq_received = 0;
- pfsyncif->sc_ureq_sent = 0;
- pfsyncif->sc_bulk_send_next = NULL;
- pfsyncif->sc_bulk_terminator = NULL;
- ifp = &pfsyncif->sc_if;
- snprintf(ifp->if_xname, sizeof ifp->if_xname, "pfsync%d", unit);
- ifp->if_softc = pfsyncif;
+ sc->sc_mbuf = NULL;
+ sc->sc_mbuf_net = NULL;
+ sc->sc_statep.s = NULL;
+ sc->sc_statep_net.s = NULL;
+ sc->sc_maxupdates = 128;
+ sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP);
+ sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP);
+ sc->sc_ureq_received = 0;
+ sc->sc_ureq_sent = 0;
+ sc->sc_imo.imo_membership = (struct in_multi **)malloc(
+ (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_PFSYNC,
+ M_WAITOK);
+ sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS;
+
+ ifp = SCP2IFP(sc);
+ if_initname(ifp, ifc->ifc_name, unit);
ifp->if_ioctl = pfsyncioctl;
ifp->if_output = pfsyncoutput;
ifp->if_start = pfsyncstart;
- ifp->if_type = IFT_PFSYNC;
ifp->if_snd.ifq_maxlen = ifqmaxlen;
ifp->if_hdrlen = PFSYNC_HDRLEN;
- pfsync_setmtu(pfsyncif, ETHERMTU);
- timeout_set(&pfsyncif->sc_tmo, pfsync_timeout, pfsyncif);
- timeout_set(&pfsyncif->sc_tdb_tmo, pfsync_tdb_timeout, pfsyncif);
- timeout_set(&pfsyncif->sc_bulk_tmo, pfsync_bulk_update, pfsyncif);
- timeout_set(&pfsyncif->sc_bulkfail_tmo, pfsync_bulkfail, pfsyncif);
+ ifp->if_baudrate = IF_Mbps(100);
+ ifp->if_softc = sc;
+ pfsync_setmtu(sc, MCLBYTES);
+ callout_init(&sc->sc_tmo, NET_CALLOUT_MPSAFE);
+ callout_init(&sc->sc_bulk_tmo, NET_CALLOUT_MPSAFE);
+ callout_init(&sc->sc_bulkfail_tmo, NET_CALLOUT_MPSAFE);
+ callout_init(&sc->sc_send_tmo, NET_CALLOUT_MPSAFE);
+ sc->sc_ifq.ifq_maxlen = ifqmaxlen;
+ mtx_init(&sc->sc_ifq.ifq_mtx, ifp->if_xname, "pfsync send queue",
+ MTX_DEF);
if_attach(ifp);
- if_alloc_sadl(ifp);
-
-#if NCARP > 0
- if_addgroup(ifp, "carp");
-#endif
+ LIST_INSERT_HEAD(&pfsync_list, sc, sc_next);
#if NBPFILTER > 0
- bpfattach(&pfsyncif->sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
+ bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
#endif
return (0);
}
-
-int
-pfsync_clone_destroy(struct ifnet *ifp)
+#else /* !__FreeBSD__ */
+void
+pfsyncattach(int npfsync)
{
+ struct ifnet *ifp;
+
+ pfsync_sync_ok = 1;
+ bzero(&pfsyncif, sizeof(pfsyncif));
+ pfsyncif.sc_mbuf = NULL;
+ pfsyncif.sc_mbuf_net = NULL;
+ pfsyncif.sc_statep.s = NULL;
+ pfsyncif.sc_statep_net.s = NULL;
+ pfsyncif.sc_maxupdates = 128;
+ pfsyncif.sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
+ pfsyncif.sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
+ pfsyncif.sc_ureq_received = 0;
+ pfsyncif.sc_ureq_sent = 0;
+ ifp = &pfsyncif.sc_if;
+ strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname);
+ ifp->if_softc = &pfsyncif;
+ ifp->if_ioctl = pfsyncioctl;
+ ifp->if_output = pfsyncoutput;
+ ifp->if_start = pfsyncstart;
+ ifp->if_type = IFT_PFSYNC;
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+ ifp->if_hdrlen = PFSYNC_HDRLEN;
+ pfsync_setmtu(&pfsyncif, MCLBYTES);
+ timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif);
+ timeout_set(&pfsyncif.sc_bulk_tmo, pfsync_bulk_update, &pfsyncif);
+ timeout_set(&pfsyncif.sc_bulkfail_tmo, pfsync_bulkfail, &pfsyncif);
+ if_attach(ifp);
+ if_alloc_sadl(ifp);
+
#if NBPFILTER > 0
- bpfdetach(ifp);
+ bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
#endif
- if_detach(ifp);
- free(pfsyncif, M_DEVBUF);
- pfsyncif = NULL;
- return (0);
}
+#endif
/*
* Start output on the pfsync interface.
@@ -187,11 +327,17 @@ pfsync_clone_destroy(struct ifnet *ifp)
void
pfsyncstart(struct ifnet *ifp)
{
+#ifdef __FreeBSD__
+ IF_LOCK(&ifp->if_snd);
+ _IF_DROP(&ifp->if_snd);
+ _IF_DRAIN(&ifp->if_snd);
+ IF_UNLOCK(&ifp->if_snd);
+#else
struct mbuf *m;
int s;
for (;;) {
- s = splnet();
+ s = splimp();
IF_DROP(&ifp->if_snd);
IF_DEQUEUE(&ifp->if_snd, m);
splx(s);
@@ -201,36 +347,26 @@ pfsyncstart(struct ifnet *ifp)
else
m_freem(m);
}
+#endif
}
int
-pfsync_alloc_scrub_memory(struct pfsync_state_peer *s,
- struct pf_state_peer *d)
-{
- if (s->scrub.scrub_flag && d->scrub == NULL) {
- d->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT);
- if (d->scrub == NULL)
- return (ENOMEM);
- bzero(d->scrub, sizeof(*d->scrub));
- }
-
- return (0);
-}
-
-int
-pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag)
+pfsync_insert_net_state(struct pfsync_state *sp)
{
struct pf_state *st = NULL;
struct pf_rule *r = NULL;
struct pfi_kif *kif;
+#ifdef __FreeBSD__
+ PF_ASSERT(MA_OWNED);
+#endif
if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) {
printf("pfsync_insert_net_state: invalid creator id:"
" %08x\n", ntohl(sp->creatorid));
return (EINVAL);
}
- kif = pfi_kif_get(sp->ifname);
+ kif = pfi_lookup_create(sp->ifname);
if (kif == NULL) {
if (pf_status.debug >= PF_DEBUG_MISC)
printf("pfsync_insert_net_state: "
@@ -240,33 +376,19 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag)
}
/*
- * If the ruleset checksums match, it's safe to associate the state
- * with the rule of that number.
+ * Just use the default rule until we have infrastructure to find the
+ * best matching rule.
*/
- if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && chksum_flag)
- r = pf_main_ruleset.rules[
- PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)];
- else
- r = &pf_default_rule;
+ r = &pf_default_rule;
if (!r->max_states || r->states < r->max_states)
st = pool_get(&pf_state_pl, PR_NOWAIT);
if (st == NULL) {
- pfi_kif_unref(kif, PFI_KIF_REF_NONE);
+ pfi_maybe_destroy(kif);
return (ENOMEM);
}
bzero(st, sizeof(*st));
- /* allocate memory for scrub info */
- if (pfsync_alloc_scrub_memory(&sp->src, &st->src) ||
- pfsync_alloc_scrub_memory(&sp->dst, &st->dst)) {
- pfi_kif_unref(kif, PFI_KIF_REF_NONE);
- if (st->src.scrub)
- pool_put(&pf_state_scrub_pl, st->src.scrub);
- pool_put(&pf_state_pl, st);
- return (ENOMEM);
- }
-
st->rule.ptr = r;
/* XXX get pointers to nat_rule and anchor */
@@ -296,14 +418,11 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag)
st->creatorid = sp->creatorid;
st->sync_flags = PFSTATE_FROMSYNC;
+
if (pf_insert_state(kif, st)) {
- pfi_kif_unref(kif, PFI_KIF_REF_NONE);
+ pfi_maybe_destroy(kif);
/* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */
r->states--;
- if (st->dst.scrub)
- pool_put(&pf_state_scrub_pl, st->dst.scrub);
- if (st->src.scrub)
- pool_put(&pf_state_scrub_pl, st->src.scrub);
pool_put(&pf_state_pl, st);
return (EINVAL);
}
@@ -312,29 +431,34 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag)
}
void
+#ifdef __FreeBSD__
+pfsync_input(struct mbuf *m, __unused int off)
+#else
pfsync_input(struct mbuf *m, ...)
+#endif
{
struct ip *ip = mtod(m, struct ip *);
struct pfsync_header *ph;
- struct pfsync_softc *sc = pfsyncif;
- struct pf_state *st;
- struct pf_state_cmp key;
+#ifdef __FreeBSD__
+ struct pfsync_softc *sc = LIST_FIRST(&pfsync_list);
+#else
+ struct pfsync_softc *sc = &pfsyncif;
+#endif
+ struct pf_state *st, key;
struct pfsync_state *sp;
struct pfsync_state_upd *up;
struct pfsync_state_del *dp;
struct pfsync_state_clr *cp;
struct pfsync_state_upd_req *rup;
struct pfsync_state_bus *bus;
- struct pfsync_tdb *pt;
struct in_addr src;
struct mbuf *mp;
int iplen, action, error, i, s, count, offp, sfail, stale = 0;
- u_int8_t chksum_flag = 0;
pfsyncstats.pfsyncs_ipackets++;
/* verify that we have a sync interface configured */
- if (!sc || !sc->sc_sync_ifp || !pf_status.running)
+ if (!sc->sc_sync_ifp || !pf_status.running) /* XXX PF_LOCK? */
goto done;
/* verify that the packet came in on the right interface */
@@ -383,9 +507,6 @@ pfsync_input(struct mbuf *m, ...)
/* Cheaper to grab this now than having to mess with mbufs later */
src = ip->ip_src;
- if (!bcmp(&ph->pf_chksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH))
- chksum_flag++;
-
switch (action) {
case PFSYNC_ACT_CLR: {
struct pf_state *nexts;
@@ -400,30 +521,43 @@ pfsync_input(struct mbuf *m, ...)
creatorid = cp->creatorid;
s = splsoftnet();
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
if (cp->ifname[0] == '\0') {
for (st = RB_MIN(pf_state_tree_id, &tree_id);
st; st = nexts) {
- nexts = RB_NEXT(pf_state_tree_id, &tree_id, st);
+ nexts = RB_NEXT(pf_state_tree_id, &tree_id, st);
if (st->creatorid == creatorid) {
- st->sync_flags |= PFSTATE_FROMSYNC;
- pf_unlink_state(st);
+ st->timeout = PFTM_PURGE;
+ pf_purge_expired_state(st);
}
}
} else {
- if ((kif = pfi_kif_get(cp->ifname)) == NULL) {
+ kif = pfi_lookup_if(cp->ifname);
+ if (kif == NULL) {
+ if (pf_status.debug >= PF_DEBUG_MISC)
+ printf("pfsync_input: PFSYNC_ACT_CLR "
+ "bad interface: %s\n", cp->ifname);
splx(s);
- return;
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
+ goto done;
}
for (st = RB_MIN(pf_state_tree_lan_ext,
&kif->pfik_lan_ext); st; st = nexts) {
nexts = RB_NEXT(pf_state_tree_lan_ext,
&kif->pfik_lan_ext, st);
if (st->creatorid == creatorid) {
- st->sync_flags |= PFSTATE_FROMSYNC;
- pf_unlink_state(st);
+ st->timeout = PFTM_PURGE;
+ pf_purge_expired_state(st);
}
}
}
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
splx(s);
break;
@@ -436,6 +570,9 @@ pfsync_input(struct mbuf *m, ...)
}
s = splsoftnet();
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
i < count; i++, sp++) {
/* check for invalid values */
@@ -451,15 +588,20 @@ pfsync_input(struct mbuf *m, ...)
continue;
}
- if ((error = pfsync_insert_net_state(sp,
- chksum_flag))) {
+ if ((error = pfsync_insert_net_state(sp))) {
if (error == ENOMEM) {
splx(s);
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
goto done;
}
continue;
}
}
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
splx(s);
break;
case PFSYNC_ACT_UPD:
@@ -470,6 +612,9 @@ pfsync_input(struct mbuf *m, ...)
}
s = splsoftnet();
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
i < count; i++, sp++) {
int flags = PFSYNC_FLAG_STALE;
@@ -491,7 +636,7 @@ pfsync_input(struct mbuf *m, ...)
st = pf_find_state_byid(&key);
if (st == NULL) {
/* insert the update */
- if (pfsync_insert_net_state(sp, chksum_flag))
+ if (pfsync_insert_net_state(sp))
pfsyncstats.pfsyncs_badstate++;
continue;
}
@@ -530,7 +675,7 @@ pfsync_input(struct mbuf *m, ...)
*/
if (st->src.state > sp->src.state)
sfail = 5;
- else if (st->dst.state > sp->dst.state)
+ else if ( st->dst.state > sp->dst.state)
sfail = 6;
}
if (sfail) {
@@ -540,7 +685,11 @@ pfsync_input(struct mbuf *m, ...)
"creatorid: %08x\n",
(sfail < 7 ? "ignoring"
: "partial"), sfail,
+#ifdef __FreeBSD__
+ (unsigned long long)be64toh(st->id),
+#else
betoh64(st->id),
+#endif
ntohl(st->creatorid));
pfsyncstats.pfsyncs_badstate++;
@@ -555,7 +704,6 @@ pfsync_input(struct mbuf *m, ...)
}
continue;
}
- pfsync_alloc_scrub_memory(&sp->dst, &st->dst);
pf_state_peer_ntoh(&sp->src, &st->src);
pf_state_peer_ntoh(&sp->dst, &st->dst);
st->expire = ntohl(sp->expire) + time_second;
@@ -563,6 +711,9 @@ pfsync_input(struct mbuf *m, ...)
}
if (stale && sc->sc_mbuf != NULL)
pfsync_sendout(sc);
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
splx(s);
break;
/*
@@ -577,6 +728,9 @@ pfsync_input(struct mbuf *m, ...)
}
s = splsoftnet();
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
i < count; i++, sp++) {
bcopy(sp->id, &key.id, sizeof(key.id));
@@ -587,9 +741,13 @@ pfsync_input(struct mbuf *m, ...)
pfsyncstats.pfsyncs_badstate++;
continue;
}
+ st->timeout = PFTM_PURGE;
st->sync_flags |= PFSTATE_FROMSYNC;
- pf_unlink_state(st);
+ pf_purge_expired_state(st);
}
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
splx(s);
break;
case PFSYNC_ACT_UPD_C: {
@@ -602,6 +760,9 @@ pfsync_input(struct mbuf *m, ...)
}
s = splsoftnet();
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp);
i < count; i++, up++) {
/* check for invalid values */
@@ -665,7 +826,11 @@ pfsync_input(struct mbuf *m, ...)
printf("pfsync: ignoring stale update "
"(%d) id: %016llx "
"creatorid: %08x\n", sfail,
+#ifdef __FreeBSD__
+ (unsigned long long)be64toh(st->id),
+#else
betoh64(st->id),
+#endif
ntohl(st->creatorid));
pfsyncstats.pfsyncs_badstate++;
@@ -681,7 +846,6 @@ pfsync_input(struct mbuf *m, ...)
PFSYNC_FLAG_STALE);
continue;
}
- pfsync_alloc_scrub_memory(&up->dst, &st->dst);
pf_state_peer_ntoh(&up->src, &st->src);
pf_state_peer_ntoh(&up->dst, &st->dst);
st->expire = ntohl(up->expire) + time_second;
@@ -689,6 +853,9 @@ pfsync_input(struct mbuf *m, ...)
}
if ((update_requested || stale) && sc->sc_mbuf)
pfsync_sendout(sc);
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
splx(s);
break;
}
@@ -700,6 +867,9 @@ pfsync_input(struct mbuf *m, ...)
}
s = splsoftnet();
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp);
i < count; i++, dp++) {
bcopy(dp->id, &key.id, sizeof(key.id));
@@ -710,9 +880,13 @@ pfsync_input(struct mbuf *m, ...)
pfsyncstats.pfsyncs_badstate++;
continue;
}
+ st->timeout = PFTM_PURGE;
st->sync_flags |= PFSTATE_FROMSYNC;
- pf_unlink_state(st);
+ pf_purge_expired_state(st);
}
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
splx(s);
break;
case PFSYNC_ACT_INS_F:
@@ -727,6 +901,9 @@ pfsync_input(struct mbuf *m, ...)
}
s = splsoftnet();
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
if (sc->sc_mbuf != NULL)
pfsync_sendout(sc);
for (i = 0,
@@ -737,15 +914,17 @@ pfsync_input(struct mbuf *m, ...)
if (key.id == 0 && key.creatorid == 0) {
sc->sc_ureq_received = time_uptime;
- if (sc->sc_bulk_send_next == NULL)
- sc->sc_bulk_send_next =
- TAILQ_FIRST(&state_list);
- sc->sc_bulk_terminator = sc->sc_bulk_send_next;
if (pf_status.debug >= PF_DEBUG_MISC)
printf("pfsync: received "
"bulk update request\n");
pfsync_send_bus(sc, PFSYNC_BUS_START);
+#ifdef __FreeBSD__
+ callout_reset(&sc->sc_bulk_tmo, 1 * hz,
+ pfsync_bulk_update,
+ LIST_FIRST(&pfsync_list));
+#else
timeout_add(&sc->sc_bulk_tmo, 1 * hz);
+#endif
} else {
st = pf_find_state_byid(&key);
if (st == NULL) {
@@ -759,6 +938,9 @@ pfsync_input(struct mbuf *m, ...)
}
if (sc->sc_mbuf != NULL)
pfsync_sendout(sc);
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
splx(s);
break;
case PFSYNC_ACT_BUS:
@@ -774,9 +956,16 @@ pfsync_input(struct mbuf *m, ...)
bus = (struct pfsync_state_bus *)(mp->m_data + offp);
switch (bus->status) {
case PFSYNC_BUS_START:
+#ifdef __FreeBSD__
+ callout_reset(&sc->sc_bulkfail_tmo,
+ pf_pool_limits[PF_LIMIT_STATES].limit /
+ (PFSYNC_BULKPACKETS * sc->sc_maxcount),
+ pfsync_bulkfail, LIST_FIRST(&pfsync_list));
+#else
timeout_add(&sc->sc_bulkfail_tmo,
pf_pool_limits[PF_LIMIT_STATES].limit /
(PFSYNC_BULKPACKETS * sc->sc_maxcount));
+#endif
if (pf_status.debug >= PF_DEBUG_MISC)
printf("pfsync: received bulk "
"update start\n");
@@ -787,10 +976,14 @@ pfsync_input(struct mbuf *m, ...)
/* that's it, we're happy */
sc->sc_ureq_sent = 0;
sc->sc_bulk_tries = 0;
+#ifdef __FreeBSD__
+ callout_stop(&sc->sc_bulkfail_tmo);
+#else
timeout_del(&sc->sc_bulkfail_tmo);
-#if NCARP > 0
+#endif
+#if NCARP > 0 /* XXX_IMPORT */
if (!pfsync_sync_ok)
- carp_group_demote_adj(&sc->sc_if, -1);
+ carp_suppress_preempt--;
#endif
pfsync_sync_ok = 1;
if (pf_status.debug >= PF_DEBUG_MISC)
@@ -804,18 +997,6 @@ pfsync_input(struct mbuf *m, ...)
break;
}
break;
- case PFSYNC_ACT_TDB_UPD:
- if ((mp = m_pulldown(m, iplen + sizeof(*ph),
- count * sizeof(*pt), &offp)) == NULL) {
- pfsyncstats.pfsyncs_badlen++;
- return;
- }
- s = splsoftnet();
- for (i = 0, pt = (struct pfsync_tdb *)(mp->m_data + offp);
- i < count; i++, pt++)
- pfsync_update_net_tdb(pt);
- splx(s);
- break;
}
done:
@@ -835,7 +1016,9 @@ pfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
int
pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
+#ifndef __FreeBSD__
struct proc *p = curproc;
+#endif
struct pfsync_softc *sc = ifp->if_softc;
struct ifreq *ifr = (struct ifreq *)data;
struct ip_moptions *imo = &sc->sc_imo;
@@ -848,10 +1031,17 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
case SIOCAIFADDR:
case SIOCSIFDSTADDR:
case SIOCSIFFLAGS:
+#ifdef __FreeBSD__
+ if (ifp->if_flags & IFF_UP)
+ ifp->if_drv_flags |= IFF_DRV_RUNNING;
+ else
+ ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+#else
if (ifp->if_flags & IFF_UP)
ifp->if_flags |= IFF_RUNNING;
else
ifp->if_flags &= ~IFF_RUNNING;
+#endif
break;
case SIOCSIFMTU:
if (ifr->ifr_mtu < PFSYNC_MINMTU)
@@ -859,12 +1049,22 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if (ifr->ifr_mtu > MCLBYTES)
ifr->ifr_mtu = MCLBYTES;
s = splnet();
- if (ifr->ifr_mtu < ifp->if_mtu)
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
+ if (ifr->ifr_mtu < ifp->if_mtu) {
pfsync_sendout(sc);
+ }
pfsync_setmtu(sc, ifr->ifr_mtu);
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
splx(s);
break;
case SIOCGETPFSYNC:
+#ifdef __FreeBSD__
+ /* XXX: read unlocked */
+#endif
bzero(&pfsyncr, sizeof(pfsyncr));
if (sc->sc_sync_ifp)
strlcpy(pfsyncr.pfsyncr_syncdev,
@@ -875,19 +1075,31 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
return (error);
break;
case SIOCSETPFSYNC:
+#ifdef __FreeBSD__
+ if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0)
+#else
if ((error = suser(p, p->p_acflag)) != 0)
+#endif
return (error);
if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr))))
return (error);
if (pfsyncr.pfsyncr_syncpeer.s_addr == 0)
+#ifdef __FreeBSD__
+ sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP);
+#else
sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
+#endif
else
sc->sc_sync_peer.s_addr =
pfsyncr.pfsyncr_syncpeer.s_addr;
if (pfsyncr.pfsyncr_maxupdates > 255)
return (EINVAL);
+#ifdef __FreeBSD__
+ callout_drain(&sc->sc_send_tmo);
+ PF_LOCK();
+#endif
sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
if (pfsyncr.pfsyncr_syncdev[0] == 0) {
@@ -904,21 +1116,36 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
imo->imo_multicast_ifp = NULL;
}
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
break;
}
- if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL)
+ if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) {
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
return (EINVAL);
+ }
s = splnet();
+#ifdef __FreeBSD__
+ if (sifp->if_mtu < SCP2IFP(sc)->if_mtu ||
+#else
if (sifp->if_mtu < sc->sc_if.if_mtu ||
+#endif
(sc->sc_sync_ifp != NULL &&
sifp->if_mtu < sc->sc_sync_ifp->if_mtu) ||
sifp->if_mtu < MCLBYTES - sizeof(struct ip))
pfsync_sendout(sc);
sc->sc_sync_ifp = sifp;
+#ifdef __FreeBSD__
+ pfsync_setmtu(sc, SCP2IFP(sc)->if_mtu);
+#else
pfsync_setmtu(sc, sc->sc_if.if_mtu);
+#endif
if (imo->imo_num_memberships > 0) {
in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
@@ -926,16 +1153,27 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
}
if (sc->sc_sync_ifp &&
+#ifdef __FreeBSD__
+ sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) {
+#else
sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
+#endif
struct in_addr addr;
if (!(sc->sc_sync_ifp->if_flags & IFF_MULTICAST)) {
sc->sc_sync_ifp = NULL;
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
splx(s);
return (EADDRNOTAVAIL);
}
-
+#ifdef __FreeBSD__
+ PF_UNLOCK(); /* addmulti mallocs w/ WAITOK */
+ addr.s_addr = htonl(INADDR_PFSYNC_GROUP);
+#else
addr.s_addr = INADDR_PFSYNC_GROUP;
+#endif
if ((imo->imo_membership[0] =
in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) {
@@ -947,27 +1185,45 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
imo->imo_multicast_ifp = sc->sc_sync_ifp;
imo->imo_multicast_ttl = PFSYNC_DFLTTL;
imo->imo_multicast_loop = 0;
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
}
if (sc->sc_sync_ifp ||
+#ifdef __FreeBSD__
+ sc->sc_sendaddr.s_addr != htonl(INADDR_PFSYNC_GROUP)) {
+#else
sc->sc_sendaddr.s_addr != INADDR_PFSYNC_GROUP) {
+#endif
/* Request a full state table update. */
sc->sc_ureq_sent = time_uptime;
#if NCARP > 0
if (pfsync_sync_ok)
- carp_group_demote_adj(&sc->sc_if, 1);
+ carp_suppress_preempt++;
#endif
pfsync_sync_ok = 0;
if (pf_status.debug >= PF_DEBUG_MISC)
printf("pfsync: requesting bulk update\n");
+#ifdef __FreeBSD__
+ callout_reset(&sc->sc_bulkfail_tmo, 5 * hz,
+ pfsync_bulkfail, LIST_FIRST(&pfsync_list));
+#else
timeout_add(&sc->sc_bulkfail_tmo, 5 * hz);
+#endif
error = pfsync_request_update(NULL, NULL);
if (error == ENOMEM) {
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
splx(s);
return (ENOMEM);
}
pfsync_sendout(sc);
}
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
splx(s);
break;
@@ -993,8 +1249,13 @@ pfsync_setmtu(struct pfsync_softc *sc, int mtu_req)
sizeof(struct pfsync_state);
if (sc->sc_maxcount > 254)
sc->sc_maxcount = 254;
+#ifdef __FreeBSD__
+ SCP2IFP(sc)->if_mtu = sizeof(struct pfsync_header) +
+ sc->sc_maxcount * sizeof(struct pfsync_state);
+#else
sc->sc_if.if_mtu = sizeof(struct pfsync_header) +
sc->sc_maxcount * sizeof(struct pfsync_state);
+#endif
}
struct mbuf *
@@ -1004,9 +1265,16 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
struct mbuf *m;
int len;
+#ifdef __FreeBSD__
+ PF_ASSERT(MA_OWNED);
+#endif
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL) {
+#ifdef __FreeBSD__
+ SCP2IFP(sc)->if_oerrors++;
+#else
sc->sc_if.if_oerrors++;
+#endif
return (NULL);
}
@@ -1031,10 +1299,6 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
len = sizeof(struct pfsync_header) +
sizeof(struct pfsync_state_bus);
break;
- case PFSYNC_ACT_TDB_UPD:
- len = (sc->sc_maxcount * sizeof(struct pfsync_tdb)) +
- sizeof(struct pfsync_header);
- break;
default:
len = (sc->sc_maxcount * sizeof(struct pfsync_state)) +
sizeof(struct pfsync_header);
@@ -1045,7 +1309,11 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
MCLGET(m, M_DONTWAIT);
if ((m->m_flags & M_EXT) == 0) {
m_free(m);
+#ifdef __FreeBSD__
+ SCP2IFP(sc)->if_oerrors++;
+#else
sc->sc_if.if_oerrors++;
+#endif
return (NULL);
}
m->m_data += (MCLBYTES - len) &~ (sizeof(long) - 1);
@@ -1059,23 +1327,26 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
h->af = 0;
h->count = 0;
h->action = action;
- if (action != PFSYNC_ACT_TDB_UPD)
- bcopy(&pf_status.pf_chksum, &h->pf_chksum,
- PF_MD5_DIGEST_LENGTH);
*sp = (void *)((char *)h + PFSYNC_HDRLEN);
- if (action == PFSYNC_ACT_TDB_UPD)
- timeout_add(&sc->sc_tdb_tmo, hz);
- else
- timeout_add(&sc->sc_tmo, hz);
+#ifdef __FreeBSD__
+ callout_reset(&sc->sc_tmo, hz, pfsync_timeout,
+ LIST_FIRST(&pfsync_list));
+#else
+ timeout_add(&sc->sc_tmo, hz);
+#endif
return (m);
}
int
pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
{
- struct ifnet *ifp = NULL;
- struct pfsync_softc *sc = pfsyncif;
+#ifdef __FreeBSD__
+ struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
+#else
+ struct ifnet *ifp = &pfsyncif.sc_if;
+#endif
+ struct pfsync_softc *sc = ifp->if_softc;
struct pfsync_header *h, *h_net;
struct pfsync_state *sp = NULL;
struct pfsync_state_upd *up = NULL;
@@ -1085,16 +1356,19 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
int s, ret = 0;
u_int8_t i = 255, newaction = 0;
- if (sc == NULL)
- return (0);
- ifp = &sc->sc_if;
-
+#ifdef __FreeBSD__
+ PF_ASSERT(MA_OWNED);
+#endif
/*
* If a packet falls in the forest and there's nobody around to
* hear, does it make a sound?
*/
if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL &&
+#ifdef __FreeBSD__
+ sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) {
+#else
sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
+#endif
/* Don't leave any stale pfsync packets hanging around. */
if (sc->sc_mbuf != NULL) {
m_freem(sc->sc_mbuf);
@@ -1151,6 +1425,8 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
secs = time_second;
st->pfsync_time = time_uptime;
+ TAILQ_REMOVE(&state_updates, st, u.s.entry_updates);
+ TAILQ_INSERT_TAIL(&state_updates, st, u.s.entry_updates);
if (sp == NULL) {
/* not a "duplicate" update */
@@ -1172,10 +1448,10 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
sp->creation = htonl(secs - st->creation);
- pf_state_counter_hton(st->packets[0], sp->packets[0]);
- pf_state_counter_hton(st->packets[1], sp->packets[1]);
- pf_state_counter_hton(st->bytes[0], sp->bytes[0]);
- pf_state_counter_hton(st->bytes[1], sp->bytes[1]);
+ sp->packets[0] = htonl(st->packets[0]);
+ sp->packets[1] = htonl(st->packets[1]);
+ sp->bytes[0] = htonl(st->bytes[0]);
+ sp->bytes[1] = htonl(st->bytes[1]);
if ((r = st->rule.ptr) == NULL)
sp->rule = htonl(-1);
else
@@ -1274,16 +1550,19 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
int
pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src)
{
- struct ifnet *ifp = NULL;
+#ifdef __FreeBSD__
+ struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
+#else
+ struct ifnet *ifp = &pfsyncif.sc_if;
+#endif
struct pfsync_header *h;
- struct pfsync_softc *sc = pfsyncif;
+ struct pfsync_softc *sc = ifp->if_softc;
struct pfsync_state_upd_req *rup;
int ret = 0;
- if (sc == NULL)
- return (0);
-
- ifp = &sc->sc_if;
+#ifdef __FreeBSD__
+ PF_ASSERT(MA_OWNED);
+#endif
if (sc->sc_mbuf == NULL) {
if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
(void *)&sc->sc_statep.s)) == NULL)
@@ -1320,16 +1599,19 @@ pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src)
int
pfsync_clear_states(u_int32_t creatorid, char *ifname)
{
- struct ifnet *ifp = NULL;
- struct pfsync_softc *sc = pfsyncif;
+#ifdef __FreeBSD__
+ struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
+#else
+ struct ifnet *ifp = &pfsyncif.sc_if;
+#endif
+ struct pfsync_softc *sc = ifp->if_softc;
struct pfsync_state_clr *cp;
int s, ret;
- if (sc == NULL)
- return (0);
-
- ifp = &sc->sc_if;
s = splnet();
+#ifdef __FreeBSD__
+ PF_ASSERT(MA_OWNED);
+#endif
if (sc->sc_mbuf != NULL)
pfsync_sendout(sc);
if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR,
@@ -1355,18 +1637,13 @@ pfsync_timeout(void *v)
int s;
s = splnet();
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
pfsync_sendout(sc);
- splx(s);
-}
-
-void
-pfsync_tdb_timeout(void *v)
-{
- struct pfsync_softc *sc = v;
- int s;
-
- s = splnet();
- pfsync_tdb_sendout(sc);
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
splx(s);
}
@@ -1376,6 +1653,9 @@ pfsync_send_bus(struct pfsync_softc *sc, u_int8_t status)
{
struct pfsync_state_bus *bus;
+#ifdef __FreeBSD__
+ PF_ASSERT(MA_OWNED);
+#endif
if (sc->sc_mbuf != NULL)
pfsync_sendout(sc);
@@ -1398,6 +1678,9 @@ pfsync_bulk_update(void *v)
int s, i = 0;
struct pf_state *state;
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
s = splnet();
if (sc->sc_mbuf != NULL)
pfsync_sendout(sc);
@@ -1406,43 +1689,44 @@ pfsync_bulk_update(void *v)
* Grab at most PFSYNC_BULKPACKETS worth of states which have not
* been sent since the latest request was made.
*/
- state = sc->sc_bulk_send_next;
- if (state)
- do {
- /* send state update if syncable and not already sent */
- if (!state->sync_flags
- && state->timeout < PFTM_MAX
- && state->pfsync_time <= sc->sc_ureq_received) {
+ while ((state = TAILQ_FIRST(&state_updates)) != NULL &&
+ ++i < (sc->sc_maxcount * PFSYNC_BULKPACKETS)) {
+ if (state->pfsync_time > sc->sc_ureq_received) {
+ /* we're done */
+ pfsync_send_bus(sc, PFSYNC_BUS_END);
+ sc->sc_ureq_received = 0;
+#ifdef __FreeBSD__
+ callout_stop(&sc->sc_bulk_tmo);
+#else
+ timeout_del(&sc->sc_bulk_tmo);
+#endif
+ if (pf_status.debug >= PF_DEBUG_MISC)
+ printf("pfsync: bulk update complete\n");
+ break;
+ } else {
+ /* send an update and move to end of list */
+ if (!state->sync_flags)
pfsync_pack_state(PFSYNC_ACT_UPD, state, 0);
- i++;
- }
-
- /* figure next state to send */
- state = TAILQ_NEXT(state, u.s.entry_list);
-
- /* wrap to start of list if we hit the end */
- if (!state)
- state = TAILQ_FIRST(&state_list);
- } while (i < sc->sc_maxcount * PFSYNC_BULKPACKETS &&
- state != sc->sc_bulk_terminator);
-
- if (!state || state == sc->sc_bulk_terminator) {
- /* we're done */
- pfsync_send_bus(sc, PFSYNC_BUS_END);
- sc->sc_ureq_received = 0;
- sc->sc_bulk_send_next = NULL;
- sc->sc_bulk_terminator = NULL;
- timeout_del(&sc->sc_bulk_tmo);
- if (pf_status.debug >= PF_DEBUG_MISC)
- printf("pfsync: bulk update complete\n");
- } else {
- /* look again for more in a bit */
- timeout_add(&sc->sc_bulk_tmo, 1);
- sc->sc_bulk_send_next = state;
+ state->pfsync_time = time_uptime;
+ TAILQ_REMOVE(&state_updates, state, u.s.entry_updates);
+ TAILQ_INSERT_TAIL(&state_updates, state,
+ u.s.entry_updates);
+
+ /* look again for more in a bit */
+#ifdef __FreeBSD__
+ callout_reset(&sc->sc_bulk_tmo, 1, pfsync_timeout,
+ LIST_FIRST(&pfsync_list));
+#else
+ timeout_add(&sc->sc_bulk_tmo, 1);
+#endif
+ }
}
if (sc->sc_mbuf != NULL)
pfsync_sendout(sc);
splx(s);
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
}
void
@@ -1451,9 +1735,17 @@ pfsync_bulkfail(void *v)
struct pfsync_softc *sc = v;
int s, error;
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) {
/* Try again in a bit */
+#ifdef __FreeBSD__
+ callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail,
+ LIST_FIRST(&pfsync_list));
+#else
timeout_add(&sc->sc_bulkfail_tmo, 5 * hz);
+#endif
s = splnet();
error = pfsync_request_update(NULL, NULL);
if (error == ENOMEM) {
@@ -1469,26 +1761,43 @@ pfsync_bulkfail(void *v)
sc->sc_bulk_tries = 0;
#if NCARP > 0
if (!pfsync_sync_ok)
- carp_group_demote_adj(&sc->sc_if, -1);
+ carp_suppress_preempt--;
#endif
pfsync_sync_ok = 1;
if (pf_status.debug >= PF_DEBUG_MISC)
printf("pfsync: failed to receive "
"bulk update status\n");
+#ifdef __FreeBSD__
+ callout_stop(&sc->sc_bulkfail_tmo);
+#else
timeout_del(&sc->sc_bulkfail_tmo);
+#endif
}
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
}
/* This must be called in splnet() */
int
-pfsync_sendout(struct pfsync_softc *sc)
+pfsync_sendout(sc)
+ struct pfsync_softc *sc;
{
#if NBPFILTER > 0
- struct ifnet *ifp = &sc->sc_if;
+# ifdef __FreeBSD__
+ struct ifnet *ifp = SCP2IFP(sc);
+# else
+ struct ifnet *ifp = &sc->if_sc;
+# endif
#endif
struct mbuf *m;
+#ifdef __FreeBSD__
+ PF_ASSERT(MA_OWNED);
+ callout_stop(&sc->sc_tmo);
+#else
timeout_del(&sc->sc_tmo);
+#endif
if (sc->sc_mbuf == NULL)
return (0);
@@ -1496,9 +1805,16 @@ pfsync_sendout(struct pfsync_softc *sc)
sc->sc_mbuf = NULL;
sc->sc_statep.s = NULL;
+#ifdef __FreeBSD__
+ KASSERT(m != NULL, ("pfsync_sendout: null mbuf"));
+#endif
#if NBPFILTER > 0
+#ifdef __FreeBSD__
+ BPF_MTAP(ifp, m);
+#else
if (ifp->if_bpf)
- bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
+ bpf_mtap(ifp->if_bpf, m);
+#endif
#endif
if (sc->sc_mbuf_net) {
@@ -1508,41 +1824,15 @@ pfsync_sendout(struct pfsync_softc *sc)
sc->sc_statep_net.s = NULL;
}
- return pfsync_sendout_mbuf(sc, m);
-}
-
-int
-pfsync_tdb_sendout(struct pfsync_softc *sc)
-{
-#if NBPFILTER > 0
- struct ifnet *ifp = &sc->sc_if;
-#endif
- struct mbuf *m;
-
- timeout_del(&sc->sc_tdb_tmo);
-
- if (sc->sc_mbuf_tdb == NULL)
- return (0);
- m = sc->sc_mbuf_tdb;
- sc->sc_mbuf_tdb = NULL;
- sc->sc_statep_tdb.t = NULL;
-
-#if NBPFILTER > 0
- if (ifp->if_bpf)
- bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
+#ifdef __FreeBSD__
+ if (sc->sc_sync_ifp ||
+ sc->sc_sync_peer.s_addr != htonl(INADDR_PFSYNC_GROUP)) {
+#else
+ if (sc->sc_sync_ifp ||sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) {
#endif
+ struct ip *ip;
+ struct sockaddr sa;
- return pfsync_sendout_mbuf(sc, m);
-}
-
-int
-pfsync_sendout_mbuf(struct pfsync_softc *sc, struct mbuf *m)
-{
- struct sockaddr sa;
- struct ip *ip;
-
- if (sc->sc_sync_ifp ||
- sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) {
M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
if (m == NULL) {
pfsyncstats.pfsyncs_onomem++;
@@ -1552,9 +1842,17 @@ pfsync_sendout_mbuf(struct pfsync_softc *sc, struct mbuf *m)
ip->ip_v = IPVERSION;
ip->ip_hl = sizeof(*ip) >> 2;
ip->ip_tos = IPTOS_LOWDELAY;
+#ifdef __FreeBSD__
+ ip->ip_len = m->m_pkthdr.len;
+#else
ip->ip_len = htons(m->m_pkthdr.len);
+#endif
ip->ip_id = htons(ip_randomid());
+#ifdef __FreeBSD__
+ ip->ip_off = IP_DF;
+#else
ip->ip_off = htons(IP_DF);
+#endif
ip->ip_ttl = PFSYNC_DFLTTL;
ip->ip_p = IPPROTO_PFSYNC;
ip->ip_sum = 0;
@@ -1562,168 +1860,118 @@ pfsync_sendout_mbuf(struct pfsync_softc *sc, struct mbuf *m)
bzero(&sa, sizeof(sa));
ip->ip_src.s_addr = INADDR_ANY;
+#ifdef __FreeBSD__
+ if (sc->sc_sendaddr.s_addr == htonl(INADDR_PFSYNC_GROUP))
+#else
if (sc->sc_sendaddr.s_addr == INADDR_PFSYNC_GROUP)
+#endif
m->m_flags |= M_MCAST;
ip->ip_dst = sc->sc_sendaddr;
sc->sc_sendaddr.s_addr = sc->sc_sync_peer.s_addr;
pfsyncstats.pfsyncs_opackets++;
-
+#ifdef __FreeBSD__
+ if (!IF_HANDOFF(&sc->sc_ifq, m, NULL))
+ pfsyncstats.pfsyncs_oerrors++;
+ callout_reset(&sc->sc_send_tmo, 1, pfsync_senddef, sc);
+#else
if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
pfsyncstats.pfsyncs_oerrors++;
+#endif
} else
m_freem(m);
return (0);
}
-/* Update an in-kernel tdb. Silently fail if no tdb is found. */
-void
-pfsync_update_net_tdb(struct pfsync_tdb *pt)
+#ifdef __FreeBSD__
+static void
+pfsync_ifdetach(void *arg, struct ifnet *ifp)
{
- struct tdb *tdb;
- int s;
-
- /* check for invalid values */
- if (ntohl(pt->spi) <= SPI_RESERVED_MAX ||
- (pt->dst.sa.sa_family != AF_INET &&
- pt->dst.sa.sa_family != AF_INET6))
- goto bad;
-
- s = spltdb();
- tdb = gettdb(pt->spi, &pt->dst, pt->sproto);
- if (tdb) {
- pt->rpl = ntohl(pt->rpl);
- pt->cur_bytes = betoh64(pt->cur_bytes);
-
- /* Neither replay nor byte counter should ever decrease. */
- if (pt->rpl < tdb->tdb_rpl ||
- pt->cur_bytes < tdb->tdb_cur_bytes) {
- splx(s);
- goto bad;
- }
+ struct pfsync_softc *sc = (struct pfsync_softc *)arg;
+ struct ip_moptions *imo;
- tdb->tdb_rpl = pt->rpl;
- tdb->tdb_cur_bytes = pt->cur_bytes;
+ if (sc == NULL || sc->sc_sync_ifp != ifp)
+ return; /* not for us; unlocked read */
+
+ PF_LOCK();
+
+ /* Deal with a member interface going away from under us. */
+ sc->sc_sync_ifp = NULL;
+ if (sc->sc_mbuf_net != NULL) {
+ m_freem(sc->sc_mbuf_net);
+ sc->sc_mbuf_net = NULL;
+ sc->sc_statep_net.s = NULL;
}
- splx(s);
- return;
-
- bad:
- if (pf_status.debug >= PF_DEBUG_MISC)
- printf("pfsync_insert: PFSYNC_ACT_TDB_UPD: "
- "invalid value\n");
- pfsyncstats.pfsyncs_badstate++;
- return;
+ imo = &sc->sc_imo;
+ if (imo->imo_num_memberships > 0) {
+ KASSERT(imo->imo_num_memberships == 1,
+ ("%s: imo_num_memberships != 1", __func__));
+ /*
+ * Our event handler is always called after protocol
+ * domains have been detached from the underlying ifnet.
+ * Do not call in_delmulti(); we held a single reference
+ * which the protocol domain has purged in in_purgemaddrs().
+ */
+ imo->imo_membership[--imo->imo_num_memberships] = NULL;
+ imo->imo_multicast_ifp = NULL;
+ }
+
+ PF_UNLOCK();
}
-/* One of our local tdbs have been updated, need to sync rpl with others */
-int
-pfsync_update_tdb(struct tdb *tdb, int output)
+static void
+pfsync_senddef(void *arg)
{
- struct ifnet *ifp = NULL;
- struct pfsync_softc *sc = pfsyncif;
- struct pfsync_header *h;
- struct pfsync_tdb *pt = NULL;
- int s, i, ret;
-
- if (sc == NULL)
- return (0);
+ struct pfsync_softc *sc = (struct pfsync_softc *)arg;
+ struct mbuf *m;
- ifp = &sc->sc_if;
- if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL &&
- sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
- /* Don't leave any stale pfsync packets hanging around. */
- if (sc->sc_mbuf_tdb != NULL) {
- m_freem(sc->sc_mbuf_tdb);
- sc->sc_mbuf_tdb = NULL;
- sc->sc_statep_tdb.t = NULL;
+ for(;;) {
+ IF_DEQUEUE(&sc->sc_ifq, m);
+ if (m == NULL)
+ break;
+ /* Deal with a member interface going away from under us. */
+ if (sc->sc_sync_ifp == NULL) {
+ pfsyncstats.pfsyncs_oerrors++;
+ m_freem(m);
+ continue;
}
- return (0);
+ if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
+ pfsyncstats.pfsyncs_oerrors++;
}
+}
- s = splnet();
- if (sc->sc_mbuf_tdb == NULL) {
- if ((sc->sc_mbuf_tdb = pfsync_get_mbuf(sc, PFSYNC_ACT_TDB_UPD,
- (void *)&sc->sc_statep_tdb.t)) == NULL) {
- splx(s);
- return (ENOMEM);
- }
- h = mtod(sc->sc_mbuf_tdb, struct pfsync_header *);
- } else {
- h = mtod(sc->sc_mbuf_tdb, struct pfsync_header *);
- if (h->action != PFSYNC_ACT_TDB_UPD) {
- /*
- * XXX will never happen as long as there's
- * only one "TDB action".
- */
- pfsync_tdb_sendout(sc);
- sc->sc_mbuf_tdb = pfsync_get_mbuf(sc,
- PFSYNC_ACT_TDB_UPD, (void *)&sc->sc_statep_tdb.t);
- if (sc->sc_mbuf_tdb == NULL) {
- splx(s);
- return (ENOMEM);
- }
- h = mtod(sc->sc_mbuf_tdb, struct pfsync_header *);
- } else if (sc->sc_maxupdates) {
- /*
- * If it's an update, look in the packet to see if
- * we already have an update for the state.
- */
- struct pfsync_tdb *u =
- (void *)((char *)h + PFSYNC_HDRLEN);
-
- for (i = 0; !pt && i < h->count; i++) {
- if (tdb->tdb_spi == u->spi &&
- tdb->tdb_sproto == u->sproto &&
- !bcmp(&tdb->tdb_dst, &u->dst,
- SA_LEN(&u->dst.sa))) {
- pt = u;
- pt->updates++;
- }
- u++;
- }
- }
- }
+static int
+pfsync_modevent(module_t mod, int type, void *data)
+{
+ int error = 0;
- if (pt == NULL) {
- /* not a "duplicate" update */
- pt = sc->sc_statep_tdb.t++;
- sc->sc_mbuf_tdb->m_pkthdr.len =
- sc->sc_mbuf_tdb->m_len += sizeof(struct pfsync_tdb);
- h->count++;
- bzero(pt, sizeof(*pt));
+ switch (type) {
+ case MOD_LOAD:
+ LIST_INIT(&pfsync_list);
+ if_clone_attach(&pfsync_cloner);
+ break;
+
+ case MOD_UNLOAD:
+ if_clone_detach(&pfsync_cloner);
+ break;
- pt->spi = tdb->tdb_spi;
- memcpy(&pt->dst, &tdb->tdb_dst, sizeof pt->dst);
- pt->sproto = tdb->tdb_sproto;
+ default:
+ error = EINVAL;
+ break;
}
- /*
- * When a failover happens, the master's rpl is probably above
- * what we see here (we may be up to a second late), so
- * increase it a bit for outbound tdbs to manage most such
- * situations.
- *
- * For now, just add an offset that is likely to be larger
- * than the number of packets we can see in one second. The RFC
- * just says the next packet must have a higher seq value.
- *
- * XXX What is a good algorithm for this? We could use
- * a rate-determined increase, but to know it, we would have
- * to extend struct tdb.
- * XXX pt->rpl can wrap over MAXINT, but if so the real tdb
- * will soon be replaced anyway. For now, just don't handle
- * this edge case.
- */
-#define RPL_INCR 16384
- pt->rpl = htonl(tdb->tdb_rpl + (output ? RPL_INCR : 0));
- pt->cur_bytes = htobe64(tdb->tdb_cur_bytes);
+ return error;
+}
- if (h->count == sc->sc_maxcount ||
- (sc->sc_maxupdates && (pt->updates >= sc->sc_maxupdates)))
- ret = pfsync_tdb_sendout(sc);
+static moduledata_t pfsync_mod = {
+ "pfsync",
+ pfsync_modevent,
+ 0
+};
- splx(s);
- return (ret);
-}
+#define PFSYNC_MODVER 1
+
+DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
+MODULE_VERSION(pfsync, PFSYNC_MODVER);
+#endif /* __FreeBSD__ */
diff --git a/sys/contrib/pf/net/if_pfsync.h b/sys/contrib/pf/net/if_pfsync.h
index 5ed465e..77ef3a5 100644
--- a/sys/contrib/pf/net/if_pfsync.h
+++ b/sys/contrib/pf/net/if_pfsync.h
@@ -1,4 +1,5 @@
-/* $OpenBSD: if_pfsync.h,v 1.30 2006/10/31 14:49:01 henning Exp $ */
+/* $FreeBSD$ */
+/* $OpenBSD: if_pfsync.h,v 1.19 2005/01/20 17:47:38 mcbride Exp $ */
/*
* Copyright (c) 2001 Michael Shalayeff
@@ -35,7 +36,6 @@
struct pfsync_state_scrub {
u_int16_t pfss_flags;
u_int8_t pfss_ttl; /* stashed TTL */
-#define PFSYNC_SCRUB_FLAG_VALID 0x01
u_int8_t scrub_flag;
u_int32_t pfss_ts_mod; /* timestamp modulation */
} __packed;
@@ -55,7 +55,8 @@ struct pfsync_state_peer {
u_int16_t mss; /* Maximum segment size option */
u_int8_t state; /* active state level */
u_int8_t wscale; /* window scaling factor */
- u_int8_t pad[6];
+ u_int8_t scrub_flag;
+ u_int8_t pad[5];
} __packed;
struct pfsync_state {
@@ -72,8 +73,8 @@ struct pfsync_state {
u_int32_t nat_rule;
u_int32_t creation;
u_int32_t expire;
- u_int32_t packets[2][2];
- u_int32_t bytes[2][2];
+ u_int32_t packets[2];
+ u_int32_t bytes[2];
u_int32_t creatorid;
sa_family_t af;
u_int8_t proto;
@@ -88,16 +89,6 @@ struct pfsync_state {
#define PFSYNC_FLAG_COMPRESS 0x01
#define PFSYNC_FLAG_STALE 0x02
-struct pfsync_tdb {
- u_int32_t spi;
- union sockaddr_union dst;
- u_int32_t rpl;
- u_int64_t cur_bytes;
- u_int8_t sproto;
- u_int8_t updates;
- u_int8_t pad[2];
-} __packed;
-
struct pfsync_state_upd {
u_int32_t id[2];
struct pfsync_state_peer src;
@@ -153,45 +144,52 @@ union sc_statep {
struct pfsync_state_upd_req *r;
};
-union sc_tdb_statep {
- struct pfsync_tdb *t;
-};
-
extern int pfsync_sync_ok;
struct pfsync_softc {
+#ifdef __FreeBSD__
+ struct ifnet *sc_ifp;
+#else
struct ifnet sc_if;
+#endif
struct ifnet *sc_sync_ifp;
struct ip_moptions sc_imo;
+#ifdef __FreeBSD__
+ struct callout sc_tmo;
+ struct callout sc_bulk_tmo;
+ struct callout sc_bulkfail_tmo;
+#else
struct timeout sc_tmo;
- struct timeout sc_tdb_tmo;
struct timeout sc_bulk_tmo;
struct timeout sc_bulkfail_tmo;
+#endif
struct in_addr sc_sync_peer;
struct in_addr sc_sendaddr;
struct mbuf *sc_mbuf; /* current cumulative mbuf */
struct mbuf *sc_mbuf_net; /* current cumulative mbuf */
- struct mbuf *sc_mbuf_tdb; /* dito for TDB updates */
+#ifdef __FreeBSD__
+ struct ifqueue sc_ifq;
+ struct callout sc_send_tmo;
+#endif
union sc_statep sc_statep;
union sc_statep sc_statep_net;
- union sc_tdb_statep sc_statep_tdb;
u_int32_t sc_ureq_received;
u_int32_t sc_ureq_sent;
- struct pf_state *sc_bulk_send_next;
- struct pf_state *sc_bulk_terminator;
int sc_bulk_tries;
int sc_maxcount; /* number of states in mtu */
int sc_maxupdates; /* number of updates/state */
+#ifdef __FreeBSD__
+ LIST_ENTRY(pfsync_softc) sc_next;
+ eventhandler_tag sc_detachtag;
+#endif
};
-
-extern struct pfsync_softc *pfsyncif;
#endif
struct pfsync_header {
u_int8_t version;
-#define PFSYNC_VERSION 3
+#define PFSYNC_VERSION 2
u_int8_t af;
u_int8_t action;
#define PFSYNC_ACT_CLR 0 /* clear all states */
@@ -204,10 +202,8 @@ struct pfsync_header {
#define PFSYNC_ACT_DEL_F 7 /* delete fragments */
#define PFSYNC_ACT_UREQ 8 /* request "uncompressed" state */
#define PFSYNC_ACT_BUS 9 /* Bulk Update Status */
-#define PFSYNC_ACT_TDB_UPD 10 /* TDB replay counter update */
-#define PFSYNC_ACT_MAX 11
+#define PFSYNC_ACT_MAX 10
u_int8_t count;
- u_int8_t pf_chksum[PF_MD5_DIGEST_LENGTH];
} __packed;
#define PFSYNC_BULKPACKETS 1 /* # of packets per timeout */
@@ -216,7 +212,7 @@ struct pfsync_header {
#define PFSYNC_ACTIONS \
"CLR ST", "INS ST", "UPD ST", "DEL ST", \
"UPD ST COMP", "DEL ST COMP", "INS FR", "DEL FR", \
- "UPD REQ", "BLK UPD STAT", "TDB UPD"
+ "UPD REQ", "BLK UPD STAT"
#define PFSYNC_DFLTTL 255
@@ -250,6 +246,10 @@ struct pfsyncreq {
int pfsyncr_authlevel;
};
+#ifdef __FreeBSD__
+#define SIOCSETPFSYNC _IOW('i', 247, struct ifreq)
+#define SIOCGETPFSYNC _IOWR('i', 248, struct ifreq)
+#endif
#define pf_state_peer_hton(s,d) do { \
(d)->seqlo = htonl((s)->seqlo); \
@@ -259,13 +259,6 @@ struct pfsyncreq {
(d)->mss = htons((s)->mss); \
(d)->state = (s)->state; \
(d)->wscale = (s)->wscale; \
- if ((s)->scrub) { \
- (d)->scrub.pfss_flags = \
- htons((s)->scrub->pfss_flags & PFSS_TIMESTAMP); \
- (d)->scrub.pfss_ttl = (s)->scrub->pfss_ttl; \
- (d)->scrub.pfss_ts_mod = htonl((s)->scrub->pfss_ts_mod);\
- (d)->scrub.scrub_flag = PFSYNC_SCRUB_FLAG_VALID; \
- } \
} while (0)
#define pf_state_peer_ntoh(s,d) do { \
@@ -276,13 +269,6 @@ struct pfsyncreq {
(d)->mss = ntohs((s)->mss); \
(d)->state = (s)->state; \
(d)->wscale = (s)->wscale; \
- if ((s)->scrub.scrub_flag == PFSYNC_SCRUB_FLAG_VALID && \
- (d)->scrub != NULL) { \
- (d)->scrub->pfss_flags = \
- ntohs((s)->scrub.pfss_flags) & PFSS_TIMESTAMP; \
- (d)->scrub->pfss_ttl = (s)->scrub.pfss_ttl; \
- (d)->scrub->pfss_ts_mod = ntohl((s)->scrub.pfss_ts_mod);\
- } \
} while (0)
#define pf_state_host_hton(s,d) do { \
@@ -295,19 +281,12 @@ struct pfsyncreq {
(d)->port = (s)->port; \
} while (0)
-#define pf_state_counter_hton(s,d) do { \
- d[0] = htonl((s>>32)&0xffffffff); \
- d[1] = htonl(s&0xffffffff); \
-} while (0)
-
-#define pf_state_counter_ntoh(s,d) do { \
- d = ntohl(s[0]); \
- d = d<<32; \
- d += ntohl(s[1]); \
-} while (0)
-
#ifdef _KERNEL
+#ifdef __FreeBSD__
+void pfsync_input(struct mbuf *, __unused int);
+#else
void pfsync_input(struct mbuf *, ...);
+#endif
int pfsync_clear_states(u_int32_t, char *);
int pfsync_pack_state(u_int8_t, struct pf_state *, int);
#define pfsync_insert_state(st) do { \
@@ -315,8 +294,7 @@ int pfsync_pack_state(u_int8_t, struct pf_state *, int);
(st->proto == IPPROTO_PFSYNC)) \
st->sync_flags |= PFSTATE_NOSYNC; \
else if (!st->sync_flags) \
- pfsync_pack_state(PFSYNC_ACT_INS, (st), \
- PFSYNC_FLAG_COMPRESS); \
+ pfsync_pack_state(PFSYNC_ACT_INS, (st), 1); \
st->sync_flags &= ~PFSTATE_FROMSYNC; \
} while (0)
#define pfsync_update_state(st) do { \
@@ -329,8 +307,8 @@ int pfsync_pack_state(u_int8_t, struct pf_state *, int);
if (!st->sync_flags) \
pfsync_pack_state(PFSYNC_ACT_DEL, (st), \
PFSYNC_FLAG_COMPRESS); \
+ st->sync_flags &= ~PFSTATE_FROMSYNC; \
} while (0)
-int pfsync_update_tdb(struct tdb *, int);
#endif
#endif /* _NET_IF_PFSYNC_H_ */
diff --git a/sys/contrib/pf/net/pf.c b/sys/contrib/pf/net/pf.c
index 793dc34..282cbb5 100644
--- a/sys/contrib/pf/net/pf.c
+++ b/sys/contrib/pf/net/pf.c
@@ -1,4 +1,5 @@
-/* $OpenBSD: pf.c,v 1.527 2007/02/22 15:23:23 pyr Exp $ */
+/* $FreeBSD$ */
+/* $OpenBSD: pf.c,v 1.483 2005/03/15 17:38:43 dhartmei Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -35,9 +36,39 @@
*
*/
+#ifdef __FreeBSD__
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#endif
+
+#ifdef __FreeBSD__
+#include "opt_mac.h"
+#include "opt_bpf.h"
+#include "opt_pf.h"
+
+#ifdef DEV_BPF
+#define NBPFILTER DEV_BPF
+#else
+#define NBPFILTER 0
+#endif
+
+#ifdef DEV_PFLOG
+#define NPFLOG DEV_PFLOG
+#else
+#define NPFLOG 0
+#endif
+
+#ifdef DEV_PFSYNC
+#define NPFSYNC DEV_PFSYNC
+#else
+#define NPFSYNC 0
+#endif
+
+#else
#include "bpfilter.h"
#include "pflog.h"
#include "pfsync.h"
+#endif
#include <sys/param.h>
#include <sys/systm.h>
@@ -47,15 +78,17 @@
#include <sys/socketvar.h>
#include <sys/kernel.h>
#include <sys/time.h>
+#ifdef __FreeBSD__
+#include <sys/sysctl.h>
+#include <sys/endian.h>
+#else
#include <sys/pool.h>
-#include <sys/proc.h>
-#include <sys/rwlock.h>
+#endif
#include <net/if.h>
#include <net/if_types.h>
#include <net/bpf.h>
#include <net/route.h>
-#include <net/radix_mpath.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
@@ -73,7 +106,9 @@
#include <netinet/icmp_var.h>
#include <netinet/if_ether.h>
+#ifndef __FreeBSD__
#include <dev/rndvar.h>
+#endif
#include <net/pfvar.h>
#include <net/if_pflog.h>
@@ -86,8 +121,20 @@
#include <netinet/in_pcb.h>
#include <netinet/icmp6.h>
#include <netinet6/nd6.h>
+#ifdef __FreeBSD__
+#include <netinet6/ip6_var.h>
+#include <netinet6/in6_pcb.h>
+#endif
#endif /* INET6 */
+#ifdef __FreeBSD__
+#include <machine/in_cksum.h>
+#include <sys/limits.h>
+#include <sys/ucred.h>
+#include <security/mac/mac_framework.h>
+
+extern int ip_optcopy(struct ip *, struct ip *);
+#endif
#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x
@@ -95,6 +142,8 @@
* Global variables
*/
+struct pf_anchor_global pf_anchors;
+struct pf_ruleset pf_main_ruleset;
struct pf_altqqueue pf_altqs[2];
struct pf_palist pf_pabuf;
struct pf_altqqueue *pf_altqs_active;
@@ -106,6 +155,12 @@ u_int32_t ticket_altqs_inactive;
int altqs_inactive_open;
u_int32_t ticket_pabuf;
+#ifdef __FreeBSD__
+struct callout pf_expire_to; /* expire timeout */
+#else
+struct timeout pf_expire_to; /* expire timeout */
+#endif
+
struct pf_anchor_stackframe {
struct pf_ruleset *rs;
struct pf_rule *r;
@@ -113,8 +168,13 @@ struct pf_anchor_stackframe {
struct pf_anchor *child;
} pf_anchor_stack[64];
+#ifdef __FreeBSD__
+uma_zone_t pf_src_tree_pl, pf_rule_pl;
+uma_zone_t pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
+#else
struct pool pf_src_tree_pl, pf_rule_pl;
struct pool pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
+#endif
void pf_print_host(struct pf_addr *, u_int16_t, u_int8_t);
@@ -126,8 +186,6 @@ int pf_check_threshold(struct pf_threshold *);
void pf_change_ap(struct pf_addr *, u_int16_t *,
u_int16_t *, u_int16_t *, struct pf_addr *,
u_int16_t, u_int8_t, sa_family_t);
-int pf_modulate_sack(struct mbuf *, int, struct pf_pdesc *,
- struct tcphdr *, struct pf_state_peer *);
#ifdef INET6
void pf_change_a6(struct pf_addr *, u_int16_t *,
struct pf_addr *, u_int8_t);
@@ -136,11 +194,16 @@ void pf_change_icmp(struct pf_addr *, u_int16_t *,
struct pf_addr *, struct pf_addr *, u_int16_t,
u_int16_t *, u_int16_t *, u_int16_t *,
u_int16_t *, u_int8_t, sa_family_t);
+#ifdef __FreeBSD__
+void pf_send_tcp(struct mbuf *,
+ const struct pf_rule *, sa_family_t,
+#else
void pf_send_tcp(const struct pf_rule *, sa_family_t,
+#endif
const struct pf_addr *, const struct pf_addr *,
u_int16_t, u_int16_t, u_int32_t, u_int32_t,
u_int8_t, u_int16_t, u_int16_t, u_int8_t, int,
- u_int16_t, struct ether_header *, struct ifnet *);
+ struct ether_header *, struct ifnet *);
void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t,
sa_family_t, struct pf_rule *);
struct pf_rule *pf_match_translation(struct pf_pdesc *, struct mbuf *,
@@ -155,11 +218,21 @@ struct pf_rule *pf_get_translation(struct pf_pdesc *, struct mbuf *,
int pf_test_tcp(struct pf_rule **, struct pf_state **,
int, struct pfi_kif *, struct mbuf *, int,
void *, struct pf_pdesc *, struct pf_rule **,
+#ifdef __FreeBSD__
+ struct pf_ruleset **, struct ifqueue *,
+ struct inpcb *);
+#else
struct pf_ruleset **, struct ifqueue *);
+#endif
int pf_test_udp(struct pf_rule **, struct pf_state **,
int, struct pfi_kif *, struct mbuf *, int,
void *, struct pf_pdesc *, struct pf_rule **,
+#ifdef __FreeBSD__
+ struct pf_ruleset **, struct ifqueue *,
+ struct inpcb *);
+#else
struct pf_ruleset **, struct ifqueue *);
+#endif
int pf_test_icmp(struct pf_rule **, struct pf_state **,
int, struct pfi_kif *, struct mbuf *, int,
void *, struct pf_pdesc *, struct pf_rule **,
@@ -183,11 +256,9 @@ int pf_test_state_icmp(struct pf_state **, int,
void *, struct pf_pdesc *, u_short *);
int pf_test_state_other(struct pf_state **, int,
struct pfi_kif *, struct pf_pdesc *);
+struct pf_tag *pf_get_tag(struct mbuf *);
int pf_match_tag(struct mbuf *, struct pf_rule *,
- struct pf_mtag *, int *);
-int pf_step_out_of_anchor(int *, struct pf_ruleset **,
- int, struct pf_rule **, struct pf_rule **,
- int *);
+ struct pf_tag **, int *);
void pf_hash(struct pf_addr *, struct pf_addr *,
struct pf_poolhashkey *, sa_family_t);
int pf_map_addr(u_int8_t, struct pf_rule *,
@@ -198,12 +269,16 @@ int pf_get_sport(sa_family_t, u_int8_t, struct pf_rule *,
struct pf_addr *, u_int16_t*, u_int16_t, u_int16_t,
struct pf_src_node **);
void pf_route(struct mbuf **, struct pf_rule *, int,
- struct ifnet *, struct pf_state *,
- struct pf_pdesc *);
+ struct ifnet *, struct pf_state *);
void pf_route6(struct mbuf **, struct pf_rule *, int,
- struct ifnet *, struct pf_state *,
- struct pf_pdesc *);
-int pf_socket_lookup(int, struct pf_pdesc *);
+ struct ifnet *, struct pf_state *);
+#ifdef __FreeBSD__
+int pf_socket_lookup(uid_t *, gid_t *,
+ int, struct pf_pdesc *, struct inpcb *);
+#else
+int pf_socket_lookup(uid_t *, gid_t *,
+ int, struct pf_pdesc *);
+#endif
u_int8_t pf_get_wscale(struct mbuf *, int, u_int16_t,
sa_family_t);
u_int16_t pf_get_mss(struct mbuf *, int, u_int16_t,
@@ -216,21 +291,24 @@ int pf_check_proto_cksum(struct mbuf *, int, int,
u_int8_t, sa_family_t);
int pf_addr_wrap_neq(struct pf_addr_wrap *,
struct pf_addr_wrap *);
+static int pf_add_mbuf_tag(struct mbuf *, u_int);
struct pf_state *pf_find_state_recurse(struct pfi_kif *,
- struct pf_state_cmp *, u_int8_t);
+ struct pf_state *, u_int8_t);
int pf_src_connlimit(struct pf_state **);
int pf_check_congestion(struct ifqueue *);
-extern struct pool pfr_ktable_pl;
-extern struct pool pfr_kentry_pl;
+#ifdef __FreeBSD__
+int in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len);
+
+struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX];
+#else
struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
{ &pf_state_pl, PFSTATE_HIWAT },
{ &pf_src_tree_pl, PFSNODE_HIWAT },
- { &pf_frent_pl, PFFRAG_FRENT_HIWAT },
- { &pfr_ktable_pl, PFR_KTABLE_HIWAT },
- { &pfr_kentry_pl, PFR_KENTRY_HIWAT }
+ { &pf_frent_pl, PFFRAG_FRENT_HIWAT }
};
+#endif
#define STATE_LOOKUP() \
do { \
@@ -260,8 +338,9 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
(s)->lan.addr.addr32[3] != (s)->gwy.addr.addr32[3])) || \
(s)->lan.port != (s)->gwy.port
-#define BOUND_IFACE(r, k) \
- ((r)->rule_flag & PFRULE_IFBOUND) ? (k) : pfi_all
+#define BOUND_IFACE(r, k) (((r)->rule_flag & PFRULE_IFBOUND) ? (k) : \
+ ((r)->rule_flag & PFRULE_GRBOUND) ? (k)->pfik_parent : \
+ (k)->pfik_parent->pfik_parent)
#define STATE_INC_COUNTERS(s) \
do { \
@@ -281,6 +360,7 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
s->rule.ptr->states--; \
} while (0)
+#ifndef __FreeBSD__
static __inline int pf_src_compare(struct pf_src_node *, struct pf_src_node *);
static __inline int pf_state_compare_lan_ext(struct pf_state *,
struct pf_state *);
@@ -288,11 +368,22 @@ static __inline int pf_state_compare_ext_gwy(struct pf_state *,
struct pf_state *);
static __inline int pf_state_compare_id(struct pf_state *,
struct pf_state *);
+static __inline int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
+#else
+static int pf_src_compare(struct pf_src_node *, struct pf_src_node *);
+static int pf_state_compare_lan_ext(struct pf_state *,
+ struct pf_state *);
+static int pf_state_compare_ext_gwy(struct pf_state *,
+ struct pf_state *);
+static int pf_state_compare_id(struct pf_state *,
+ struct pf_state *);
+static int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
+#endif
struct pf_src_tree tree_src_tracking;
struct pf_state_tree_id tree_id;
-struct pf_state_queue state_list;
+struct pf_state_queue state_updates;
RB_GENERATE(pf_src_tree, pf_src_node, entry, pf_src_compare);
RB_GENERATE(pf_state_tree_lan_ext, pf_state,
@@ -301,8 +392,14 @@ RB_GENERATE(pf_state_tree_ext_gwy, pf_state,
u.s.entry_ext_gwy, pf_state_compare_ext_gwy);
RB_GENERATE(pf_state_tree_id, pf_state,
u.s.entry_id, pf_state_compare_id);
+RB_GENERATE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare);
+RB_GENERATE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare);
+#ifdef __FreeBSD__
+static int
+#else
static __inline int
+#endif
pf_src_compare(struct pf_src_node *a, struct pf_src_node *b)
{
int diff;
@@ -346,7 +443,11 @@ pf_src_compare(struct pf_src_node *a, struct pf_src_node *b)
return (0);
}
+#ifdef __FreeBSD__
+static int
+#else
static __inline int
+#endif
pf_state_compare_lan_ext(struct pf_state *a, struct pf_state *b)
{
int diff;
@@ -414,7 +515,11 @@ pf_state_compare_lan_ext(struct pf_state *a, struct pf_state *b)
return (0);
}
+#ifdef __FreeBSD__
+static int
+#else
static __inline int
+#endif
pf_state_compare_ext_gwy(struct pf_state *a, struct pf_state *b)
{
int diff;
@@ -482,7 +587,11 @@ pf_state_compare_ext_gwy(struct pf_state *a, struct pf_state *b)
return (0);
}
+#ifdef __FreeBSD__
+static int
+#else
static __inline int
+#endif
pf_state_compare_id(struct pf_state *a, struct pf_state *b)
{
if (a->id > b->id)
@@ -497,6 +606,18 @@ pf_state_compare_id(struct pf_state *a, struct pf_state *b)
return (0);
}
+#ifdef __FreeBSD__
+static int
+#else
+static __inline int
+#endif
+pf_anchor_compare(struct pf_anchor *a, struct pf_anchor *b)
+{
+ int c = strcmp(a->path, b->path);
+
+ return (c ? (c < 0 ? -1 : 1) : 0);
+}
+
#ifdef INET6
void
pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af)
@@ -518,14 +639,14 @@ pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af)
#endif /* INET6 */
struct pf_state *
-pf_find_state_byid(struct pf_state_cmp *key)
+pf_find_state_byid(struct pf_state *key)
{
pf_status.fcounters[FCNT_STATE_SEARCH]++;
- return (RB_FIND(pf_state_tree_id, &tree_id, (struct pf_state *)key));
+ return (RB_FIND(pf_state_tree_id, &tree_id, key));
}
struct pf_state *
-pf_find_state_recurse(struct pfi_kif *kif, struct pf_state_cmp *key, u_int8_t tree)
+pf_find_state_recurse(struct pfi_kif *kif, struct pf_state *key, u_int8_t tree)
{
struct pf_state *s;
@@ -533,20 +654,20 @@ pf_find_state_recurse(struct pfi_kif *kif, struct pf_state_cmp *key, u_int8_t tr
switch (tree) {
case PF_LAN_EXT:
- if ((s = RB_FIND(pf_state_tree_lan_ext, &kif->pfik_lan_ext,
- (struct pf_state *)key)) != NULL)
- return (s);
- if ((s = RB_FIND(pf_state_tree_lan_ext, &pfi_all->pfik_lan_ext,
- (struct pf_state *)key)) != NULL)
- return (s);
+ for (; kif != NULL; kif = kif->pfik_parent) {
+ s = RB_FIND(pf_state_tree_lan_ext,
+ &kif->pfik_lan_ext, key);
+ if (s != NULL)
+ return (s);
+ }
return (NULL);
case PF_EXT_GWY:
- if ((s = RB_FIND(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy,
- (struct pf_state *)key)) != NULL)
- return (s);
- if ((s = RB_FIND(pf_state_tree_ext_gwy, &pfi_all->pfik_ext_gwy,
- (struct pf_state *)key)) != NULL)
- return (s);
+ for (; kif != NULL; kif = kif->pfik_parent) {
+ s = RB_FIND(pf_state_tree_ext_gwy,
+ &kif->pfik_ext_gwy, key);
+ if (s != NULL)
+ return (s);
+ }
return (NULL);
default:
panic("pf_find_state_recurse");
@@ -554,7 +675,7 @@ pf_find_state_recurse(struct pfi_kif *kif, struct pf_state_cmp *key, u_int8_t tr
}
struct pf_state *
-pf_find_state_all(struct pf_state_cmp *key, u_int8_t tree, int *more)
+pf_find_state_all(struct pf_state *key, u_int8_t tree, int *more)
{
struct pf_state *s, *ss = NULL;
struct pfi_kif *kif;
@@ -565,7 +686,7 @@ pf_find_state_all(struct pf_state_cmp *key, u_int8_t tree, int *more)
case PF_LAN_EXT:
TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) {
s = RB_FIND(pf_state_tree_lan_ext,
- &kif->pfik_lan_ext, (struct pf_state *)key);
+ &kif->pfik_lan_ext, key);
if (s == NULL)
continue;
if (more == NULL)
@@ -577,7 +698,7 @@ pf_find_state_all(struct pf_state_cmp *key, u_int8_t tree, int *more)
case PF_EXT_GWY:
TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) {
s = RB_FIND(pf_state_tree_ext_gwy,
- &kif->pfik_ext_gwy, (struct pf_state *)key);
+ &kif->pfik_ext_gwy, key);
if (s == NULL)
continue;
if (more == NULL)
@@ -628,7 +749,9 @@ pf_src_connlimit(struct pf_state **state)
int bad = 0;
(*state)->src_node->conn++;
- (*state)->src.tcp_est = 1;
+#ifdef __FreeBSD__
+ (*state)->local_flags |= PFSTATE_SRC_CONN;
+#endif
pf_add_threshold(&(*state)->src_node->conn_rate);
if ((*state)->rule.ptr->max_src_conn &&
@@ -831,9 +954,16 @@ pf_insert_state(struct pfi_kif *kif, struct pf_state *state)
}
if (RB_INSERT(pf_state_tree_id, &tree_id, state) != NULL) {
if (pf_status.debug >= PF_DEBUG_MISC) {
+#ifdef __FreeBSD__
+ printf("pf: state insert failed: "
+ "id: %016llx creatorid: %08x",
+ (long long)be64toh(state->id),
+ ntohl(state->creatorid));
+#else
printf("pf: state insert failed: "
"id: %016llx creatorid: %08x",
betoh64(state->id), ntohl(state->creatorid));
+#endif
if (state->sync_flags & PFSTATE_FROMSYNC)
printf(" (from sync)");
printf("\n");
@@ -842,10 +972,11 @@ pf_insert_state(struct pfi_kif *kif, struct pf_state *state)
RB_REMOVE(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state);
return (-1);
}
- TAILQ_INSERT_TAIL(&state_list, state, u.s.entry_list);
+ TAILQ_INSERT_HEAD(&state_updates, state, u.s.entry_updates);
+
pf_status.fcounters[FCNT_STATE_INSERT]++;
pf_status.states++;
- pfi_kif_ref(kif, PFI_KIF_REF_STATE);
+ pfi_attach_state(kif);
#if NPFSYNC
pfsync_insert_state(state);
#endif
@@ -853,28 +984,33 @@ pf_insert_state(struct pfi_kif *kif, struct pf_state *state)
}
void
-pf_purge_thread(void *v)
+pf_purge_timeout(void *arg)
{
- int nloops = 0, s;
-
- for (;;) {
- tsleep(pf_purge_thread, PWAIT, "pftm", 1 * hz);
-
- s = splsoftnet();
-
- /* process a fraction of the state table every second */
- pf_purge_expired_states(1 + (pf_status.states
- / pf_default_rule.timeout[PFTM_INTERVAL]));
+#ifdef __FreeBSD__
+ struct callout *to = arg;
+#else
+ struct timeout *to = arg;
+#endif
+ int s;
- /* purge other expired types every PFTM_INTERVAL seconds */
- if (++nloops >= pf_default_rule.timeout[PFTM_INTERVAL]) {
- pf_purge_expired_fragments();
- pf_purge_expired_src_nodes(0);
- nloops = 0;
- }
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
+ s = splsoftnet();
+ pf_purge_expired_states();
+ pf_purge_expired_fragments();
+ pf_purge_expired_src_nodes();
+ splx(s);
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
- splx(s);
- }
+#ifdef __FreeBSD__
+ callout_reset(to, pf_default_rule.timeout[PFTM_INTERVAL] * hz,
+ pf_purge_timeout, to);
+#else
+ timeout_add(to, pf_default_rule.timeout[PFTM_INTERVAL] * hz);
+#endif
}
u_int32_t
@@ -890,8 +1026,12 @@ pf_state_expires(const struct pf_state *state)
return (time_second);
if (state->timeout == PFTM_UNTIL_PACKET)
return (0);
- KASSERT(state->timeout != PFTM_UNLINKED);
+#ifdef __FreeBSD__
+ KASSERT((state->timeout < PFTM_MAX),
+ ("pf_state_expires: timeout > PFTM_MAX"));
+#else
KASSERT(state->timeout < PFTM_MAX);
+#endif
timeout = state->rule.ptr->timeout[state->timeout];
if (!timeout)
timeout = pf_default_rule.timeout[state->timeout];
@@ -915,21 +1055,14 @@ pf_state_expires(const struct pf_state *state)
}
void
-pf_purge_expired_src_nodes(int waslocked)
+pf_purge_expired_src_nodes(void)
{
struct pf_src_node *cur, *next;
- int locked = waslocked;
for (cur = RB_MIN(pf_src_tree, &tree_src_tracking); cur; cur = next) {
next = RB_NEXT(pf_src_tree, &tree_src_tracking, cur);
if (cur->states <= 0 && cur->expire <= time_second) {
- if (! locked) {
- rw_enter_write(&pf_consistency_lock);
- next = RB_NEXT(pf_src_tree,
- &tree_src_tracking, cur);
- locked = 1;
- }
if (cur->rule.ptr != NULL) {
cur->rule.ptr->src_nodes--;
if (cur->rule.ptr->states <= 0 &&
@@ -942,9 +1075,6 @@ pf_purge_expired_src_nodes(int waslocked)
pool_put(&pf_src_tree_pl, cur);
}
}
-
- if (locked && !waslocked)
- rw_exit_write(&pf_consistency_lock);
}
void
@@ -954,7 +1084,12 @@ pf_src_tree_remove_state(struct pf_state *s)
if (s->src_node != NULL) {
if (s->proto == IPPROTO_TCP) {
- if (s->src.tcp_est)
+#ifdef __FreeBSD__
+ if (s->local_flags & PFSTATE_SRC_CONN)
+#else
+ if (s->src.state == PF_TCPS_PROXY_DST ||
+ s->timeout >= PFTM_TCP_ESTABLISHED)
+#endif
--s->src_node->conn;
}
if (--s->src_node->states <= 0) {
@@ -977,42 +1112,33 @@ pf_src_tree_remove_state(struct pf_state *s)
s->src_node = s->nat_src_node = NULL;
}
-/* callers should be at splsoftnet */
void
-pf_unlink_state(struct pf_state *cur)
+pf_purge_expired_state(struct pf_state *cur)
{
- if (cur->src.state == PF_TCPS_PROXY_DST) {
+#ifdef __FreeBSD__
+ if (cur->local_flags & PFSTATE_EXPIRING)
+ return;
+ cur->local_flags |= PFSTATE_EXPIRING;
+#endif
+ if (cur->src.state == PF_TCPS_PROXY_DST)
+#ifdef __FreeBSD__
+ pf_send_tcp(NULL, cur->rule.ptr, cur->af,
+#else
pf_send_tcp(cur->rule.ptr, cur->af,
+#endif
&cur->ext.addr, &cur->lan.addr,
cur->ext.port, cur->lan.port,
cur->src.seqhi, cur->src.seqlo + 1,
- TH_RST|TH_ACK, 0, 0, 0, 1, cur->tag, NULL, NULL);
- }
+ TH_RST|TH_ACK, 0, 0, 0, 1, NULL, NULL);
RB_REMOVE(pf_state_tree_ext_gwy,
&cur->u.s.kif->pfik_ext_gwy, cur);
RB_REMOVE(pf_state_tree_lan_ext,
&cur->u.s.kif->pfik_lan_ext, cur);
RB_REMOVE(pf_state_tree_id, &tree_id, cur);
#if NPFSYNC
- if (cur->creatorid == pf_status.hostid)
- pfsync_delete_state(cur);
+ pfsync_delete_state(cur);
#endif
- cur->timeout = PFTM_UNLINKED;
pf_src_tree_remove_state(cur);
-}
-
-/* callers should be at splsoftnet and hold the
- * write_lock on pf_consistency_lock */
-void
-pf_free_state(struct pf_state *cur)
-{
-#if NPFSYNC
- if (pfsyncif != NULL &&
- (pfsyncif->sc_bulk_send_next == cur ||
- pfsyncif->sc_bulk_terminator == cur))
- return;
-#endif
- KASSERT(cur->timeout == PFTM_UNLINKED);
if (--cur->rule.ptr->states <= 0 &&
cur->rule.ptr->src_nodes <= 0)
pf_rm_rule(NULL, cur->rule.ptr);
@@ -1024,8 +1150,8 @@ pf_free_state(struct pf_state *cur)
if (--cur->anchor.ptr->states <= 0)
pf_rm_rule(NULL, cur->anchor.ptr);
pf_normalize_tcp_cleanup(cur);
- pfi_kif_unref(cur->u.s.kif, PFI_KIF_REF_STATE);
- TAILQ_REMOVE(&state_list, cur, u.s.entry_list);
+ pfi_detach_state(cur->u.s.kif);
+ TAILQ_REMOVE(&state_updates, cur, u.s.entry_updates);
if (cur->tag)
pf_tag_unref(cur->tag);
pool_put(&pf_state_pl, cur);
@@ -1034,44 +1160,16 @@ pf_free_state(struct pf_state *cur)
}
void
-pf_purge_expired_states(u_int32_t maxcheck)
+pf_purge_expired_states(void)
{
- static struct pf_state *cur = NULL;
- struct pf_state *next;
- int locked = 0;
-
- while (maxcheck--) {
- /* wrap to start of list when we hit the end */
- if (cur == NULL) {
- cur = TAILQ_FIRST(&state_list);
- if (cur == NULL)
- break; /* list empty */
- }
-
- /* get next state, as cur may get deleted */
- next = TAILQ_NEXT(cur, u.s.entry_list);
-
- if (cur->timeout == PFTM_UNLINKED) {
- /* free unlinked state */
- if (! locked) {
- rw_enter_write(&pf_consistency_lock);
- locked = 1;
- }
- pf_free_state(cur);
- } else if (pf_state_expires(cur) <= time_second) {
- /* unlink and free expired state */
- pf_unlink_state(cur);
- if (! locked) {
- rw_enter_write(&pf_consistency_lock);
- locked = 1;
- }
- pf_free_state(cur);
- }
- cur = next;
- }
+ struct pf_state *cur, *next;
- if (locked)
- rw_exit_write(&pf_consistency_lock);
+ for (cur = RB_MIN(pf_state_tree_id, &tree_id);
+ cur; cur = next) {
+ next = RB_NEXT(pf_state_tree_id, &tree_id, cur);
+ if (pf_state_expires(cur) <= time_second)
+ pf_purge_expired_state(cur);
+ }
}
int
@@ -1297,12 +1395,9 @@ pf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2)
case PF_ADDR_DYNIFTL:
return (aw1->p.dyn->pfid_kt != aw2->p.dyn->pfid_kt);
case PF_ADDR_NOROUTE:
- case PF_ADDR_URPFFAILED:
return (0);
case PF_ADDR_TABLE:
return (aw1->p.tbl != aw2->p.tbl);
- case PF_ADDR_RTLABEL:
- return (aw1->v.rtlabel != aw2->v.rtlabel);
default:
printf("invalid address type: %d\n", aw1->type);
return (1);
@@ -1417,7 +1512,7 @@ pf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa,
/* Change inner protocol port, fix inner protocol checksum. */
if (ip != NULL) {
u_int16_t oip = *ip;
- u_int32_t opc;
+ u_int32_t opc = 0; /* make the compiler happy */
if (pc != NULL)
opc = *pc;
@@ -1489,82 +1584,27 @@ pf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa,
}
}
-
-/*
- * Need to modulate the sequence numbers in the TCP SACK option
- * (credits to Krzysztof Pfaff for report and patch)
- */
-int
-pf_modulate_sack(struct mbuf *m, int off, struct pf_pdesc *pd,
- struct tcphdr *th, struct pf_state_peer *dst)
-{
- int hlen = (th->th_off << 2) - sizeof(*th), thoptlen = hlen;
- u_int8_t opts[MAX_TCPOPTLEN], *opt = opts;
- int copyback = 0, i, olen;
- struct sackblk sack;
-
-#define TCPOLEN_SACKLEN (TCPOLEN_SACK + 2)
- if (hlen < TCPOLEN_SACKLEN ||
- !pf_pull_hdr(m, off + sizeof(*th), opts, hlen, NULL, NULL, pd->af))
- return 0;
-
- while (hlen >= TCPOLEN_SACKLEN) {
- olen = opt[1];
- switch (*opt) {
- case TCPOPT_EOL: /* FALLTHROUGH */
- case TCPOPT_NOP:
- opt++;
- hlen--;
- break;
- case TCPOPT_SACK:
- if (olen > hlen)
- olen = hlen;
- if (olen >= TCPOLEN_SACKLEN) {
- for (i = 2; i + TCPOLEN_SACK <= olen;
- i += TCPOLEN_SACK) {
- memcpy(&sack, &opt[i], sizeof(sack));
- pf_change_a(&sack.start, &th->th_sum,
- htonl(ntohl(sack.start) -
- dst->seqdiff), 0);
- pf_change_a(&sack.end, &th->th_sum,
- htonl(ntohl(sack.end) -
- dst->seqdiff), 0);
- memcpy(&opt[i], &sack, sizeof(sack));
- }
- copyback = 1;
- }
- /* FALLTHROUGH */
- default:
- if (olen < 2)
- olen = 2;
- hlen -= olen;
- opt += olen;
- }
- }
-
- if (copyback)
- m_copyback(m, off + sizeof(*th), thoptlen, opts);
- return (copyback);
-}
-
void
+#ifdef __FreeBSD__
+pf_send_tcp(struct mbuf *replyto, const struct pf_rule *r, sa_family_t af,
+#else
pf_send_tcp(const struct pf_rule *r, sa_family_t af,
+#endif
const struct pf_addr *saddr, const struct pf_addr *daddr,
u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack,
u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, int tag,
- u_int16_t rtag, struct ether_header *eh, struct ifnet *ifp)
+ struct ether_header *eh, struct ifnet *ifp)
{
struct mbuf *m;
- int len, tlen;
+ int len = 0, tlen; /* make the compiler happy */
#ifdef INET
- struct ip *h;
+ struct ip *h = NULL; /* make the compiler happy */
#endif /* INET */
#ifdef INET6
- struct ip6_hdr *h6;
+ struct ip6_hdr *h6 = NULL; /* make the compiler happy */
#endif /* INET6 */
- struct tcphdr *th;
- char *opt;
- struct pf_mtag *pf_mtag;
+ struct tcphdr *th = NULL; /* make the compiler happy */
+ char *opt;
/* maximum segment size tcp option */
tlen = sizeof(struct tcphdr);
@@ -1588,24 +1628,44 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af,
m = m_gethdr(M_DONTWAIT, MT_HEADER);
if (m == NULL)
return;
- if ((pf_mtag = pf_get_mtag(m)) == NULL) {
- m_freem(m);
- return;
- }
- if (tag)
- pf_mtag->flags |= PF_TAG_GENERATED;
-
- pf_mtag->tag = rtag;
-
- if (r != NULL && r->rtableid >= 0)
- pf_mtag->rtableid = r->rtableid;
+#ifdef __FreeBSD__
+#ifdef MAC
+ if (replyto)
+ mac_create_mbuf_netlayer(replyto, m);
+ else
+ mac_create_mbuf_from_firewall(m);
+#else
+ (void)replyto;
+#endif
+#endif
+ if (tag) {
+#ifdef __FreeBSD__
+ m->m_flags |= M_SKIP_FIREWALL;
+#else
+ struct m_tag *mtag;
+ mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
+ if (mtag == NULL) {
+ m_freem(m);
+ return;
+ }
+ m_tag_prepend(m, mtag);
+#endif
+ }
#ifdef ALTQ
if (r != NULL && r->qid) {
- pf_mtag->qid = r->qid;
- /* add hints for ecn */
- pf_mtag->af = af;
- pf_mtag->hdr = mtod(m, struct ip *);
+ struct m_tag *mtag;
+ struct altq_tag *atag;
+
+ mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
+ if (mtag != NULL) {
+ atag = (struct altq_tag *)(mtag + 1);
+ atag->qid = r->qid;
+ /* add hints for ecn */
+ atag->af = af;
+ atag->hdr = mtod(m, struct ip *);
+ m_tag_prepend(m, mtag);
+ }
}
#endif /* ALTQ */
m->m_data += max_linkhdr;
@@ -1668,13 +1728,25 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af,
h->ip_v = 4;
h->ip_hl = sizeof(*h) >> 2;
h->ip_tos = IPTOS_LOWDELAY;
- h->ip_len = htons(len);
+#ifdef __FreeBSD__
+ h->ip_off = path_mtu_discovery ? IP_DF : 0;
+ h->ip_len = len;
+#else
h->ip_off = htons(ip_mtudisc ? IP_DF : 0);
+ h->ip_len = htons(len);
+#endif
h->ip_ttl = ttl ? ttl : ip_defttl;
h->ip_sum = 0;
if (eh == NULL) {
+#ifdef __FreeBSD__
+ PF_UNLOCK();
ip_output(m, (void *)NULL, (void *)NULL, 0,
(void *)NULL, (void *)NULL);
+ PF_LOCK();
+#else /* ! __FreeBSD__ */
+ ip_output(m, (void *)NULL, (void *)NULL, 0,
+ (void *)NULL, (void *)NULL);
+#endif
} else {
struct route ro;
struct rtentry rt;
@@ -1691,8 +1763,16 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af,
bcopy(eh->ether_dhost, e->ether_shost, ETHER_ADDR_LEN);
bcopy(eh->ether_shost, e->ether_dhost, ETHER_ADDR_LEN);
e->ether_type = eh->ether_type;
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+ /* XXX_IMPORT: later */
+ ip_output(m, (void *)NULL, &ro, 0,
+ (void *)NULL, (void *)NULL);
+ PF_LOCK();
+#else /* ! __FreeBSD__ */
ip_output(m, (void *)NULL, &ro, IP_ROUTETOETHER,
(void *)NULL, (void *)NULL);
+#endif
}
break;
#endif /* INET */
@@ -1705,7 +1785,13 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af,
h6->ip6_vfc |= IPV6_VERSION;
h6->ip6_hlim = IPV6_DEFHLIM;
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+ ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
+ PF_LOCK();
+#else
ip6_output(m, NULL, NULL, 0, NULL, NULL);
+#endif
break;
#endif /* INET6 */
}
@@ -1715,36 +1801,72 @@ void
pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
struct pf_rule *r)
{
- struct pf_mtag *pf_mtag;
+#ifdef ALTQ
+ struct m_tag *mtag;
+#endif
struct mbuf *m0;
+#ifdef __FreeBSD__
+ struct ip *ip;
+#endif
+#ifdef __FreeBSD__
+ m0 = m_copypacket(m, M_DONTWAIT);
+ if (m0 == NULL)
+ return;
+ m0->m_flags |= M_SKIP_FIREWALL;
+#else
+ mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
+ if (mtag == NULL)
+ return;
m0 = m_copy(m, 0, M_COPYALL);
-
- if ((pf_mtag = pf_get_mtag(m0)) == NULL)
+ if (m0 == NULL) {
+ m_tag_free(mtag);
return;
- pf_mtag->flags |= PF_TAG_GENERATED;
-
- if (r->rtableid >= 0)
- pf_mtag->rtableid = r->rtableid;
+ }
+ m_tag_prepend(m0, mtag);
+#endif
#ifdef ALTQ
if (r->qid) {
- pf_mtag->qid = r->qid;
- /* add hints for ecn */
- pf_mtag->af = af;
- pf_mtag->hdr = mtod(m0, struct ip *);
+ struct altq_tag *atag;
+
+ mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
+ if (mtag != NULL) {
+ atag = (struct altq_tag *)(mtag + 1);
+ atag->qid = r->qid;
+ /* add hints for ecn */
+ atag->af = af;
+ atag->hdr = mtod(m0, struct ip *);
+ m_tag_prepend(m0, mtag);
+ }
}
#endif /* ALTQ */
switch (af) {
#ifdef INET
case AF_INET:
+#ifdef __FreeBSD__
+ /* icmp_error() expects host byte ordering */
+ ip = mtod(m0, struct ip *);
+ NTOHS(ip->ip_len);
+ NTOHS(ip->ip_off);
+ PF_UNLOCK();
icmp_error(m0, type, code, 0, 0);
+ PF_LOCK();
+#else
+ icmp_error(m0, type, code, 0, (void *)NULL);
+#endif
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
icmp6_error(m0, type, code, 0);
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
break;
#endif /* INET6 */
}
@@ -1847,71 +1969,58 @@ pf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g)
return (pf_match(op, a1, a2, g));
}
-struct pf_mtag *
-pf_find_mtag(struct mbuf *m)
+struct pf_tag *
+pf_get_tag(struct mbuf *m)
{
struct m_tag *mtag;
- if ((mtag = m_tag_find(m, PACKET_TAG_PF, NULL)) == NULL)
+ if ((mtag = m_tag_find(m, PACKET_TAG_PF_TAG, NULL)) != NULL)
+ return ((struct pf_tag *)(mtag + 1));
+ else
return (NULL);
-
- return ((struct pf_mtag *)(mtag + 1));
-}
-
-struct pf_mtag *
-pf_get_mtag(struct mbuf *m)
-{
- struct m_tag *mtag;
-
- if ((mtag = m_tag_find(m, PACKET_TAG_PF, NULL)) == NULL) {
- mtag = m_tag_get(PACKET_TAG_PF, sizeof(struct pf_mtag),
- M_NOWAIT);
- if (mtag == NULL)
- return (NULL);
- bzero(mtag + 1, sizeof(struct pf_mtag));
- m_tag_prepend(m, mtag);
- }
-
- return ((struct pf_mtag *)(mtag + 1));
}
int
-pf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_mtag *pf_mtag,
- int *tag)
+pf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_tag **pftag, int *tag)
{
- if (*tag == -1)
- *tag = pf_mtag->tag;
+ if (*tag == -1) { /* find mbuf tag */
+ *pftag = pf_get_tag(m);
+ if (*pftag != NULL)
+ *tag = (*pftag)->tag;
+ else
+ *tag = 0;
+ }
return ((!r->match_tag_not && r->match_tag == *tag) ||
(r->match_tag_not && r->match_tag != *tag));
}
int
-pf_tag_packet(struct mbuf *m, struct pf_mtag *pf_mtag, int tag, int rtableid)
+pf_tag_packet(struct mbuf *m, struct pf_tag *pftag, int tag)
{
- if (tag <= 0 && rtableid < 0)
+ struct m_tag *mtag;
+
+ if (tag <= 0)
return (0);
- if (pf_mtag == NULL)
- if ((pf_mtag = pf_get_mtag(m)) == NULL)
+ if (pftag == NULL) {
+ mtag = m_tag_get(PACKET_TAG_PF_TAG, sizeof(*pftag), M_NOWAIT);
+ if (mtag == NULL)
return (1);
- if (tag > 0)
- pf_mtag->tag = tag;
- if (rtableid >= 0)
- pf_mtag->rtableid = rtableid;
+ ((struct pf_tag *)(mtag + 1))->tag = tag;
+ m_tag_prepend(m, mtag);
+ } else
+ pftag->tag = tag;
return (0);
}
static void
pf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n,
- struct pf_rule **r, struct pf_rule **a, int *match)
+ struct pf_rule **r, struct pf_rule **a)
{
struct pf_anchor_stackframe *f;
- (*r)->anchor->match = 0;
- if (match)
- *match = 0;
if (*depth >= sizeof(pf_anchor_stack) /
sizeof(pf_anchor_stack[0])) {
printf("pf_step_into_anchor: stack overflow\n");
@@ -1938,23 +2047,17 @@ pf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n,
*r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
}
-int
+static void
pf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n,
- struct pf_rule **r, struct pf_rule **a, int *match)
+ struct pf_rule **r, struct pf_rule **a)
{
struct pf_anchor_stackframe *f;
- int quick = 0;
do {
if (*depth <= 0)
break;
f = pf_anchor_stack + *depth - 1;
if (f->parent != NULL && f->child != NULL) {
- if (f->child->match ||
- (match != NULL && *match)) {
- f->r->anchor->match = 1;
- *match = 0;
- }
f->child = RB_NEXT(pf_anchor_node, f->parent, f->child);
if (f->child != NULL) {
*rs = &f->child->ruleset;
@@ -1969,12 +2072,8 @@ pf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n,
if (*depth == 0 && a != NULL)
*a = NULL;
*rs = f->rs;
- if (f->r->anchor->match || (match != NULL && *match))
- quick = f->r->quick;
*r = TAILQ_NEXT(f->r, entries);
} while (*r == NULL);
-
- return (quick);
}
#ifdef INET6
@@ -2278,7 +2377,7 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high,
struct pf_src_node **sn)
{
- struct pf_state_cmp key;
+ struct pf_state key;
struct pf_addr init_addr;
u_int16_t cut;
@@ -2370,8 +2469,8 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
{
struct pf_rule *r, *rm = NULL;
struct pf_ruleset *ruleset = NULL;
+ struct pf_tag *pftag = NULL;
int tag = -1;
- int rtableid = -1;
int asd = 0;
r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr);
@@ -2389,7 +2488,8 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
}
r->evaluations++;
- if (pfi_kif_match(r->kif, kif) == r->ifnot)
+ if (r->kif != NULL &&
+ (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
r = r->skip[PF_SKIP_IFP].ptr;
else if (r->direction && r->direction != direction)
r = r->skip[PF_SKIP_DIR].ptr;
@@ -2397,8 +2497,7 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
r = r->skip[PF_SKIP_AF].ptr;
else if (r->proto && r->proto != pd->proto)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&src->addr, saddr, pd->af,
- src->neg, kif))
+ else if (PF_MISMATCHAW(&src->addr, saddr, pd->af, src->neg))
r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR :
PF_SKIP_DST_ADDR].ptr;
else if (src->port_op && !pf_match_port(src->port_op,
@@ -2406,16 +2505,15 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT :
PF_SKIP_DST_PORT].ptr;
else if (dst != NULL &&
- PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg, NULL))
+ PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
- else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af,
- 0, NULL))
+ else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af, 0))
r = TAILQ_NEXT(r, entries);
else if (dst != NULL && dst->port_op &&
!pf_match_port(dst->port_op, dst->port[0],
dst->port[1], dport))
r = r->skip[PF_SKIP_DST_PORT].ptr;
- else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
+ else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
r = TAILQ_NEXT(r, entries);
else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto !=
IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m,
@@ -2424,19 +2522,15 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
else {
if (r->tag)
tag = r->tag;
- if (r->rtableid >= 0)
- rtableid = r->rtableid;
if (r->anchor == NULL) {
rm = r;
} else
- pf_step_into_anchor(&asd, &ruleset, rs_num,
- &r, NULL, NULL);
+ pf_step_into_anchor(&asd, &ruleset, rs_num, &r, NULL);
}
if (r == NULL)
- pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r,
- NULL, NULL);
+ pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r, NULL);
}
- if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid))
+ if (pf_tag_packet(m, pftag, tag))
return (NULL);
if (rm != NULL && (rm->action == PF_NONAT ||
rm->action == PF_NORDR || rm->action == PF_NOBINAT))
@@ -2596,35 +2690,56 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
}
int
-pf_socket_lookup(int direction, struct pf_pdesc *pd)
+#ifdef __FreeBSD__
+pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd,
+ struct inpcb *inp_arg)
+#else
+pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd)
+#endif
{
struct pf_addr *saddr, *daddr;
u_int16_t sport, dport;
+#ifdef __FreeBSD__
+ struct inpcbinfo *pi;
+#else
struct inpcbtable *tb;
+#endif
struct inpcb *inp;
- if (pd == NULL)
- return (-1);
- pd->lookup.uid = UID_MAX;
- pd->lookup.gid = GID_MAX;
- pd->lookup.pid = NO_PID;
+ *uid = UID_MAX;
+ *gid = GID_MAX;
+#ifdef __FreeBSD__
+ if (inp_arg != NULL) {
+ INP_LOCK_ASSERT(inp_arg);
+ if (inp_arg->inp_socket) {
+ *uid = inp_arg->inp_socket->so_cred->cr_uid;
+ *gid = inp_arg->inp_socket->so_cred->cr_groups[0];
+ return (1);
+ } else
+ return (0);
+ }
+#endif
switch (pd->proto) {
case IPPROTO_TCP:
- if (pd->hdr.tcp == NULL)
- return (-1);
sport = pd->hdr.tcp->th_sport;
dport = pd->hdr.tcp->th_dport;
+#ifdef __FreeBSD__
+ pi = &tcbinfo;
+#else
tb = &tcbtable;
+#endif
break;
case IPPROTO_UDP:
- if (pd->hdr.udp == NULL)
- return (-1);
sport = pd->hdr.udp->uh_sport;
dport = pd->hdr.udp->uh_dport;
+#ifdef __FreeBSD__
+ pi = &udbinfo;
+#else
tb = &udbtable;
+#endif
break;
default:
- return (-1);
+ return (0);
}
if (direction == PF_IN) {
saddr = pd->src;
@@ -2641,32 +2756,72 @@ pf_socket_lookup(int direction, struct pf_pdesc *pd)
switch (pd->af) {
#ifdef INET
case AF_INET:
+#ifdef __FreeBSD__
+ INP_INFO_RLOCK(pi); /* XXX LOR */
+ inp = in_pcblookup_hash(pi, saddr->v4, sport, daddr->v4,
+ dport, 0, NULL);
+ if (inp == NULL) {
+ inp = in_pcblookup_hash(pi, saddr->v4, sport,
+ daddr->v4, dport, INPLOOKUP_WILDCARD, NULL);
+ if(inp == NULL) {
+ INP_INFO_RUNLOCK(pi);
+ return (0);
+ }
+ }
+#else
inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport);
if (inp == NULL) {
inp = in_pcblookup_listen(tb, daddr->v4, dport, 0);
if (inp == NULL)
- return (-1);
+ return (0);
}
+#endif
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
+#ifdef __FreeBSD__
+ INP_INFO_RLOCK(pi);
+ inp = in6_pcblookup_hash(pi, &saddr->v6, sport,
+ &daddr->v6, dport, 0, NULL);
+ if (inp == NULL) {
+ inp = in6_pcblookup_hash(pi, &saddr->v6, sport,
+ &daddr->v6, dport, INPLOOKUP_WILDCARD, NULL);
+ if (inp == NULL) {
+ INP_INFO_RUNLOCK(pi);
+ return (0);
+ }
+ }
+#else
inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6,
dport);
if (inp == NULL) {
inp = in6_pcblookup_listen(tb, &daddr->v6, dport, 0);
if (inp == NULL)
- return (-1);
+ return (0);
}
+#endif
break;
#endif /* INET6 */
default:
- return (-1);
+ return (0);
}
- pd->lookup.uid = inp->inp_socket->so_euid;
- pd->lookup.gid = inp->inp_socket->so_egid;
- pd->lookup.pid = inp->inp_socket->so_cpid;
+#ifdef __FreeBSD__
+ INP_LOCK(inp);
+ if ((inp->inp_socket == NULL) || (inp->inp_socket->so_cred == NULL)) {
+ INP_UNLOCK(inp);
+ INP_INFO_RUNLOCK(pi);
+ return (0);
+ }
+ *uid = inp->inp_socket->so_cred->cr_uid;
+ *gid = inp->inp_socket->so_cred->cr_groups[0];
+ INP_UNLOCK(inp);
+ INP_INFO_RUNLOCK(pi);
+#else
+ *uid = inp->inp_socket->so_euid;
+ *gid = inp->inp_socket->so_egid;
+#endif
return (1);
}
@@ -2760,7 +2915,7 @@ pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer)
struct route_in6 ro6;
#endif /* INET6 */
struct rtentry *rt = NULL;
- int hlen;
+ int hlen = 0; /* make the compiler happy */
u_int16_t mss = tcp_mssdflt;
switch (af) {
@@ -2772,7 +2927,15 @@ pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer)
dst->sin_family = AF_INET;
dst->sin_len = sizeof(*dst);
dst->sin_addr = addr->v4;
+#ifdef __FreeBSD__
+#ifdef RTF_PRCLONING
+ rtalloc_ign(&ro, (RTF_CLONING | RTF_PRCLONING));
+#else /* !RTF_PRCLONING */
+ rtalloc_ign(&ro, RTF_CLONING);
+#endif
+#else /* ! __FreeBSD__ */
rtalloc_noclone(&ro, NO_CLONING);
+#endif
rt = ro.ro_rt;
break;
#endif /* INET */
@@ -2784,7 +2947,16 @@ pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer)
dst6->sin6_family = AF_INET6;
dst6->sin6_len = sizeof(*dst6);
dst6->sin6_addr = addr->v6;
+#ifdef __FreeBSD__
+#ifdef RTF_PRCLONING
+ rtalloc_ign((struct route *)&ro6,
+ (RTF_CLONING | RTF_PRCLONING));
+#else /* !RTF_PRCLONING */
+ rtalloc_ign((struct route *)&ro6, RTF_CLONING);
+#endif
+#else /* ! __FreeBSD__ */
rtalloc_noclone((struct route *)&ro6, NO_CLONING);
+#endif
rt = ro6.ro_rt;
break;
#endif /* INET6 */
@@ -2829,29 +3001,43 @@ pf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr)
int
pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
struct pfi_kif *kif, struct mbuf *m, int off, void *h,
+#ifdef __FreeBSD__
+ struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
+ struct ifqueue *ifq, struct inpcb *inp)
+#else
struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
struct ifqueue *ifq)
+#endif
{
struct pf_rule *nr = NULL;
struct pf_addr *saddr = pd->src, *daddr = pd->dst;
struct tcphdr *th = pd->hdr.tcp;
u_int16_t bport, nport = 0;
sa_family_t af = pd->af;
+ int lookup = -1;
+ uid_t uid;
+ gid_t gid;
struct pf_rule *r, *a = NULL;
struct pf_ruleset *ruleset = NULL;
struct pf_src_node *nsn = NULL;
u_short reason;
int rewrite = 0;
- int tag = -1, rtableid = -1;
+ struct pf_tag *pftag = NULL;
+ int tag = -1;
u_int16_t mss = tcp_mssdflt;
int asd = 0;
- int match = 0;
if (pf_check_congestion(ifq)) {
REASON_SET(&reason, PFRES_CONGEST);
return (PF_DROP);
}
+#if defined(__FreeBSD__) && defined(PF_MPSAFE_UGID)
+ PF_UNLOCK();
+ lookup = pf_socket_lookup(&uid, &gid, direction, pd, inp);
+ PF_LOCK();
+#endif
+
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
if (direction == PF_OUT) {
@@ -2886,7 +3072,8 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
while (r != NULL) {
r->evaluations++;
- if (pfi_kif_match(r->kif, kif) == r->ifnot)
+ if (r->kif != NULL &&
+ (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
r = r->skip[PF_SKIP_IFP].ptr;
else if (r->direction && r->direction != direction)
r = r->skip[PF_SKIP_DIR].ptr;
@@ -2894,37 +3081,43 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
r = r->skip[PF_SKIP_AF].ptr;
else if (r->proto && r->proto != IPPROTO_TCP)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
- r->src.neg, kif))
+ else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
else if (r->src.port_op && !pf_match_port(r->src.port_op,
r->src.port[0], r->src.port[1], th->th_sport))
r = r->skip[PF_SKIP_SRC_PORT].ptr;
- else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
- r->dst.neg, NULL))
+ else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
r->dst.port[0], r->dst.port[1], th->th_dport))
r = r->skip[PF_SKIP_DST_PORT].ptr;
- else if (r->tos && !(r->tos == pd->tos))
+ else if (r->tos && !(r->tos & pd->tos))
r = TAILQ_NEXT(r, entries);
else if (r->rule_flag & PFRULE_FRAGMENT)
r = TAILQ_NEXT(r, entries);
else if ((r->flagset & th->th_flags) != r->flags)
r = TAILQ_NEXT(r, entries);
- else if (r->uid.op && (pd->lookup.done || (pd->lookup.done =
- pf_socket_lookup(direction, pd), 1)) &&
+ else if (r->uid.op && (lookup != -1 || (lookup =
+#ifdef __FreeBSD__
+ pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
+#else
+ pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
+#endif
!pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
- pd->lookup.uid))
+ uid))
r = TAILQ_NEXT(r, entries);
- else if (r->gid.op && (pd->lookup.done || (pd->lookup.done =
- pf_socket_lookup(direction, pd), 1)) &&
+ else if (r->gid.op && (lookup != -1 || (lookup =
+#ifdef __FreeBSD__
+ pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
+#else
+ pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
+#endif
!pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
- pd->lookup.gid))
+ gid))
r = TAILQ_NEXT(r, entries);
else if (r->prob && r->prob <= arc4random())
r = TAILQ_NEXT(r, entries);
- else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
+ else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
r = TAILQ_NEXT(r, entries);
else if (r->os_fingerprint != PF_OSFP_ANY && !pf_osfp_match(
pf_osfp_fingerprint(pd, m, off, th), r->os_fingerprint))
@@ -2932,10 +3125,7 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
else {
if (r->tag)
tag = r->tag;
- if (r->rtableid >= 0)
- rtableid = r->rtableid;
if (r->anchor == NULL) {
- match = 1;
*rm = r;
*am = a;
*rsm = ruleset;
@@ -2944,11 +3134,11 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
r = TAILQ_NEXT(r, entries);
} else
pf_step_into_anchor(&asd, &ruleset,
- PF_RULESET_FILTER, &r, &a, &match);
+ PF_RULESET_FILTER, &r, &a);
}
- if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
- PF_RULESET_FILTER, &r, &a, &match))
- break;
+ if (r == NULL)
+ pf_step_out_of_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
r = *rm;
a = *am;
@@ -2956,11 +3146,10 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
REASON_SET(&reason, PFRES_MATCH);
- if (r->log || (nr != NULL && nr->natpass && nr->log)) {
+ if (r->log) {
if (rewrite)
- m_copyback(m, off, sizeof(*th), th);
- PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
- a, ruleset, pd);
+ m_copyback(m, off, sizeof(*th), (caddr_t)th);
+ PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
}
if ((r->action == PF_DROP) &&
@@ -2988,10 +3177,14 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
ack++;
if (th->th_flags & TH_FIN)
ack++;
+#ifdef __FreeBSD__
+ pf_send_tcp(m, r, af, pd->dst,
+#else
pf_send_tcp(r, af, pd->dst,
+#endif
pd->src, th->th_dport, th->th_sport,
ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0,
- r->return_ttl, 1, 0, pd->eh, kif->pfik_ifp);
+ r->return_ttl, 1, pd->eh, kif->pfik_ifp);
} else if ((af == AF_INET) && r->return_icmp)
pf_send_icmp(m, r->return_icmp >> 8,
r->return_icmp & 255, af, r);
@@ -3003,7 +3196,7 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
if (r->action == PF_DROP)
return (PF_DROP);
- if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
+ if (pf_tag_packet(m, pftag, tag)) {
REASON_SET(&reason, PFRES_MEMORY);
return (PF_DROP);
}
@@ -3023,7 +3216,7 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
REASON_SET(&reason, PFRES_MAXSTATES);
goto cleanup;
}
- /* src node for filter rule */
+ /* src node for flter rule */
if ((r->rule_flag & PFRULE_SRCTRACK ||
r->rpool.opts & PF_POOL_STICKYADDR) &&
pf_insert_src_node(&sn, r, saddr, af) != 0) {
@@ -3063,9 +3256,7 @@ cleanup:
s->anchor.ptr = a;
STATE_INC_COUNTERS(s);
s->allow_opts = r->allow_opts;
- s->log = r->log & PF_LOG_ALL;
- if (nr != NULL)
- s->log |= nr->log & PF_LOG_ALL;
+ s->log = r->log & 2;
s->proto = IPPROTO_TCP;
s->direction = direction;
s->af = af;
@@ -3100,8 +3291,7 @@ cleanup:
if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
r->keep_state == PF_STATE_MODULATE) {
/* Generate sequence number modulator */
- while ((s->src.seqdiff =
- tcp_rndiss_next() - s->src.seqlo) == 0)
+ while ((s->src.seqdiff = htonl(arc4random())) == 0)
;
pf_change_a(&th->th_seq, &th->th_sum,
htonl(s->src.seqlo + s->src.seqdiff), 0);
@@ -3192,9 +3382,13 @@ cleanup:
mss = pf_calc_mss(saddr, af, mss);
mss = pf_calc_mss(daddr, af, mss);
s->src.mss = mss;
+#ifdef __FreeBSD__
+ pf_send_tcp(NULL, r, af, daddr, saddr, th->th_dport,
+#else
pf_send_tcp(r, af, daddr, saddr, th->th_dport,
+#endif
th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1,
- TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL, NULL);
+ TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, NULL, NULL);
REASON_SET(&reason, PFRES_SYNPROXY);
return (PF_SYNPROXY_DROP);
}
@@ -3202,7 +3396,7 @@ cleanup:
/* copy back packet headers if we performed NAT operations */
if (rewrite)
- m_copyback(m, off, sizeof(*th), th);
+ m_copyback(m, off, sizeof(*th), (caddr_t)th);
return (PF_PASS);
}
@@ -3210,28 +3404,42 @@ cleanup:
int
pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
struct pfi_kif *kif, struct mbuf *m, int off, void *h,
+#ifdef __FreeBSD__
+ struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
+ struct ifqueue *ifq, struct inpcb *inp)
+#else
struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
struct ifqueue *ifq)
+#endif
{
struct pf_rule *nr = NULL;
struct pf_addr *saddr = pd->src, *daddr = pd->dst;
struct udphdr *uh = pd->hdr.udp;
u_int16_t bport, nport = 0;
sa_family_t af = pd->af;
+ int lookup = -1;
+ uid_t uid;
+ gid_t gid;
struct pf_rule *r, *a = NULL;
struct pf_ruleset *ruleset = NULL;
struct pf_src_node *nsn = NULL;
u_short reason;
int rewrite = 0;
- int tag = -1, rtableid = -1;
+ struct pf_tag *pftag = NULL;
+ int tag = -1;
int asd = 0;
- int match = 0;
if (pf_check_congestion(ifq)) {
REASON_SET(&reason, PFRES_CONGEST);
return (PF_DROP);
}
+#if defined(__FreeBSD__) && defined(PF_MPSAFE_UGID)
+ PF_UNLOCK();
+ lookup = pf_socket_lookup(&uid, &gid, direction, pd, inp);
+ PF_LOCK();
+#endif
+
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
if (direction == PF_OUT) {
@@ -3266,7 +3474,8 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
while (r != NULL) {
r->evaluations++;
- if (pfi_kif_match(r->kif, kif) == r->ifnot)
+ if (r->kif != NULL &&
+ (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
r = r->skip[PF_SKIP_IFP].ptr;
else if (r->direction && r->direction != direction)
r = r->skip[PF_SKIP_DIR].ptr;
@@ -3274,45 +3483,48 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
r = r->skip[PF_SKIP_AF].ptr;
else if (r->proto && r->proto != IPPROTO_UDP)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
- r->src.neg, kif))
+ else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
else if (r->src.port_op && !pf_match_port(r->src.port_op,
r->src.port[0], r->src.port[1], uh->uh_sport))
r = r->skip[PF_SKIP_SRC_PORT].ptr;
- else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
- r->dst.neg, NULL))
+ else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
r->dst.port[0], r->dst.port[1], uh->uh_dport))
r = r->skip[PF_SKIP_DST_PORT].ptr;
- else if (r->tos && !(r->tos == pd->tos))
+ else if (r->tos && !(r->tos & pd->tos))
r = TAILQ_NEXT(r, entries);
else if (r->rule_flag & PFRULE_FRAGMENT)
r = TAILQ_NEXT(r, entries);
- else if (r->uid.op && (pd->lookup.done || (pd->lookup.done =
- pf_socket_lookup(direction, pd), 1)) &&
+ else if (r->uid.op && (lookup != -1 || (lookup =
+#ifdef __FreeBSD__
+ pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
+#else
+ pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
+#endif
!pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
- pd->lookup.uid))
+ uid))
r = TAILQ_NEXT(r, entries);
- else if (r->gid.op && (pd->lookup.done || (pd->lookup.done =
- pf_socket_lookup(direction, pd), 1)) &&
+ else if (r->gid.op && (lookup != -1 || (lookup =
+#ifdef __FreeBSD__
+ pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
+#else
+ pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
+#endif
!pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
- pd->lookup.gid))
+ gid))
r = TAILQ_NEXT(r, entries);
else if (r->prob && r->prob <= arc4random())
r = TAILQ_NEXT(r, entries);
- else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
+ else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
r = TAILQ_NEXT(r, entries);
else if (r->os_fingerprint != PF_OSFP_ANY)
r = TAILQ_NEXT(r, entries);
else {
if (r->tag)
tag = r->tag;
- if (r->rtableid >= 0)
- rtableid = r->rtableid;
if (r->anchor == NULL) {
- match = 1;
*rm = r;
*am = a;
*rsm = ruleset;
@@ -3321,11 +3533,11 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
r = TAILQ_NEXT(r, entries);
} else
pf_step_into_anchor(&asd, &ruleset,
- PF_RULESET_FILTER, &r, &a, &match);
+ PF_RULESET_FILTER, &r, &a);
}
- if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
- PF_RULESET_FILTER, &r, &a, &match))
- break;
+ if (r == NULL)
+ pf_step_out_of_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
r = *rm;
a = *am;
@@ -3333,11 +3545,10 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
REASON_SET(&reason, PFRES_MATCH);
- if (r->log || (nr != NULL && nr->natpass && nr->log)) {
+ if (r->log) {
if (rewrite)
- m_copyback(m, off, sizeof(*uh), uh);
- PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
- a, ruleset, pd);
+ m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
+ PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
}
if ((r->action == PF_DROP) &&
@@ -3366,7 +3577,7 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
if (r->action == PF_DROP)
return (PF_DROP);
- if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
+ if (pf_tag_packet(m, pftag, tag)) {
REASON_SET(&reason, PFRES_MEMORY);
return (PF_DROP);
}
@@ -3382,7 +3593,7 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
REASON_SET(&reason, PFRES_MAXSTATES);
goto cleanup;
}
- /* src node for filter rule */
+ /* src node for flter rule */
if ((r->rule_flag & PFRULE_SRCTRACK ||
r->rpool.opts & PF_POOL_STICKYADDR) &&
pf_insert_src_node(&sn, r, saddr, af) != 0) {
@@ -3422,9 +3633,7 @@ cleanup:
s->anchor.ptr = a;
STATE_INC_COUNTERS(s);
s->allow_opts = r->allow_opts;
- s->log = r->log & PF_LOG_ALL;
- if (nr != NULL)
- s->log |= nr->log & PF_LOG_ALL;
+ s->log = r->log & 2;
s->proto = IPPROTO_UDP;
s->direction = direction;
s->af = af;
@@ -3484,7 +3693,7 @@ cleanup:
/* copy back packet headers if we performed NAT operations */
if (rewrite)
- m_copyback(m, off, sizeof(*uh), uh);
+ m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
return (PF_PASS);
}
@@ -3501,16 +3710,17 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
struct pf_ruleset *ruleset = NULL;
struct pf_src_node *nsn = NULL;
u_short reason;
- u_int16_t icmpid, bport, nport = 0;
+ u_int16_t icmpid = 0, bport, nport = 0;
sa_family_t af = pd->af;
- u_int8_t icmptype, icmpcode;
+ u_int8_t icmptype = 0; /* make the compiler happy */
+ u_int8_t icmpcode = 0; /* make the compiler happy */
int state_icmp = 0;
- int tag = -1, rtableid = -1;
+ struct pf_tag *pftag = NULL;
+ int tag = -1;
#ifdef INET6
int rewrite = 0;
#endif /* INET6 */
int asd = 0;
- int match = 0;
if (pf_check_congestion(ifq)) {
REASON_SET(&reason, PFRES_CONGEST);
@@ -3564,7 +3774,8 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
pd->hdr.icmp->icmp_cksum = pf_cksum_fixup(
pd->hdr.icmp->icmp_cksum, icmpid, nport, 0);
pd->hdr.icmp->icmp_id = nport;
- m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp);
+ m_copyback(m, off, ICMP_MINLEN,
+ (caddr_t)pd->hdr.icmp);
break;
#endif /* INET */
#ifdef INET6
@@ -3609,7 +3820,8 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
while (r != NULL) {
r->evaluations++;
- if (pfi_kif_match(r->kif, kif) == r->ifnot)
+ if (r->kif != NULL &&
+ (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
r = r->skip[PF_SKIP_IFP].ptr;
else if (r->direction && r->direction != direction)
r = r->skip[PF_SKIP_DIR].ptr;
@@ -3617,33 +3829,28 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
r = r->skip[PF_SKIP_AF].ptr;
else if (r->proto && r->proto != pd->proto)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
- r->src.neg, kif))
+ else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
- else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
- r->dst.neg, NULL))
+ else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (r->type && r->type != icmptype + 1)
r = TAILQ_NEXT(r, entries);
else if (r->code && r->code != icmpcode + 1)
r = TAILQ_NEXT(r, entries);
- else if (r->tos && !(r->tos == pd->tos))
+ else if (r->tos && !(r->tos & pd->tos))
r = TAILQ_NEXT(r, entries);
else if (r->rule_flag & PFRULE_FRAGMENT)
r = TAILQ_NEXT(r, entries);
else if (r->prob && r->prob <= arc4random())
r = TAILQ_NEXT(r, entries);
- else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
+ else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
r = TAILQ_NEXT(r, entries);
else if (r->os_fingerprint != PF_OSFP_ANY)
r = TAILQ_NEXT(r, entries);
else {
if (r->tag)
tag = r->tag;
- if (r->rtableid >= 0)
- rtableid = r->rtableid;
if (r->anchor == NULL) {
- match = 1;
*rm = r;
*am = a;
*rsm = ruleset;
@@ -3652,11 +3859,11 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
r = TAILQ_NEXT(r, entries);
} else
pf_step_into_anchor(&asd, &ruleset,
- PF_RULESET_FILTER, &r, &a, &match);
+ PF_RULESET_FILTER, &r, &a);
}
- if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
- PF_RULESET_FILTER, &r, &a, &match))
- break;
+ if (r == NULL)
+ pf_step_out_of_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
r = *rm;
a = *am;
@@ -3664,20 +3871,19 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
REASON_SET(&reason, PFRES_MATCH);
- if (r->log || (nr != NULL && nr->natpass && nr->log)) {
+ if (r->log) {
#ifdef INET6
if (rewrite)
m_copyback(m, off, sizeof(struct icmp6_hdr),
- pd->hdr.icmp6);
+ (caddr_t)pd->hdr.icmp6);
#endif /* INET6 */
- PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
- a, ruleset, pd);
+ PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
}
if (r->action != PF_PASS)
return (PF_DROP);
- if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
+ if (pf_tag_packet(m, pftag, tag)) {
REASON_SET(&reason, PFRES_MEMORY);
return (PF_DROP);
}
@@ -3693,7 +3899,7 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
REASON_SET(&reason, PFRES_MAXSTATES);
goto cleanup;
}
- /* src node for filter rule */
+ /* src node for flter rule */
if ((r->rule_flag & PFRULE_SRCTRACK ||
r->rpool.opts & PF_POOL_STICKYADDR) &&
pf_insert_src_node(&sn, r, saddr, af) != 0) {
@@ -3733,9 +3939,7 @@ cleanup:
s->anchor.ptr = a;
STATE_INC_COUNTERS(s);
s->allow_opts = r->allow_opts;
- s->log = r->log & PF_LOG_ALL;
- if (nr != NULL)
- s->log |= nr->log & PF_LOG_ALL;
+ s->log = r->log & 2;
s->proto = pd->proto;
s->direction = direction;
s->af = af;
@@ -3795,7 +3999,7 @@ cleanup:
/* copy back packet headers if we performed IPv6 NAT operations */
if (rewrite)
m_copyback(m, off, sizeof(struct icmp6_hdr),
- pd->hdr.icmp6);
+ (caddr_t)pd->hdr.icmp6);
#endif /* INET6 */
return (PF_PASS);
@@ -3813,9 +4017,9 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
struct pf_addr *saddr = pd->src, *daddr = pd->dst;
sa_family_t af = pd->af;
u_short reason;
- int tag = -1, rtableid = -1;
+ struct pf_tag *pftag = NULL;
+ int tag = -1;
int asd = 0;
- int match = 0;
if (pf_check_congestion(ifq)) {
REASON_SET(&reason, PFRES_CONGEST);
@@ -3872,7 +4076,8 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
while (r != NULL) {
r->evaluations++;
- if (pfi_kif_match(r->kif, kif) == r->ifnot)
+ if (r->kif != NULL &&
+ (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
r = r->skip[PF_SKIP_IFP].ptr;
else if (r->direction && r->direction != direction)
r = r->skip[PF_SKIP_DIR].ptr;
@@ -3880,29 +4085,24 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
r = r->skip[PF_SKIP_AF].ptr;
else if (r->proto && r->proto != pd->proto)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&r->src.addr, pd->src, af,
- r->src.neg, kif))
+ else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
- else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af,
- r->dst.neg, NULL))
+ else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
- else if (r->tos && !(r->tos == pd->tos))
+ else if (r->tos && !(r->tos & pd->tos))
r = TAILQ_NEXT(r, entries);
else if (r->rule_flag & PFRULE_FRAGMENT)
r = TAILQ_NEXT(r, entries);
else if (r->prob && r->prob <= arc4random())
r = TAILQ_NEXT(r, entries);
- else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
+ else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
r = TAILQ_NEXT(r, entries);
else if (r->os_fingerprint != PF_OSFP_ANY)
r = TAILQ_NEXT(r, entries);
else {
if (r->tag)
tag = r->tag;
- if (r->rtableid >= 0)
- rtableid = r->rtableid;
if (r->anchor == NULL) {
- match = 1;
*rm = r;
*am = a;
*rsm = ruleset;
@@ -3911,11 +4111,11 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
r = TAILQ_NEXT(r, entries);
} else
pf_step_into_anchor(&asd, &ruleset,
- PF_RULESET_FILTER, &r, &a, &match);
+ PF_RULESET_FILTER, &r, &a);
}
- if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
- PF_RULESET_FILTER, &r, &a, &match))
- break;
+ if (r == NULL)
+ pf_step_out_of_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
r = *rm;
a = *am;
@@ -3923,9 +4123,8 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
REASON_SET(&reason, PFRES_MATCH);
- if (r->log || (nr != NULL && nr->natpass && nr->log))
- PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
- a, ruleset, pd);
+ if (r->log)
+ PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
if ((r->action == PF_DROP) &&
((r->rule_flag & PFRULE_RETURNICMP) ||
@@ -3964,7 +4163,7 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
if (r->action != PF_PASS)
return (PF_DROP);
- if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
+ if (pf_tag_packet(m, pftag, tag)) {
REASON_SET(&reason, PFRES_MEMORY);
return (PF_DROP);
}
@@ -3980,7 +4179,7 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
REASON_SET(&reason, PFRES_MAXSTATES);
goto cleanup;
}
- /* src node for filter rule */
+ /* src node for flter rule */
if ((r->rule_flag & PFRULE_SRCTRACK ||
r->rpool.opts & PF_POOL_STICKYADDR) &&
pf_insert_src_node(&sn, r, saddr, af) != 0) {
@@ -4020,9 +4219,7 @@ cleanup:
s->anchor.ptr = a;
STATE_INC_COUNTERS(s);
s->allow_opts = r->allow_opts;
- s->log = r->log & PF_LOG_ALL;
- if (nr != NULL)
- s->log |= nr->log & PF_LOG_ALL;
+ s->log = r->log & 2;
s->proto = pd->proto;
s->direction = direction;
s->af = af;
@@ -4082,14 +4279,15 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
struct pf_ruleset *ruleset = NULL;
sa_family_t af = pd->af;
u_short reason;
+ struct pf_tag *pftag = NULL;
int tag = -1;
int asd = 0;
- int match = 0;
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
while (r != NULL) {
r->evaluations++;
- if (pfi_kif_match(r->kif, kif) == r->ifnot)
+ if (r->kif != NULL &&
+ (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
r = r->skip[PF_SKIP_IFP].ptr;
else if (r->direction && r->direction != direction)
r = r->skip[PF_SKIP_DIR].ptr;
@@ -4097,13 +4295,11 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
r = r->skip[PF_SKIP_AF].ptr;
else if (r->proto && r->proto != pd->proto)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&r->src.addr, pd->src, af,
- r->src.neg, kif))
+ else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
- else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af,
- r->dst.neg, NULL))
+ else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
- else if (r->tos && !(r->tos == pd->tos))
+ else if (r->tos && !(r->tos & pd->tos))
r = TAILQ_NEXT(r, entries);
else if (r->src.port_op || r->dst.port_op ||
r->flagset || r->type || r->code ||
@@ -4111,11 +4307,10 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
r = TAILQ_NEXT(r, entries);
else if (r->prob && r->prob <= arc4random())
r = TAILQ_NEXT(r, entries);
- else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
+ else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
r = TAILQ_NEXT(r, entries);
else {
if (r->anchor == NULL) {
- match = 1;
*rm = r;
*am = a;
*rsm = ruleset;
@@ -4124,11 +4319,11 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
r = TAILQ_NEXT(r, entries);
} else
pf_step_into_anchor(&asd, &ruleset,
- PF_RULESET_FILTER, &r, &a, &match);
+ PF_RULESET_FILTER, &r, &a);
}
- if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
- PF_RULESET_FILTER, &r, &a, &match))
- break;
+ if (r == NULL)
+ pf_step_out_of_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
r = *rm;
a = *am;
@@ -4137,13 +4332,12 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
REASON_SET(&reason, PFRES_MATCH);
if (r->log)
- PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset,
- pd);
+ PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
if (r->action != PF_PASS)
return (PF_DROP);
- if (pf_tag_packet(m, pd->pf_mtag, tag, -1)) {
+ if (pf_tag_packet(m, pftag, tag)) {
REASON_SET(&reason, PFRES_MEMORY);
return (PF_DROP);
}
@@ -4156,7 +4350,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
u_short *reason)
{
- struct pf_state_cmp key;
+ struct pf_state key;
struct tcphdr *th = pd->hdr.tcp;
u_int16_t win = ntohs(th->th_win);
u_int32_t ack, end, seq, orig_seq;
@@ -4199,11 +4393,15 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
REASON_SET(reason, PFRES_SYNPROXY);
return (PF_DROP);
}
+#ifdef __FreeBSD__
+ pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst,
+#else
pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
+#endif
pd->src, th->th_dport, th->th_sport,
(*state)->src.seqhi, ntohl(th->th_seq) + 1,
TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1,
- 0, NULL, NULL);
+ NULL, NULL);
REASON_SET(reason, PFRES_SYNPROXY);
return (PF_SYNPROXY_DROP);
} else if (!(th->th_flags & TH_ACK) ||
@@ -4238,10 +4436,15 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
(*state)->src.max_win = MAX(ntohs(th->th_win), 1);
if ((*state)->dst.seqhi == 1)
(*state)->dst.seqhi = htonl(arc4random());
+#ifdef __FreeBSD__
+ pf_send_tcp(NULL, (*state)->rule.ptr, pd->af,
+ &src->addr,
+#else
pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
+#endif
&dst->addr, src->port, dst->port,
(*state)->dst.seqhi, 0, TH_SYN, 0,
- (*state)->src.mss, 0, 0, (*state)->tag, NULL, NULL);
+ (*state)->src.mss, 0, 0, NULL, NULL);
REASON_SET(reason, PFRES_SYNPROXY);
return (PF_SYNPROXY_DROP);
} else if (((th->th_flags & (TH_SYN|TH_ACK)) !=
@@ -4252,16 +4455,25 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
} else {
(*state)->dst.max_win = MAX(ntohs(th->th_win), 1);
(*state)->dst.seqlo = ntohl(th->th_seq);
+#ifdef __FreeBSD__
+ pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst,
+#else
pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
+#endif
pd->src, th->th_dport, th->th_sport,
ntohl(th->th_ack), ntohl(th->th_seq) + 1,
TH_ACK, (*state)->src.max_win, 0, 0, 0,
- (*state)->tag, NULL, NULL);
+ NULL, NULL);
+#ifdef __FreeBSD__
+ pf_send_tcp(NULL, (*state)->rule.ptr, pd->af,
+ &src->addr,
+#else
pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
+#endif
&dst->addr, src->port, dst->port,
(*state)->src.seqhi + 1, (*state)->src.seqlo + 1,
TH_ACK, (*state)->dst.max_win, 0, 0, 1,
- 0, NULL, NULL);
+ NULL, NULL);
(*state)->src.seqdiff = (*state)->dst.seqhi -
(*state)->src.seqlo;
(*state)->dst.seqdiff = (*state)->src.seqhi -
@@ -4304,7 +4516,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
/* Deferred generation of sequence number modulator */
if (dst->seqdiff && !src->seqdiff) {
- while ((src->seqdiff = tcp_rndiss_next() - seq) == 0)
+ while ((src->seqdiff = htonl(arc4random())) == 0)
;
ack = ntohl(th->th_ack) - dst->seqdiff;
pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
@@ -4393,25 +4605,6 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
ackskew = dst->seqlo - ack;
-
- /*
- * Need to demodulate the sequence numbers in any TCP SACK options
- * (Selective ACK). We could optionally validate the SACK values
- * against the current ACK window, either forwards or backwards, but
- * I'm not confident that SACK has been implemented properly
- * everywhere. It wouldn't surprise me if several stacks accidently
- * SACK too far backwards of previously ACKed data. There really aren't
- * any security implications of bad SACKing unless the target stack
- * doesn't validate the option length correctly. Someone trying to
- * spoof into a TCP connection won't bother blindly sending SACK
- * options anyway.
- */
- if (dst->seqdiff && (th->th_off << 2) > sizeof(struct tcphdr)) {
- if (pf_modulate_sack(m, off, pd, th, dst))
- copyback = 1;
- }
-
-
#define MAXACKWINDOW (0xffff + 1500) /* 1500 is an arbitrary fudge factor */
if (SEQ_GEQ(src->seqhi, end) &&
/* Last octet inside other's window space */
@@ -4422,8 +4615,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
(ackskew <= (MAXACKWINDOW << sws)) &&
/* Acking not more than one window forward */
((th->th_flags & TH_RST) == 0 || orig_seq == src->seqlo ||
- (orig_seq == src->seqlo + 1) || (pd->flags & PFDESC_IP_REAS) == 0)) {
- /* Require an exact/+1 sequence match on resets when possible */
+ (pd->flags & PFDESC_IP_REAS) == 0)) {
+ /* Require an exact sequence match on resets when possible */
if (dst->scrub || src->scrub) {
if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
@@ -4469,8 +4662,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
if (src->state >= TCPS_FIN_WAIT_2 &&
dst->state >= TCPS_FIN_WAIT_2)
(*state)->timeout = PFTM_TCP_CLOSED;
- else if (src->state >= TCPS_CLOSING &&
- dst->state >= TCPS_CLOSING)
+ else if (src->state >= TCPS_FIN_WAIT_2 ||
+ dst->state >= TCPS_FIN_WAIT_2)
(*state)->timeout = PFTM_TCP_FIN_WAIT;
else if (src->state < TCPS_ESTABLISHED ||
dst->state < TCPS_ESTABLISHED)
@@ -4516,10 +4709,9 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
printf("pf: loose state match: ");
pf_print_state(*state);
pf_print_flags(th->th_flags);
- printf(" seq=%u (%u) ack=%u len=%u ackskew=%d "
- "pkts=%llu:%llu\n", seq, orig_seq, ack, pd->p_len,
- ackskew, (*state)->packets[0],
- (*state)->packets[1]);
+ printf(" seq=%u ack=%u len=%u ackskew=%d pkts=%d:%d\n",
+ seq, ack, pd->p_len, ackskew,
+ (*state)->packets[0], (*state)->packets[1]);
}
if (dst->scrub || src->scrub) {
@@ -4556,11 +4748,15 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
(*state)->src.state == TCPS_SYN_SENT) {
/* Send RST for state mismatches during handshake */
if (!(th->th_flags & TH_RST))
+#ifdef __FreeBSD__
+ pf_send_tcp(m, (*state)->rule.ptr, pd->af,
+#else
pf_send_tcp((*state)->rule.ptr, pd->af,
+#endif
pd->dst, pd->src, th->th_dport,
th->th_sport, ntohl(th->th_ack), 0,
TH_RST, 0, 0,
- (*state)->rule.ptr->return_ttl, 1, 0,
+ (*state)->rule.ptr->return_ttl, 1,
pd->eh, kif->pfik_ifp);
src->seqlo = 0;
src->seqhi = 1;
@@ -4569,9 +4765,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
printf("pf: BAD state: ");
pf_print_state(*state);
pf_print_flags(th->th_flags);
- printf(" seq=%u (%u) ack=%u len=%u ackskew=%d "
- "pkts=%llu:%llu dir=%s,%s\n",
- seq, orig_seq, ack, pd->p_len, ackskew,
+ printf(" seq=%u ack=%u len=%u ackskew=%d pkts=%d:%d "
+ "dir=%s,%s\n", seq, ack, pd->p_len, ackskew,
(*state)->packets[0], (*state)->packets[1],
direction == PF_IN ? "in" : "out",
direction == (*state)->direction ? "fwd" : "rev");
@@ -4600,10 +4795,10 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum,
&th->th_sum, &(*state)->lan.addr,
(*state)->lan.port, 0, pd->af);
- m_copyback(m, off, sizeof(*th), th);
+ m_copyback(m, off, sizeof(*th), (caddr_t)th);
} else if (copyback) {
/* Copyback sequence modulation or stateful scrub changes */
- m_copyback(m, off, sizeof(*th), th);
+ m_copyback(m, off, sizeof(*th), (caddr_t)th);
}
return (PF_PASS);
@@ -4614,7 +4809,7 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
struct mbuf *m, int off, void *h, struct pf_pdesc *pd)
{
struct pf_state_peer *src, *dst;
- struct pf_state_cmp key;
+ struct pf_state key;
struct udphdr *uh = pd->hdr.udp;
key.af = pd->af;
@@ -4664,7 +4859,7 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum,
&uh->uh_sum, &(*state)->lan.addr,
(*state)->lan.port, 1, pd->af);
- m_copyback(m, off, sizeof(*uh), uh);
+ m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
}
return (PF_PASS);
@@ -4675,10 +4870,10 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason)
{
struct pf_addr *saddr = pd->src, *daddr = pd->dst;
- u_int16_t icmpid, *icmpsum;
- u_int8_t icmptype;
+ u_int16_t icmpid = 0; /* make the compiler happy */
+ u_int16_t *icmpsum = NULL; /* make the compiler happy */
+ u_int8_t icmptype = 0; /* make the compiler happy */
int state_icmp = 0;
- struct pf_state_cmp key;
switch (pd->proto) {
#ifdef INET
@@ -4716,6 +4911,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
* ICMP query/reply message not related to a TCP/UDP packet.
* Search for an ICMP state.
*/
+ struct pf_state key;
+
key.af = pd->af;
key.proto = pd->proto;
if (direction == PF_IN) {
@@ -4751,7 +4948,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
pd->hdr.icmp->icmp_id =
(*state)->gwy.port;
m_copyback(m, off, ICMP_MINLEN,
- pd->hdr.icmp);
+ (caddr_t)pd->hdr.icmp);
break;
#endif /* INET */
#ifdef INET6
@@ -4761,7 +4958,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
&(*state)->gwy.addr, 0);
m_copyback(m, off,
sizeof(struct icmp6_hdr),
- pd->hdr.icmp6);
+ (caddr_t)pd->hdr.icmp6);
break;
#endif /* INET6 */
}
@@ -4779,7 +4976,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
pd->hdr.icmp->icmp_id =
(*state)->lan.port;
m_copyback(m, off, ICMP_MINLEN,
- pd->hdr.icmp);
+ (caddr_t)pd->hdr.icmp);
break;
#endif /* INET */
#ifdef INET6
@@ -4789,7 +4986,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
&(*state)->lan.addr, 0);
m_copyback(m, off,
sizeof(struct icmp6_hdr),
- pd->hdr.icmp6);
+ (caddr_t)pd->hdr.icmp6);
break;
#endif /* INET6 */
}
@@ -4812,8 +5009,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
struct ip6_hdr h2_6;
int terminal = 0;
#endif /* INET6 */
- int ipoff2;
- int off2;
+ int ipoff2 = 0; /* make the compiler happy */
+ int off2 = 0; /* make the compiler happy */
pd2.af = pd->af;
switch (pd->af) {
@@ -4907,6 +5104,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
case IPPROTO_TCP: {
struct tcphdr th;
u_int32_t seq;
+ struct pf_state key;
struct pf_state_peer *src, *dst;
u_int8_t dws;
int copyback = 0;
@@ -5000,22 +5198,22 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
#ifdef INET
case AF_INET:
m_copyback(m, off, ICMP_MINLEN,
- pd->hdr.icmp);
+ (caddr_t)pd->hdr.icmp);
m_copyback(m, ipoff2, sizeof(h2),
- &h2);
+ (caddr_t)&h2);
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
m_copyback(m, off,
sizeof(struct icmp6_hdr),
- pd->hdr.icmp6);
+ (caddr_t)pd->hdr.icmp6);
m_copyback(m, ipoff2, sizeof(h2_6),
- &h2_6);
+ (caddr_t)&h2_6);
break;
#endif /* INET6 */
}
- m_copyback(m, off2, 8, &th);
+ m_copyback(m, off2, 8, (caddr_t)&th);
}
return (PF_PASS);
@@ -5023,6 +5221,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
}
case IPPROTO_UDP: {
struct udphdr uh;
+ struct pf_state key;
if (!pf_pull_hdr(m, off2, &uh, sizeof(uh),
NULL, reason, pd2.af)) {
@@ -5066,21 +5265,23 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
#ifdef INET
case AF_INET:
m_copyback(m, off, ICMP_MINLEN,
- pd->hdr.icmp);
- m_copyback(m, ipoff2, sizeof(h2), &h2);
+ (caddr_t)pd->hdr.icmp);
+ m_copyback(m, ipoff2, sizeof(h2),
+ (caddr_t)&h2);
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
m_copyback(m, off,
sizeof(struct icmp6_hdr),
- pd->hdr.icmp6);
+ (caddr_t)pd->hdr.icmp6);
m_copyback(m, ipoff2, sizeof(h2_6),
- &h2_6);
+ (caddr_t)&h2_6);
break;
#endif /* INET6 */
}
- m_copyback(m, off2, sizeof(uh), &uh);
+ m_copyback(m, off2, sizeof(uh),
+ (caddr_t)&uh);
}
return (PF_PASS);
@@ -5089,6 +5290,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
#ifdef INET
case IPPROTO_ICMP: {
struct icmp iih;
+ struct pf_state key;
if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN,
NULL, reason, pd2.af)) {
@@ -5128,9 +5330,12 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
pd2.ip_sum, icmpsum,
pd->ip_sum, 0, AF_INET);
}
- m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp);
- m_copyback(m, ipoff2, sizeof(h2), &h2);
- m_copyback(m, off2, ICMP_MINLEN, &iih);
+ m_copyback(m, off, ICMP_MINLEN,
+ (caddr_t)pd->hdr.icmp);
+ m_copyback(m, ipoff2, sizeof(h2),
+ (caddr_t)&h2);
+ m_copyback(m, off2, ICMP_MINLEN,
+ (caddr_t)&iih);
}
return (PF_PASS);
@@ -5140,6 +5345,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
#ifdef INET6
case IPPROTO_ICMPV6: {
struct icmp6_hdr iih;
+ struct pf_state key;
if (!pf_pull_hdr(m, off2, &iih,
sizeof(struct icmp6_hdr), NULL, reason, pd2.af)) {
@@ -5180,10 +5386,11 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
pd->ip_sum, 0, AF_INET6);
}
m_copyback(m, off, sizeof(struct icmp6_hdr),
- pd->hdr.icmp6);
- m_copyback(m, ipoff2, sizeof(h2_6), &h2_6);
+ (caddr_t)pd->hdr.icmp6);
+ m_copyback(m, ipoff2, sizeof(h2_6),
+ (caddr_t)&h2_6);
m_copyback(m, off2, sizeof(struct icmp6_hdr),
- &iih);
+ (caddr_t)&iih);
}
return (PF_PASS);
@@ -5191,6 +5398,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
}
#endif /* INET6 */
default: {
+ struct pf_state key;
+
key.af = pd2.af;
key.proto = pd2.proto;
if (direction == PF_IN) {
@@ -5225,17 +5434,18 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
#ifdef INET
case AF_INET:
m_copyback(m, off, ICMP_MINLEN,
- pd->hdr.icmp);
- m_copyback(m, ipoff2, sizeof(h2), &h2);
+ (caddr_t)pd->hdr.icmp);
+ m_copyback(m, ipoff2, sizeof(h2),
+ (caddr_t)&h2);
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
m_copyback(m, off,
sizeof(struct icmp6_hdr),
- pd->hdr.icmp6);
+ (caddr_t)pd->hdr.icmp6);
m_copyback(m, ipoff2, sizeof(h2_6),
- &h2_6);
+ (caddr_t)&h2_6);
break;
#endif /* INET6 */
}
@@ -5253,7 +5463,7 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
struct pf_pdesc *pd)
{
struct pf_state_peer *src, *dst;
- struct pf_state_cmp key;
+ struct pf_state key;
key.af = pd->af;
key.proto = pd->proto;
@@ -5381,24 +5591,16 @@ pf_pull_hdr(struct mbuf *m, int off, void *p, int len,
}
int
-pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif)
+pf_routable(struct pf_addr *addr, sa_family_t af)
{
struct sockaddr_in *dst;
- int ret = 1;
- int check_mpath;
- extern int ipmultipath;
#ifdef INET6
- extern int ip6_multipath;
struct sockaddr_in6 *dst6;
struct route_in6 ro;
#else
struct route ro;
#endif
- struct radix_node *rn;
- struct rtentry *rt;
- struct ifnet *ifp;
- check_mpath = 0;
bzero(&ro, sizeof(ro));
switch (af) {
case AF_INET:
@@ -5406,8 +5608,6 @@ pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif)
dst->sin_family = AF_INET;
dst->sin_len = sizeof(*dst);
dst->sin_addr = addr->v4;
- if (ipmultipath)
- check_mpath = 1;
break;
#ifdef INET6
case AF_INET6:
@@ -5415,50 +5615,28 @@ pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif)
dst6->sin6_family = AF_INET6;
dst6->sin6_len = sizeof(*dst6);
dst6->sin6_addr = addr->v6;
- if (ip6_multipath)
- check_mpath = 1;
break;
#endif /* INET6 */
default:
return (0);
}
- /* Skip checks for ipsec interfaces */
- if (kif != NULL && kif->pfik_ifp->if_type == IFT_ENC)
- goto out;
-
+#ifdef __FreeBSD__
+#ifdef RTF_PRCLONING
+ rtalloc_ign((struct route *)&ro, (RTF_CLONING | RTF_PRCLONING));
+#else /* !RTF_PRCLONING */
+ rtalloc_ign((struct route *)&ro, RTF_CLONING);
+#endif
+#else /* ! __FreeBSD__ */
rtalloc_noclone((struct route *)&ro, NO_CLONING);
+#endif
if (ro.ro_rt != NULL) {
- /* No interface given, this is a no-route check */
- if (kif == NULL)
- goto out;
-
- if (kif->pfik_ifp == NULL) {
- ret = 0;
- goto out;
- }
-
- /* Perform uRPF check if passed input interface */
- ret = 0;
- rn = (struct radix_node *)ro.ro_rt;
- do {
- rt = (struct rtentry *)rn;
- if (rt->rt_ifp->if_type == IFT_CARP)
- ifp = rt->rt_ifp->if_carpdev;
- else
- ifp = rt->rt_ifp;
-
- if (kif->pfik_ifp == ifp)
- ret = 1;
- rn = rn_mpath_next(rn);
- } while (check_mpath == 1 && rn != NULL && ret == 0);
- } else
- ret = 0;
-out:
- if (ro.ro_rt != NULL)
RTFREE(ro.ro_rt);
- return (ret);
+ return (1);
+ }
+
+ return (0);
}
int
@@ -5493,11 +5671,23 @@ pf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw)
return (0);
}
+#ifdef __FreeBSD__
+# ifdef RTF_PRCLONING
+ rtalloc_ign((struct route *)&ro, (RTF_CLONING|RTF_PRCLONING));
+# else /* !RTF_PRCLONING */
+ rtalloc_ign((struct route *)&ro, RTF_CLONING);
+# endif
+#else /* ! __FreeBSD__ */
rtalloc_noclone((struct route *)&ro, NO_CLONING);
+#endif
if (ro.ro_rt != NULL) {
+#ifdef __FreeBSD__
+ /* XXX_IMPORT: later */
+#else
if (ro.ro_rt->rt_labelid == aw->v.rtlabel)
ret = 1;
+#endif
RTFREE(ro.ro_rt);
}
@@ -5505,35 +5695,53 @@ pf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw)
}
#ifdef INET
+
void
pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
- struct pf_state *s, struct pf_pdesc *pd)
+ struct pf_state *s)
{
struct mbuf *m0, *m1;
+ struct m_tag *mtag;
struct route iproute;
- struct route *ro = NULL;
+ struct route *ro = NULL; /* XXX: was uninitialized */
struct sockaddr_in *dst;
struct ip *ip;
struct ifnet *ifp = NULL;
struct pf_addr naddr;
struct pf_src_node *sn = NULL;
int error = 0;
-#ifdef IPSEC
- struct m_tag *mtag;
-#endif /* IPSEC */
+#ifdef __FreeBSD__
+ int sw_csum;
+#endif
if (m == NULL || *m == NULL || r == NULL ||
(dir != PF_IN && dir != PF_OUT) || oifp == NULL)
panic("pf_route: invalid parameters");
- if (pd->pf_mtag->routed++ > 3) {
- m0 = *m;
- *m = NULL;
- goto bad;
+ if ((mtag = m_tag_find(*m, PACKET_TAG_PF_ROUTED, NULL)) == NULL) {
+ if ((mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 1, M_NOWAIT)) ==
+ NULL) {
+ m0 = *m;
+ *m = NULL;
+ goto bad;
+ }
+ *(char *)(mtag + 1) = 1;
+ m_tag_prepend(*m, mtag);
+ } else {
+ if (*(char *)(mtag + 1) > 3) {
+ m0 = *m;
+ *m = NULL;
+ goto bad;
+ }
+ (*(char *)(mtag + 1))++;
}
if (r->rt == PF_DUPTO) {
+#ifdef __FreeBSD__
+ if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL)
+#else
if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
+#endif
return;
} else {
if ((r->rt == PF_REPLYTO) == (r->direction == dir))
@@ -5592,10 +5800,22 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
goto bad;
if (oifp != ifp) {
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+ if (pf_test(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) {
+ PF_LOCK();
+ goto bad;
+ } else if (m0 == NULL) {
+ PF_LOCK();
+ goto done;
+ }
+ PF_LOCK();
+#else
if (pf_test(PF_OUT, ifp, &m0, NULL) != PF_PASS)
goto bad;
else if (m0 == NULL)
goto done;
+#endif
if (m0->m_len < sizeof(struct ip)) {
DPFPRINTF(PF_DEBUG_URGENT,
("pf_route: m0->m_len < sizeof(struct ip)\n"));
@@ -5604,6 +5824,47 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
ip = mtod(m0, struct ip *);
}
+#ifdef __FreeBSD__
+ /* Copied from FreeBSD 5.1-CURRENT ip_output. */
+ m0->m_pkthdr.csum_flags |= CSUM_IP;
+ sw_csum = m0->m_pkthdr.csum_flags & ~ifp->if_hwassist;
+ if (sw_csum & CSUM_DELAY_DATA) {
+ /*
+ * XXX: in_delayed_cksum assumes HBO for ip->ip_len (at least)
+ */
+ NTOHS(ip->ip_len);
+ NTOHS(ip->ip_off); /* XXX: needed? */
+ in_delayed_cksum(m0);
+ HTONS(ip->ip_len);
+ HTONS(ip->ip_off);
+ sw_csum &= ~CSUM_DELAY_DATA;
+ }
+ m0->m_pkthdr.csum_flags &= ifp->if_hwassist;
+
+ if (ntohs(ip->ip_len) <= ifp->if_mtu ||
+ (ifp->if_hwassist & CSUM_FRAGMENT &&
+ ((ip->ip_off & htons(IP_DF)) == 0))) {
+ /*
+ * ip->ip_len = htons(ip->ip_len);
+ * ip->ip_off = htons(ip->ip_off);
+ */
+ ip->ip_sum = 0;
+ if (sw_csum & CSUM_DELAY_IP) {
+ /* From KAME */
+ if (ip->ip_v == IPVERSION &&
+ (ip->ip_hl << 2) == sizeof(*ip)) {
+ ip->ip_sum = in_cksum_hdr(ip);
+ } else {
+ ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
+ }
+ }
+ PF_UNLOCK();
+ error = (*ifp->if_output)(ifp, m0, sintosa(dst), ro->ro_rt);
+ PF_LOCK();
+ goto done;
+ }
+
+#else
/* Copied from ip_output. */
#ifdef IPSEC
/*
@@ -5619,38 +5880,38 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
#endif /* IPSEC */
/* Catch routing changes wrt. hardware checksumming for TCP or UDP. */
- if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT) {
+ if (m0->m_pkthdr.csum & M_TCPV4_CSUM_OUT) {
if (!(ifp->if_capabilities & IFCAP_CSUM_TCPv4) ||
ifp->if_bridge != NULL) {
in_delayed_cksum(m0);
- m0->m_pkthdr.csum_flags &= ~M_TCPV4_CSUM_OUT; /* Clear */
+ m0->m_pkthdr.csum &= ~M_TCPV4_CSUM_OUT; /* Clear */
}
- } else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT) {
+ } else if (m0->m_pkthdr.csum & M_UDPV4_CSUM_OUT) {
if (!(ifp->if_capabilities & IFCAP_CSUM_UDPv4) ||
ifp->if_bridge != NULL) {
in_delayed_cksum(m0);
- m0->m_pkthdr.csum_flags &= ~M_UDPV4_CSUM_OUT; /* Clear */
+ m0->m_pkthdr.csum &= ~M_UDPV4_CSUM_OUT; /* Clear */
}
}
if (ntohs(ip->ip_len) <= ifp->if_mtu) {
if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
ifp->if_bridge == NULL) {
- m0->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
+ m0->m_pkthdr.csum |= M_IPV4_CSUM_OUT;
ipstat.ips_outhwcsum++;
} else {
ip->ip_sum = 0;
ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
}
/* Update relevant hardware checksum stats for TCP/UDP */
- if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT)
+ if (m0->m_pkthdr.csum & M_TCPV4_CSUM_OUT)
tcpstat.tcps_outhwcsum++;
- else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT)
+ else if (m0->m_pkthdr.csum & M_UDPV4_CSUM_OUT)
udpstat.udps_outhwcsum++;
error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL);
goto done;
}
-
+#endif
/*
* Too large for interface; fragment if possible.
* Must be able to put at least 8 bytes per fragment.
@@ -5658,27 +5919,57 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
if (ip->ip_off & htons(IP_DF)) {
ipstat.ips_cantfrag++;
if (r->rt != PF_DUPTO) {
+#ifdef __FreeBSD__
+ /* icmp_error() expects host byte ordering */
+ NTOHS(ip->ip_len);
+ NTOHS(ip->ip_off);
+ PF_UNLOCK();
icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
ifp->if_mtu);
+ PF_LOCK();
+#else
+ icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
+ ifp);
+#endif
goto done;
} else
goto bad;
}
m1 = m0;
+#ifdef __FreeBSD__
+ /*
+ * XXX: is cheaper + less error prone than own function
+ */
+ NTOHS(ip->ip_len);
+ NTOHS(ip->ip_off);
+ error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist, sw_csum);
+#else
error = ip_fragment(m0, ifp, ifp->if_mtu);
+#endif
if (error) {
+#ifndef __FreeBSD__ /* ip_fragment does not do m_freem() on FreeBSD */
m0 = NULL;
+#endif
goto bad;
}
for (m0 = m1; m0; m0 = m1) {
m1 = m0->m_nextpkt;
m0->m_nextpkt = 0;
+#ifdef __FreeBSD__
+ if (error == 0) {
+ PF_UNLOCK();
+ error = (*ifp->if_output)(ifp, m0, sintosa(dst),
+ NULL);
+ PF_LOCK();
+ } else
+#else
if (error == 0)
error = (*ifp->if_output)(ifp, m0, sintosa(dst),
NULL);
else
+#endif
m_freem(m0);
}
@@ -5701,9 +5992,10 @@ bad:
#ifdef INET6
void
pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
- struct pf_state *s, struct pf_pdesc *pd)
+ struct pf_state *s)
{
struct mbuf *m0;
+ struct m_tag *mtag;
struct route_in6 ip6route;
struct route_in6 *ro;
struct sockaddr_in6 *dst;
@@ -5717,14 +6009,30 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
(dir != PF_IN && dir != PF_OUT) || oifp == NULL)
panic("pf_route6: invalid parameters");
- if (pd->pf_mtag->routed++ > 3) {
- m0 = *m;
- *m = NULL;
- goto bad;
+ if ((mtag = m_tag_find(*m, PACKET_TAG_PF_ROUTED, NULL)) == NULL) {
+ if ((mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 1, M_NOWAIT)) ==
+ NULL) {
+ m0 = *m;
+ *m = NULL;
+ goto bad;
+ }
+ *(char *)(mtag + 1) = 1;
+ m_tag_prepend(*m, mtag);
+ } else {
+ if (*(char *)(mtag + 1) > 3) {
+ m0 = *m;
+ *m = NULL;
+ goto bad;
+ }
+ (*(char *)(mtag + 1))++;
}
if (r->rt == PF_DUPTO) {
+#ifdef __FreeBSD__
+ if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL)
+#else
if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
+#endif
return;
} else {
if ((r->rt == PF_REPLYTO) == (r->direction == dir))
@@ -5746,10 +6054,20 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
dst->sin6_len = sizeof(*dst);
dst->sin6_addr = ip6->ip6_dst;
- /* Cheat. XXX why only in the v6 case??? */
+ /* Cheat. */
if (r->rt == PF_FASTROUTE) {
- pd->pf_mtag->flags |= PF_TAG_GENERATED;
+#ifdef __FreeBSD__
+ m0->m_flags |= M_SKIP_FIREWALL;
+ PF_UNLOCK();
+ ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
+ PF_LOCK();
+#else
+ mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
+ if (mtag == NULL)
+ goto bad;
+ m_tag_prepend(m0, mtag);
ip6_output(m0, NULL, NULL, 0, NULL, NULL);
+#endif
return;
}
@@ -5775,10 +6093,22 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
goto bad;
if (oifp != ifp) {
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+ if (pf_test6(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) {
+ PF_LOCK();
+ goto bad;
+ } else if (m0 == NULL) {
+ PF_LOCK();
+ goto done;
+ }
+ PF_LOCK();
+#else
if (pf_test6(PF_OUT, ifp, &m0, NULL) != PF_PASS)
goto bad;
else if (m0 == NULL)
goto done;
+#endif
if (m0->m_len < sizeof(struct ip6_hdr)) {
DPFPRINTF(PF_DEBUG_URGENT,
("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
@@ -5791,15 +6121,29 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
* If the packet is too large for the outgoing interface,
* send back an icmp6 error.
*/
- if (IN6_IS_SCOPE_EMBED(&dst->sin6_addr))
+ if (IN6_IS_ADDR_LINKLOCAL(&dst->sin6_addr))
dst->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) {
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
error = nd6_output(ifp, ifp, m0, dst, NULL);
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
} else {
in6_ifstat_inc(ifp, ifs6_in_toobig);
+#ifdef __FreeBSD__
+ if (r->rt != PF_DUPTO) {
+ PF_UNLOCK();
+ icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
+ PF_LOCK();
+ } else
+#else
if (r->rt != PF_DUPTO)
icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
else
+#endif
goto bad;
}
@@ -5815,6 +6159,131 @@ bad:
#endif /* INET6 */
+#ifdef __FreeBSD__
+/*
+ * FreeBSD supports cksum offloads for the following drivers.
+ * em(4), fxp(4), ixgb(4), lge(4), ndis(4), nge(4), re(4),
+ * ti(4), txp(4), xl(4)
+ *
+ * CSUM_DATA_VALID | CSUM_PSEUDO_HDR :
+ * network driver performed cksum including pseudo header, need to verify
+ * csum_data
+ * CSUM_DATA_VALID :
+ * network driver performed cksum, needs to additional pseudo header
+ * cksum computation with partial csum_data(i.e. lack of H/W support for
+ * pseudo header, for instance hme(4), sk(4) and possibly gem(4))
+ *
+ * After validating the cksum of packet, set both flag CSUM_DATA_VALID and
+ * CSUM_PSEUDO_HDR in order to avoid recomputation of the cksum in upper
+ * TCP/UDP layer.
+ * Also, set csum_data to 0xffff to force cksum validation.
+ */
+int
+pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t af)
+{
+ u_int16_t sum = 0;
+ int hw_assist = 0;
+ struct ip *ip;
+
+ if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
+ return (1);
+ if (m->m_pkthdr.len < off + len)
+ return (1);
+
+ switch (p) {
+ case IPPROTO_TCP:
+ if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
+ if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
+ sum = m->m_pkthdr.csum_data;
+ } else {
+ ip = mtod(m, struct ip *);
+ sum = in_pseudo(ip->ip_src.s_addr,
+ ip->ip_dst.s_addr, htonl((u_short)len +
+ m->m_pkthdr.csum_data + IPPROTO_TCP));
+ }
+ sum ^= 0xffff;
+ ++hw_assist;
+ }
+ break;
+ case IPPROTO_UDP:
+ if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
+ if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
+ sum = m->m_pkthdr.csum_data;
+ } else {
+ ip = mtod(m, struct ip *);
+ sum = in_pseudo(ip->ip_src.s_addr,
+ ip->ip_dst.s_addr, htonl((u_short)len +
+ m->m_pkthdr.csum_data + IPPROTO_UDP));
+ }
+ sum ^= 0xffff;
+ ++hw_assist;
+ }
+ break;
+ case IPPROTO_ICMP:
+#ifdef INET6
+ case IPPROTO_ICMPV6:
+#endif /* INET6 */
+ break;
+ default:
+ return (1);
+ }
+
+ if (!hw_assist) {
+ switch (af) {
+ case AF_INET:
+ if (p == IPPROTO_ICMP) {
+ if (m->m_len < off)
+ return (1);
+ m->m_data += off;
+ m->m_len -= off;
+ sum = in_cksum(m, len);
+ m->m_data -= off;
+ m->m_len += off;
+ } else {
+ if (m->m_len < sizeof(struct ip))
+ return (1);
+ sum = in4_cksum(m, p, off, len);
+ }
+ break;
+#ifdef INET6
+ case AF_INET6:
+ if (m->m_len < sizeof(struct ip6_hdr))
+ return (1);
+ sum = in6_cksum(m, p, off, len);
+ break;
+#endif /* INET6 */
+ default:
+ return (1);
+ }
+ }
+ if (sum) {
+ switch (p) {
+ case IPPROTO_TCP:
+ tcpstat.tcps_rcvbadsum++;
+ break;
+ case IPPROTO_UDP:
+ udpstat.udps_badsum++;
+ break;
+ case IPPROTO_ICMP:
+ icmpstat.icps_checksum++;
+ break;
+#ifdef INET6
+ case IPPROTO_ICMPV6:
+ icmp6stat.icp6s_checksum++;
+ break;
+#endif /* INET6 */
+ }
+ return (1);
+ } else {
+ if (p == IPPROTO_TCP || p == IPPROTO_UDP) {
+ m->m_pkthdr.csum_flags |=
+ (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
+ m->m_pkthdr.csum_data = 0xffff;
+ }
+ }
+ return (0);
+}
+#else
/*
* check protocol (tcp/udp/icmp/icmp6) checksum and set mbuf flag
* off is the offset where the protocol header starts
@@ -5846,9 +6315,9 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p,
default:
return (1);
}
- if (m->m_pkthdr.csum_flags & flag_ok)
+ if (m->m_pkthdr.csum & flag_ok)
return (0);
- if (m->m_pkthdr.csum_flags & flag_bad)
+ if (m->m_pkthdr.csum & flag_bad)
return (1);
if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
return (1);
@@ -5883,7 +6352,7 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p,
return (1);
}
if (sum) {
- m->m_pkthdr.csum_flags |= flag_bad;
+ m->m_pkthdr.csum |= flag_bad;
switch (p) {
case IPPROTO_TCP:
tcpstat.tcps_rcvbadsum++;
@@ -5902,54 +6371,91 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p,
}
return (1);
}
- m->m_pkthdr.csum_flags |= flag_ok;
+ m->m_pkthdr.csum |= flag_ok;
+ return (0);
+}
+#endif
+
+static int
+pf_add_mbuf_tag(struct mbuf *m, u_int tag)
+{
+ struct m_tag *mtag;
+
+ if (m_tag_find(m, tag, NULL) != NULL)
+ return (0);
+ mtag = m_tag_get(tag, 0, M_NOWAIT);
+ if (mtag == NULL)
+ return (1);
+ m_tag_prepend(m, mtag);
return (0);
}
#ifdef INET
int
+#ifdef __FreeBSD__
+pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
+ struct ether_header *eh, struct inpcb *inp)
+#else
pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
struct ether_header *eh)
+#endif
{
struct pfi_kif *kif;
u_short action, reason = 0, log = 0;
struct mbuf *m = *m0;
- struct ip *h;
+ struct ip *h = NULL; /* make the compiler happy */
struct pf_rule *a = NULL, *r = &pf_default_rule, *tr, *nr;
struct pf_state *s = NULL;
struct pf_ruleset *ruleset = NULL;
struct pf_pdesc pd;
int off, dirndx, pqid = 0;
- if (!pf_status.running)
- return (PF_PASS);
-
- memset(&pd, 0, sizeof(pd));
- if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) {
- DPFPRINTF(PF_DEBUG_URGENT,
- ("pf_test: pf_get_mtag returned NULL\n"));
- return (PF_DROP);
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
+ if (!pf_status.running ||
+#ifdef __FreeBSD__
+ (m->m_flags & M_SKIP_FIREWALL)) {
+ PF_UNLOCK();
+#else
+ (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) {
+#endif
+ return (PF_PASS);
}
- if (pd.pf_mtag->flags & PF_TAG_GENERATED)
- return (PF_PASS);
+#ifdef __FreeBSD__
+ /* XXX_IMPORT: later */
+#else
if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
ifp = ifp->if_carpdev;
+#endif
- kif = (struct pfi_kif *)ifp->if_pf_kif;
+ kif = pfi_index2kif[ifp->if_index];
if (kif == NULL) {
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
DPFPRINTF(PF_DEBUG_URGENT,
("pf_test: kif == NULL, if_xname %s\n", ifp->if_xname));
return (PF_DROP);
}
- if (kif->pfik_flags & PFI_IFLAG_SKIP)
+ if (kif->pfik_flags & PFI_IFLAG_SKIP) {
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
return (PF_PASS);
+ }
+#ifdef __FreeBSD__
+ M_ASSERTPKTHDR(m);
+#else
#ifdef DIAGNOSTIC
if ((m->m_flags & M_PKTHDR) == 0)
panic("non-M_PKTHDR is passed to pf_test");
#endif /* DIAGNOSTIC */
+#endif /* __FreeBSD__ */
+ memset(&pd, 0, sizeof(pd));
if (m->m_pkthdr.len < (int)sizeof(*h)) {
action = PF_DROP;
REASON_SET(&reason, PFRES_SHORT);
@@ -6003,7 +6509,6 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
}
if (dir == PF_IN && pf_check_proto_cksum(m, off,
ntohs(h->ip_len) - off, IPPROTO_TCP, AF_INET)) {
- REASON_SET(&reason, PFRES_PROTCKSUM);
action = PF_DROP;
goto done;
}
@@ -6023,8 +6528,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
+#ifdef __FreeBSD__
+ action = pf_test_tcp(&r, &s, dir, kif,
+ m, off, h, &pd, &a, &ruleset, NULL, inp);
+#else
action = pf_test_tcp(&r, &s, dir, kif,
m, off, h, &pd, &a, &ruleset, &ipintrq);
+#endif
break;
}
@@ -6040,14 +6550,12 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
off, ntohs(h->ip_len) - off, IPPROTO_UDP, AF_INET)) {
action = PF_DROP;
- REASON_SET(&reason, PFRES_PROTCKSUM);
goto done;
}
if (uh.uh_dport == 0 ||
ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
action = PF_DROP;
- REASON_SET(&reason, PFRES_SHORT);
goto done;
}
action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
@@ -6059,8 +6567,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
+#ifdef __FreeBSD__
+ action = pf_test_udp(&r, &s, dir, kif,
+ m, off, h, &pd, &a, &ruleset, NULL, inp);
+#else
action = pf_test_udp(&r, &s, dir, kif,
m, off, h, &pd, &a, &ruleset, &ipintrq);
+#endif
break;
}
@@ -6076,7 +6589,6 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
if (dir == PF_IN && pf_check_proto_cksum(m, off,
ntohs(h->ip_len) - off, IPPROTO_ICMP, AF_INET)) {
action = PF_DROP;
- REASON_SET(&reason, PFRES_PROTCKSUM);
goto done;
}
action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd,
@@ -6089,8 +6601,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
+#ifdef __FreeBSD__
+ action = pf_test_icmp(&r, &s, dir, kif,
+ m, off, h, &pd, &a, &ruleset, NULL);
+#else
action = pf_test_icmp(&r, &s, dir, kif,
m, off, h, &pd, &a, &ruleset, &ipintrq);
+#endif
break;
}
@@ -6104,8 +6621,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
+#ifdef __FreeBSD__
+ action = pf_test_other(&r, &s, dir, kif, m, off, h,
+ &pd, &a, &ruleset, NULL);
+#else
action = pf_test_other(&r, &s, dir, kif, m, off, h,
&pd, &a, &ruleset, &ipintrq);
+#endif
break;
}
@@ -6119,18 +6641,26 @@ done:
("pf: dropping packet with ip options\n"));
}
- if ((s && s->tag) || r->rtableid)
- pf_tag_packet(m, pd.pf_mtag, s ? s->tag : 0, r->rtableid);
+ if (s && s->tag)
+ pf_tag_packet(m, pf_get_tag(m), s->tag);
#ifdef ALTQ
if (action == PF_PASS && r->qid) {
- if (pqid || (pd.tos & IPTOS_LOWDELAY))
- pd.pf_mtag->qid = r->pqid;
- else
- pd.pf_mtag->qid = r->qid;
- /* add hints for ecn */
- pd.pf_mtag->af = AF_INET;
- pd.pf_mtag->hdr = h;
+ struct m_tag *mtag;
+ struct altq_tag *atag;
+
+ mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
+ if (mtag != NULL) {
+ atag = (struct altq_tag *)(mtag + 1);
+ if (pqid || pd.tos == IPTOS_LOWDELAY)
+ atag->qid = r->pqid;
+ else
+ atag->qid = r->qid;
+ /* add hints for ecn */
+ atag->af = AF_INET;
+ atag->hdr = h;
+ m_tag_prepend(m, mtag);
+ }
}
#endif /* ALTQ */
@@ -6143,48 +6673,41 @@ done:
pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
(s->nat_rule.ptr->action == PF_RDR ||
s->nat_rule.ptr->action == PF_BINAT) &&
- (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
- pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST;
-
- if (log) {
- struct pf_rule *lr;
-
- if (s != NULL && s->nat_rule.ptr != NULL &&
- s->nat_rule.ptr->log & PF_LOG_ALL)
- lr = s->nat_rule.ptr;
- else
- lr = r;
- PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, lr, a, ruleset,
- &pd);
+ (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET &&
+ pf_add_mbuf_tag(m, PACKET_TAG_PF_TRANSLATE_LOCALHOST)) {
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_MEMORY);
}
+ if (log)
+ PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, r, a, ruleset);
+
kif->pfik_bytes[0][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
kif->pfik_packets[0][dir == PF_OUT][action != PF_PASS]++;
if (action == PF_PASS || r->action == PF_DROP) {
- dirndx = (dir == PF_OUT);
- r->packets[dirndx]++;
- r->bytes[dirndx] += pd.tot_len;
+ r->packets++;
+ r->bytes += pd.tot_len;
if (a != NULL) {
- a->packets[dirndx]++;
- a->bytes[dirndx] += pd.tot_len;
+ a->packets++;
+ a->bytes += pd.tot_len;
}
if (s != NULL) {
+ dirndx = (dir == s->direction) ? 0 : 1;
+ s->packets[dirndx]++;
+ s->bytes[dirndx] += pd.tot_len;
if (s->nat_rule.ptr != NULL) {
- s->nat_rule.ptr->packets[dirndx]++;
- s->nat_rule.ptr->bytes[dirndx] += pd.tot_len;
+ s->nat_rule.ptr->packets++;
+ s->nat_rule.ptr->bytes += pd.tot_len;
}
if (s->src_node != NULL) {
- s->src_node->packets[dirndx]++;
- s->src_node->bytes[dirndx] += pd.tot_len;
+ s->src_node->packets++;
+ s->src_node->bytes += pd.tot_len;
}
if (s->nat_src_node != NULL) {
- s->nat_src_node->packets[dirndx]++;
- s->nat_src_node->bytes[dirndx] += pd.tot_len;
+ s->nat_src_node->packets++;
+ s->nat_src_node->bytes += pd.tot_len;
}
- dirndx = (dir == s->direction) ? 0 : 1;
- s->packets[dirndx]++;
- s->bytes[dirndx] += pd.tot_len;
}
tr = r;
nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
@@ -6229,7 +6752,11 @@ done:
action = PF_PASS;
} else if (r->rt)
/* pf_route can free the mbuf causing *m0 to become NULL */
- pf_route(m0, r, dir, ifp, s, &pd);
+ pf_route(m0, r, dir, ifp, s);
+
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
return (action);
}
@@ -6237,48 +6764,71 @@ done:
#ifdef INET6
int
+#ifdef __FreeBSD__
+pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
+ struct ether_header *eh, struct inpcb *inp)
+#else
pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
struct ether_header *eh)
+#endif
{
struct pfi_kif *kif;
u_short action, reason = 0, log = 0;
- struct mbuf *m = *m0, *n = NULL;
- struct ip6_hdr *h;
+ struct mbuf *m = *m0;
+ struct ip6_hdr *h = NULL; /* make the compiler happy */
struct pf_rule *a = NULL, *r = &pf_default_rule, *tr, *nr;
struct pf_state *s = NULL;
struct pf_ruleset *ruleset = NULL;
struct pf_pdesc pd;
- int off, terminal = 0, dirndx;
+ int off, terminal = 0, dirndx, rh_cnt = 0;
- if (!pf_status.running)
- return (PF_PASS);
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
- memset(&pd, 0, sizeof(pd));
- if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) {
- DPFPRINTF(PF_DEBUG_URGENT,
- ("pf_test6: pf_get_mtag returned NULL\n"));
- return (PF_DROP);
- }
- if (pd.pf_mtag->flags & PF_TAG_GENERATED)
+ if (!pf_status.running ||
+#ifdef __FreeBSD__
+ (m->m_flags & M_SKIP_FIREWALL)) {
+ PF_UNLOCK();
+#else
+ (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) {
+#endif
return (PF_PASS);
+ }
+#ifdef __FreeBSD__
+ /* XXX_IMPORT: later */
+#else
if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
ifp = ifp->if_carpdev;
+#endif
- kif = (struct pfi_kif *)ifp->if_pf_kif;
+ kif = pfi_index2kif[ifp->if_index];
if (kif == NULL) {
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
DPFPRINTF(PF_DEBUG_URGENT,
("pf_test6: kif == NULL, if_xname %s\n", ifp->if_xname));
return (PF_DROP);
}
- if (kif->pfik_flags & PFI_IFLAG_SKIP)
+ if (kif->pfik_flags & PFI_IFLAG_SKIP) {
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
return (PF_PASS);
+ }
+#ifdef __FreeBSD__
+ M_ASSERTPKTHDR(m);
+#else
#ifdef DIAGNOSTIC
if ((m->m_flags & M_PKTHDR) == 0)
panic("non-M_PKTHDR is passed to pf_test6");
#endif /* DIAGNOSTIC */
+#endif
+ memset(&pd, 0, sizeof(pd));
if (m->m_pkthdr.len < (int)sizeof(*h)) {
action = PF_DROP;
REASON_SET(&reason, PFRES_SHORT);
@@ -6327,62 +6877,33 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
goto done;
case IPPROTO_ROUTING: {
struct ip6_rthdr rthdr;
- struct ip6_rthdr0 rthdr0;
- struct in6_addr finaldst;
- struct ip6_hdr *ip6;
+ if (rh_cnt++) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: IPv6 more than one rthdr\n"));
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_IPOPTIONS);
+ log = 1;
+ goto done;
+ }
if (!pf_pull_hdr(m, off, &rthdr, sizeof(rthdr), NULL,
&reason, pd.af)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: IPv6 short rthdr\n"));
action = PF_DROP;
+ REASON_SET(&reason, PFRES_SHORT);
log = 1;
goto done;
}
if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) {
- if (!pf_pull_hdr(m, off, &rthdr0,
- sizeof(rthdr0), NULL, &reason, pd.af)) {
- DPFPRINTF(PF_DEBUG_MISC,
- ("pf: IPv6 short rthdr0\n"));
- action = PF_DROP;
- log = 1;
- goto done;
- }
- if (rthdr0.ip6r0_segleft != 0) {
- if (!pf_pull_hdr(m, off +
- sizeof(rthdr0) +
- rthdr0.ip6r0_len * 8 -
- sizeof(finaldst), &finaldst,
- sizeof(finaldst), NULL,
- &reason, pd.af)) {
- DPFPRINTF(PF_DEBUG_MISC,
- ("pf: IPv6 short rthdr0\n"));
- action = PF_DROP;
- log = 1;
- goto done;
- }
-
- n = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
- if (!n) {
- DPFPRINTF(PF_DEBUG_MISC,
- ("pf: mbuf shortage\n"));
- action = PF_DROP;
- log = 1;
- goto done;
- }
- n = m_pullup(n, sizeof(struct ip6_hdr));
- if (!n) {
- DPFPRINTF(PF_DEBUG_MISC,
- ("pf: mbuf shortage\n"));
- action = PF_DROP;
- log = 1;
- goto done;
- }
- ip6 = mtod(n, struct ip6_hdr *);
- ip6->ip6_dst = finaldst;
- }
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: IPv6 rthdr0\n"));
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_IPOPTIONS);
+ log = 1;
+ goto done;
}
- /* FALLTHROUGH */
+ /* fallthrough */
}
case IPPROTO_AH:
case IPPROTO_HOPOPTS:
@@ -6412,10 +6933,6 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
}
} while (!terminal);
- /* if there's no routing header, use unmodified mbuf for checksumming */
- if (!n)
- n = m;
-
switch (pd.proto) {
case IPPROTO_TCP: {
@@ -6427,7 +6944,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
log = action != PF_PASS;
goto done;
}
- if (dir == PF_IN && pf_check_proto_cksum(n, off,
+ if (dir == PF_IN && pf_check_proto_cksum(m, off,
ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
IPPROTO_TCP, AF_INET6)) {
action = PF_DROP;
@@ -6448,8 +6965,13 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
+#ifdef __FreeBSD__
+ action = pf_test_tcp(&r, &s, dir, kif,
+ m, off, h, &pd, &a, &ruleset, NULL, inp);
+#else
action = pf_test_tcp(&r, &s, dir, kif,
m, off, h, &pd, &a, &ruleset, &ip6intrq);
+#endif
break;
}
@@ -6462,7 +6984,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
log = action != PF_PASS;
goto done;
}
- if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(n,
+ if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
off, ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
IPPROTO_UDP, AF_INET6)) {
action = PF_DROP;
@@ -6473,7 +6995,6 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
action = PF_DROP;
- REASON_SET(&reason, PFRES_SHORT);
goto done;
}
action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
@@ -6485,8 +7006,13 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
+#ifdef __FreeBSD__
+ action = pf_test_udp(&r, &s, dir, kif,
+ m, off, h, &pd, &a, &ruleset, NULL, inp);
+#else
action = pf_test_udp(&r, &s, dir, kif,
m, off, h, &pd, &a, &ruleset, &ip6intrq);
+#endif
break;
}
@@ -6499,7 +7025,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
log = action != PF_PASS;
goto done;
}
- if (dir == PF_IN && pf_check_proto_cksum(n, off,
+ if (dir == PF_IN && pf_check_proto_cksum(m, off,
ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
IPPROTO_ICMPV6, AF_INET6)) {
action = PF_DROP;
@@ -6516,8 +7042,13 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
+#ifdef __FreeBSD__
+ action = pf_test_icmp(&r, &s, dir, kif,
+ m, off, h, &pd, &a, &ruleset, NULL);
+#else
action = pf_test_icmp(&r, &s, dir, kif,
m, off, h, &pd, &a, &ruleset, &ip6intrq);
+#endif
break;
}
@@ -6531,31 +7062,47 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
+#ifdef __FreeBSD__
+ action = pf_test_other(&r, &s, dir, kif, m, off, h,
+ &pd, &a, &ruleset, NULL);
+#else
action = pf_test_other(&r, &s, dir, kif, m, off, h,
&pd, &a, &ruleset, &ip6intrq);
+#endif
break;
}
done:
- if (n != m) {
- m_freem(n);
- n = NULL;
+ /* handle dangerous IPv6 extension headers. */
+ if (action == PF_PASS && rh_cnt &&
+ !((s && s->allow_opts) || r->allow_opts)) {
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_IPOPTIONS);
+ log = 1;
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: dropping packet with dangerous v6 headers\n"));
}
- /* XXX handle IPv6 options, if not allowed. not implemented. */
-
- if ((s && s->tag) || r->rtableid)
- pf_tag_packet(m, pd.pf_mtag, s ? s->tag : 0, r->rtableid);
+ if (s && s->tag)
+ pf_tag_packet(m, pf_get_tag(m), s->tag);
#ifdef ALTQ
if (action == PF_PASS && r->qid) {
- if (pd.tos & IPTOS_LOWDELAY)
- pd.pf_mtag->qid = r->pqid;
- else
- pd.pf_mtag->qid = r->qid;
- /* add hints for ecn */
- pd.pf_mtag->af = AF_INET6;
- pd.pf_mtag->hdr = h;
+ struct m_tag *mtag;
+ struct altq_tag *atag;
+
+ mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
+ if (mtag != NULL) {
+ atag = (struct altq_tag *)(mtag + 1);
+ if (pd.tos == IPTOS_LOWDELAY)
+ atag->qid = r->pqid;
+ else
+ atag->qid = r->qid;
+ /* add hints for ecn */
+ atag->af = AF_INET6;
+ atag->hdr = h;
+ m_tag_prepend(m, mtag);
+ }
}
#endif /* ALTQ */
@@ -6563,48 +7110,41 @@ done:
pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
(s->nat_rule.ptr->action == PF_RDR ||
s->nat_rule.ptr->action == PF_BINAT) &&
- IN6_IS_ADDR_LOOPBACK(&pd.dst->v6))
- pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST;
-
- if (log) {
- struct pf_rule *lr;
-
- if (s != NULL && s->nat_rule.ptr != NULL &&
- s->nat_rule.ptr->log & PF_LOG_ALL)
- lr = s->nat_rule.ptr;
- else
- lr = r;
- PFLOG_PACKET(kif, h, m, AF_INET6, dir, reason, lr, a, ruleset,
- &pd);
+ IN6_IS_ADDR_LOOPBACK(&pd.dst->v6) &&
+ pf_add_mbuf_tag(m, PACKET_TAG_PF_TRANSLATE_LOCALHOST)) {
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_MEMORY);
}
+ if (log)
+ PFLOG_PACKET(kif, h, m, AF_INET6, dir, reason, r, a, ruleset);
+
kif->pfik_bytes[1][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
kif->pfik_packets[1][dir == PF_OUT][action != PF_PASS]++;
if (action == PF_PASS || r->action == PF_DROP) {
- dirndx = (dir == PF_OUT);
- r->packets[dirndx]++;
- r->bytes[dirndx] += pd.tot_len;
+ r->packets++;
+ r->bytes += pd.tot_len;
if (a != NULL) {
- a->packets[dirndx]++;
- a->bytes[dirndx] += pd.tot_len;
+ a->packets++;
+ a->bytes += pd.tot_len;
}
if (s != NULL) {
+ dirndx = (dir == s->direction) ? 0 : 1;
+ s->packets[dirndx]++;
+ s->bytes[dirndx] += pd.tot_len;
if (s->nat_rule.ptr != NULL) {
- s->nat_rule.ptr->packets[dirndx]++;
- s->nat_rule.ptr->bytes[dirndx] += pd.tot_len;
+ s->nat_rule.ptr->packets++;
+ s->nat_rule.ptr->bytes += pd.tot_len;
}
if (s->src_node != NULL) {
- s->src_node->packets[dirndx]++;
- s->src_node->bytes[dirndx] += pd.tot_len;
+ s->src_node->packets++;
+ s->src_node->bytes += pd.tot_len;
}
if (s->nat_src_node != NULL) {
- s->nat_src_node->packets[dirndx]++;
- s->nat_src_node->bytes[dirndx] += pd.tot_len;
+ s->nat_src_node->packets++;
+ s->nat_src_node->bytes += pd.tot_len;
}
- dirndx = (dir == s->direction) ? 0 : 1;
- s->packets[dirndx]++;
- s->bytes[dirndx] += pd.tot_len;
}
tr = r;
nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
@@ -6649,8 +7189,11 @@ done:
action = PF_PASS;
} else if (r->rt)
/* pf_route6 can free the mbuf causing *m0 to become NULL */
- pf_route6(m0, r, dir, ifp, s, &pd);
+ pf_route6(m0, r, dir, ifp, s);
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
return (action);
}
#endif /* INET6 */
@@ -6658,8 +7201,13 @@ done:
int
pf_check_congestion(struct ifqueue *ifq)
{
+#ifdef __FreeBSD__
+ /* XXX_IMPORT: later */
+ return (0);
+#else
if (ifq->ifq_congestion)
return (1);
else
return (0);
+#endif
}
diff --git a/sys/contrib/pf/net/pf_if.c b/sys/contrib/pf/net/pf_if.c
index 6a15a89..8e35070 100644
--- a/sys/contrib/pf/net/pf_if.c
+++ b/sys/contrib/pf/net/pf_if.c
@@ -1,8 +1,7 @@
-/* $OpenBSD: pf_if.c,v 1.46 2006/12/13 09:01:59 itojun Exp $ */
+/* $FreeBSD$ */
+/* $OpenBSD: pf_if.c,v 1.23 2004/12/22 17:17:55 dhartmei Exp $ */
/*
- * Copyright 2005 Henning Brauer <henning@openbsd.org>
- * Copyright 2005 Ryan McBride <mcbride@openbsd.org>
* Copyright (c) 2001 Daniel Hartmeier
* Copyright (c) 2003 Cedric Berger
* All rights reserved.
@@ -32,14 +31,24 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#if defined(__FreeBSD__)
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#endif
+
#include <sys/param.h>
#include <sys/systm.h>
+#ifdef __FreeBSD__
+#include <sys/malloc.h>
+#endif
#include <sys/mbuf.h>
#include <sys/filio.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/kernel.h>
+#ifndef __FreeBSD__
#include <sys/device.h>
+#endif
#include <sys/time.h>
#include <net/if.h>
@@ -57,273 +66,440 @@
#include <netinet/ip6.h>
#endif /* INET6 */
-struct pfi_kif *pfi_all = NULL;
+#define ACCEPT_FLAGS(oklist) \
+ do { \
+ if ((flags & ~(oklist)) & \
+ PFI_FLAG_ALLMASK) \
+ return (EINVAL); \
+ } while (0)
+
+#define senderr(e) do { rv = (e); goto _bad; } while (0)
+
+struct pfi_kif **pfi_index2kif;
+struct pfi_kif *pfi_self, *pfi_dummy;
+int pfi_indexlim;
+struct pfi_ifhead pfi_ifs;
struct pfi_statehead pfi_statehead;
+int pfi_ifcnt;
+#ifdef __FreeBSD__
+uma_zone_t pfi_addr_pl;
+#else
struct pool pfi_addr_pl;
-struct pfi_ifhead pfi_ifs;
+#endif
long pfi_update = 1;
struct pfr_addr *pfi_buffer;
int pfi_buffer_cnt;
int pfi_buffer_max;
+#ifdef __FreeBSD__
+eventhandler_tag pfi_clone_cookie = NULL;
+eventhandler_tag pfi_attach_cookie = NULL;
+eventhandler_tag pfi_detach_cookie = NULL;
+#endif
-void pfi_kif_update(struct pfi_kif *);
-void pfi_dynaddr_update(struct pfi_dynaddr *dyn);
+void pfi_dynaddr_update(void *);
+void pfi_kifaddr_update(void *);
void pfi_table_update(struct pfr_ktable *, struct pfi_kif *,
int, int);
-void pfi_kifaddr_update(void *);
void pfi_instance_add(struct ifnet *, int, int);
void pfi_address_add(struct sockaddr *, int, int);
int pfi_if_compare(struct pfi_kif *, struct pfi_kif *);
-int pfi_skip_if(const char *, struct pfi_kif *);
+struct pfi_kif *pfi_if_create(const char *, struct pfi_kif *, int);
+void pfi_copy_group(char *, const char *, int);
+void pfi_newgroup(const char *, int);
+int pfi_skip_if(const char *, struct pfi_kif *, int);
int pfi_unmask(void *);
+void pfi_dohooks(struct pfi_kif *);
+#ifdef __FreeBSD__
+void pfi_kifaddr_update_event(void *, struct ifnet *);
+void pfi_attach_clone_event(void * __unused, struct if_clone *);
+void pfi_attach_ifnet_event(void * __unused, struct ifnet *);
+void pfi_detach_ifnet_event(void * __unused, struct ifnet *);
+#endif
RB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
#define PFI_BUFFER_MAX 0x10000
+#ifdef __FreeBSD__
+MALLOC_DEFINE(PFI_MTYPE, "pf_if", "pf interface table");
+#else
#define PFI_MTYPE M_IFADDR
+#endif
void
pfi_initialize(void)
{
- if (pfi_all != NULL) /* already initialized */
+#ifdef __FreeBSD__
+ struct ifnet *ifp;
+#endif
+
+ if (pfi_self != NULL) /* already initialized */
return;
TAILQ_INIT(&pfi_statehead);
+#ifndef __FreeBSD__
pool_init(&pfi_addr_pl, sizeof(struct pfi_dynaddr), 0, 0, 0,
"pfiaddrpl", &pool_allocator_nointr);
+#endif
pfi_buffer_max = 64;
pfi_buffer = malloc(pfi_buffer_max * sizeof(*pfi_buffer),
PFI_MTYPE, M_WAITOK);
-
- if ((pfi_all = pfi_kif_get(IFG_ALL)) == NULL)
- panic("pfi_kif_get for pfi_all failed");
+ pfi_self = pfi_if_create("self", NULL, PFI_IFLAG_GROUP);
+#ifdef __FreeBSD__
+ /* XXX_IMPORT */
+ PF_LOCK();
+ IFNET_RLOCK();
+ TAILQ_FOREACH(ifp, &ifnet, if_link) {
+ IFNET_RUNLOCK();
+ pfi_attach_ifnet(ifp);
+ IFNET_RLOCK();
+ }
+ IFNET_RUNLOCK();
+ PF_UNLOCK();
+ pfi_dummy = pfi_if_create("notyet", pfi_self,
+ PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC);
+ pfi_attach_cookie = EVENTHANDLER_REGISTER(ifnet_arrival_event,
+ pfi_attach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
+ pfi_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event,
+ pfi_detach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
+ pfi_clone_cookie = EVENTHANDLER_REGISTER(if_clone_event,
+ pfi_attach_clone_event, NULL, EVENTHANDLER_PRI_ANY);
+#endif
}
-struct pfi_kif *
-pfi_kif_get(const char *kif_name)
+#ifdef __FreeBSD__
+void
+pfi_cleanup(void)
{
- struct pfi_kif *kif;
- struct pfi_kif_cmp s;
-
- bzero(&s, sizeof(s));
- strlcpy(s.pfik_name, kif_name, sizeof(s.pfik_name));
- if ((kif = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&s)) != NULL)
- return (kif);
-
- /* create new one */
- if ((kif = malloc(sizeof(*kif), PFI_MTYPE, M_DONTWAIT)) == NULL)
- return (NULL);
+ struct pfi_kif *p, key;
+ struct ifnet *ifp;
+
+ PF_ASSERT(MA_OWNED);
+
+ PF_UNLOCK();
+ EVENTHANDLER_DEREGISTER(ifnet_arrival_event, pfi_attach_cookie);
+ EVENTHANDLER_DEREGISTER(ifnet_departure_event, pfi_detach_cookie);
+ EVENTHANDLER_DEREGISTER(if_clone_event, pfi_clone_cookie);
+ PF_LOCK();
+
+ IFNET_RLOCK();
+ /* release PFI_IFLAG_INSTANCE */
+ TAILQ_FOREACH(ifp, &ifnet, if_link) {
+ strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
+ p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
+ if (p != NULL) {
+ IFNET_RUNLOCK();
+ pfi_detach_ifnet(ifp);
+ IFNET_RLOCK();
+ }
+ }
+ IFNET_RUNLOCK();
- bzero(kif, sizeof(*kif));
- strlcpy(kif->pfik_name, kif_name, sizeof(kif->pfik_name));
- kif->pfik_tzero = time_second;
- TAILQ_INIT(&kif->pfik_dynaddrs);
+ /* XXX clear all other interface group */
+ while ((p = RB_MIN(pfi_ifhead, &pfi_ifs))) {
+ RB_REMOVE(pfi_ifhead, &pfi_ifs, p);
- RB_INSERT(pfi_ifhead, &pfi_ifs, kif);
- return (kif);
+ free(p->pfik_ah_head, PFI_MTYPE);
+ free(p, PFI_MTYPE);
+ }
+ free(pfi_index2kif, PFI_MTYPE);
+ free(pfi_buffer, PFI_MTYPE);
+ pfi_index2kif = NULL;
+ pfi_buffer = NULL;
+ pfi_self = NULL;
}
+/*
+ * Wrapper functions for FreeBSD eventhandler
+ */
void
-pfi_kif_ref(struct pfi_kif *kif, enum pfi_kif_refs what)
+pfi_kifaddr_update_event(void *arg, struct ifnet *ifp)
{
- switch (what) {
- case PFI_KIF_REF_RULE:
- kif->pfik_rules++;
- break;
- case PFI_KIF_REF_STATE:
- if (!kif->pfik_states++)
- TAILQ_INSERT_TAIL(&pfi_statehead, kif, pfik_w_states);
- break;
- default:
- panic("pfi_kif_ref with unknown type");
- }
+ struct pfi_kif *p = arg;
+
+ PF_LOCK();
+ /*
+ * Check to see if it is 'our' interface as we do not have per
+ * interface hooks and thus get an update for every interface.
+ */
+ if (p && p->pfik_ifp == ifp)
+ pfi_kifaddr_update(p);
+ PF_UNLOCK();
}
void
-pfi_kif_unref(struct pfi_kif *kif, enum pfi_kif_refs what)
+pfi_attach_clone_event(void *arg __unused, struct if_clone *ifc)
{
- if (kif == NULL)
- return;
-
- switch (what) {
- case PFI_KIF_REF_NONE:
- break;
- case PFI_KIF_REF_RULE:
- if (kif->pfik_rules <= 0) {
- printf("pfi_kif_unref: rules refcount <= 0\n");
- return;
- }
- kif->pfik_rules--;
- break;
- case PFI_KIF_REF_STATE:
- if (kif->pfik_states <= 0) {
- printf("pfi_kif_unref: state refcount <= 0\n");
- return;
- }
- if (!--kif->pfik_states)
- TAILQ_REMOVE(&pfi_statehead, kif, pfik_w_states);
- break;
- default:
- panic("pfi_kif_unref with unknown type");
- }
-
- if (kif->pfik_ifp != NULL || kif->pfik_group != NULL || kif == pfi_all)
- return;
-
- if (kif->pfik_rules || kif->pfik_states)
- return;
-
- RB_REMOVE(pfi_ifhead, &pfi_ifs, kif);
- free(kif, PFI_MTYPE);
+ PF_LOCK();
+ pfi_attach_clone(ifc);
+ PF_UNLOCK();
}
-int
-pfi_kif_match(struct pfi_kif *rule_kif, struct pfi_kif *packet_kif)
+void
+pfi_attach_ifnet_event(void *arg __unused, struct ifnet *ifp)
{
- struct ifg_list *p;
-
- if (rule_kif == NULL || rule_kif == packet_kif)
- return (1);
+ PF_LOCK();
+ pfi_attach_ifnet(ifp);
+ PF_UNLOCK();
+}
- if (rule_kif->pfik_group != NULL)
- TAILQ_FOREACH(p, &packet_kif->pfik_ifp->if_groups, ifgl_next)
- if (p->ifgl_group == rule_kif->pfik_group)
- return (1);
+void
+pfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp)
+{
+ PF_LOCK();
+ pfi_detach_ifnet(ifp);
+ PF_UNLOCK();
+}
+#endif /* __FreeBSD__ */
- return (0);
+void
+pfi_attach_clone(struct if_clone *ifc)
+{
+ pfi_initialize();
+ pfi_newgroup(ifc->ifc_name, PFI_IFLAG_CLONABLE);
}
void
pfi_attach_ifnet(struct ifnet *ifp)
{
- struct pfi_kif *kif;
- int s;
+ struct pfi_kif *p, *q, key;
+ int s;
+#ifdef __FreeBSD__
+ int realname;
+#endif
pfi_initialize();
s = splsoftnet();
pfi_update++;
- if ((kif = pfi_kif_get(ifp->if_xname)) == NULL)
- panic("pfi_kif_get failed");
-
- kif->pfik_ifp = ifp;
- ifp->if_pf_kif = (caddr_t)kif;
-
- if ((kif->pfik_ah_cookie = hook_establish(ifp->if_addrhooks, 1,
- pfi_kifaddr_update, kif)) == NULL)
- panic("pfi_attach_ifnet: cannot allocate '%s' address hook",
- ifp->if_xname);
-
- pfi_kif_update(kif);
+ if (ifp->if_index >= pfi_indexlim) {
+ /*
+ * grow pfi_index2kif, similar to ifindex2ifnet code in if.c
+ */
+ size_t m, n, oldlim;
+ struct pfi_kif **mp, **np;
+
+ oldlim = pfi_indexlim;
+ if (pfi_indexlim == 0)
+ pfi_indexlim = 64;
+ while (ifp->if_index >= pfi_indexlim)
+ pfi_indexlim <<= 1;
+
+ m = oldlim * sizeof(struct pfi_kif *);
+ mp = pfi_index2kif;
+ n = pfi_indexlim * sizeof(struct pfi_kif *);
+#ifdef __FreeBSD__
+ np = malloc(n, PFI_MTYPE, M_NOWAIT);
+#else
+ np = malloc(n, PFI_MTYPE, M_DONTWAIT);
+#endif
+ if (np == NULL)
+ panic("pfi_attach_ifnet: "
+ "cannot allocate translation table");
+ bzero(np, n);
+ if (mp != NULL)
+ bcopy(mp, np, m);
+ pfi_index2kif = np;
+ if (mp != NULL)
+ free(mp, PFI_MTYPE);
+ }
+ strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
+ p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
+#ifdef __FreeBSD__
+ /* some additional trickery for placeholders */
+ if ((p == NULL) || (p->pfik_parent == pfi_dummy)) {
+ /* are we looking at a renamed instance or not? */
+ pfi_copy_group(key.pfik_name, ifp->if_xname,
+ sizeof(key.pfik_name));
+ realname = (strncmp(key.pfik_name, ifp->if_dname,
+ sizeof(key.pfik_name)) == 0);
+ /* add group */
+ /* we can change if_xname, hence use if_dname as group id */
+ pfi_copy_group(key.pfik_name, ifp->if_dname,
+ sizeof(key.pfik_name));
+ q = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
+ if (q == NULL)
+ q = pfi_if_create(key.pfik_name, pfi_self,
+ PFI_IFLAG_GROUP|PFI_IFLAG_DYNAMIC);
+ else if (q->pfik_parent == pfi_dummy) {
+ q->pfik_parent = pfi_self;
+ q->pfik_flags = (PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC);
+ }
+ if (q == NULL)
+ panic("pfi_attach_ifnet: "
+ "cannot allocate '%s' group", key.pfik_name);
+
+ /* add/modify interface */
+ if (p == NULL)
+ p = pfi_if_create(ifp->if_xname, q, PFI_IFLAG_INSTANCE |
+ (realname?0:PFI_IFLAG_PLACEHOLDER));
+ else {
+ /* remove from the dummy group */
+ /* XXX: copy stats? We should not have any!!! */
+ pfi_dummy->pfik_delcnt++;
+ TAILQ_REMOVE(&pfi_dummy->pfik_grouphead, p,
+ pfik_instances);
+ /* move to the right group */
+ p->pfik_parent = q;
+ q->pfik_addcnt++;
+ TAILQ_INSERT_TAIL(&q->pfik_grouphead, p,
+ pfik_instances);
+ if (realname)
+ p->pfik_flags &= ~PFI_IFLAG_PLACEHOLDER;
+ p->pfik_flags |= PFI_IFLAG_INSTANCE;
+ }
+ if (p == NULL)
+ panic("pfi_attach_ifnet: "
+ "cannot allocate '%s' interface", ifp->if_xname);
+#else
+ if (p == NULL) {
+ /* add group */
+ pfi_copy_group(key.pfik_name, ifp->if_xname,
+ sizeof(key.pfik_name));
+ q = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
+ if (q == NULL)
+ q = pfi_if_create(key.pfik_name, pfi_self, PFI_IFLAG_GROUP);
+ else if (q->pfik_parent == pfi_dummy) {
+ q->pfik_parent = pfi_self;
+ q->pfik_flags = (PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC);
+ }
+ if (q == NULL)
+ panic("pfi_attach_ifnet: "
+ "cannot allocate '%s' group", key.pfik_name);
+
+ /* add interface */
+ p = pfi_if_create(ifp->if_xname, q, PFI_IFLAG_INSTANCE);
+ if (p == NULL)
+ panic("pfi_attach_ifnet: "
+ "cannot allocate '%s' interface", ifp->if_xname);
+#endif
+ } else
+ q = p->pfik_parent;
+ p->pfik_ifp = ifp;
+ p->pfik_flags |= PFI_IFLAG_ATTACHED;
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+ p->pfik_ah_cookie = EVENTHANDLER_REGISTER(ifaddr_event,
+ pfi_kifaddr_update_event, p, EVENTHANDLER_PRI_ANY);
+ PF_LOCK();
+#else
+ p->pfik_ah_cookie =
+ hook_establish(ifp->if_addrhooks, 1, pfi_kifaddr_update, p);
+#endif
+ pfi_index2kif[ifp->if_index] = p;
+ pfi_dohooks(p);
splx(s);
}
void
pfi_detach_ifnet(struct ifnet *ifp)
{
- int s;
- struct pfi_kif *kif;
+ struct pfi_kif *p, *q, key;
+ int s;
- if ((kif = (struct pfi_kif *)ifp->if_pf_kif) == NULL)
- return;
+ strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
s = splsoftnet();
pfi_update++;
- hook_disestablish(ifp->if_addrhooks, kif->pfik_ah_cookie);
- pfi_kif_update(kif);
-
- kif->pfik_ifp = NULL;
- ifp->if_pf_kif = NULL;
- pfi_kif_unref(kif, PFI_KIF_REF_NONE);
+ p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
+ if (p == NULL) {
+ printf("pfi_detach_ifnet: cannot find %s", ifp->if_xname);
+ splx(s);
+ return;
+ }
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+ EVENTHANDLER_DEREGISTER(ifaddr_event, p->pfik_ah_cookie);
+ PF_LOCK();
+#else
+ hook_disestablish(p->pfik_ifp->if_addrhooks, p->pfik_ah_cookie);
+#endif
+ q = p->pfik_parent;
+ p->pfik_ifp = NULL;
+ p->pfik_flags &= ~PFI_IFLAG_ATTACHED;
+ pfi_index2kif[ifp->if_index] = NULL;
+ pfi_dohooks(p);
+ pfi_maybe_destroy(p);
splx(s);
}
-void
-pfi_attach_ifgroup(struct ifg_group *ifg)
+struct pfi_kif *
+pfi_lookup_create(const char *name)
{
- struct pfi_kif *kif;
+ struct pfi_kif *p, *q, key;
int s;
- pfi_initialize();
s = splsoftnet();
- pfi_update++;
- if ((kif = pfi_kif_get(ifg->ifg_group)) == NULL)
- panic("pfi_kif_get failed");
+ p = pfi_lookup_if(name);
+ if (p == NULL) {
+ pfi_copy_group(key.pfik_name, name, sizeof(key.pfik_name));
+ q = pfi_lookup_if(key.pfik_name);
+#ifdef __FreeBSD__
+ /* XXX_IMPORT */
+ if ((q != NULL) && (q->pfik_parent != pfi_dummy))
+ p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE);
+ else {
+ if (pfi_dummy == NULL)
+ panic("no 'notyet' dummy group");
+ p = pfi_if_create(name, pfi_dummy,
+ PFI_IFLAG_PLACEHOLDER);
+ }
+#else
+ if (q == NULL) {
+ pfi_newgroup(key.pfik_name, PFI_IFLAG_DYNAMIC);
+ q = pfi_lookup_if(key.pfik_name);
+ }
+ p = pfi_lookup_if(name);
+ if (p == NULL && q != NULL)
+ p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE);
+#endif
+ }
+ splx(s);
+ return (p);
+}
- kif->pfik_group = ifg;
- ifg->ifg_pf_kif = (caddr_t)kif;
+struct pfi_kif *
+pfi_attach_rule(const char *name)
+{
+ struct pfi_kif *p;
- splx(s);
+ p = pfi_lookup_create(name);
+ if (p != NULL)
+ p->pfik_rules++;
+ return (p);
}
void
-pfi_detach_ifgroup(struct ifg_group *ifg)
+pfi_detach_rule(struct pfi_kif *p)
{
- int s;
- struct pfi_kif *kif;
-
- if ((kif = (struct pfi_kif *)ifg->ifg_pf_kif) == NULL)
+ if (p == NULL)
return;
-
- s = splsoftnet();
- pfi_update++;
-
- kif->pfik_group = NULL;
- ifg->ifg_pf_kif = NULL;
- pfi_kif_unref(kif, PFI_KIF_REF_NONE);
- splx(s);
+ if (p->pfik_rules > 0)
+ p->pfik_rules--;
+ else
+ printf("pfi_detach_rule: reference count at 0\n");
+ pfi_maybe_destroy(p);
}
void
-pfi_group_change(const char *group)
+pfi_attach_state(struct pfi_kif *p)
{
- struct pfi_kif *kif;
- int s;
-
- s = splsoftnet();
- pfi_update++;
- if ((kif = pfi_kif_get(group)) == NULL)
- panic("pfi_kif_get failed");
-
- pfi_kif_update(kif);
-
- splx(s);
+ if (!p->pfik_states++)
+ TAILQ_INSERT_TAIL(&pfi_statehead, p, pfik_w_states);
}
-int
-pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
+void
+pfi_detach_state(struct pfi_kif *p)
{
- switch (af) {
-#ifdef INET
- case AF_INET:
- switch (dyn->pfid_acnt4) {
- case 0:
- return (0);
- case 1:
- return (PF_MATCHA(0, &dyn->pfid_addr4,
- &dyn->pfid_mask4, a, AF_INET));
- default:
- return (pfr_match_addr(dyn->pfid_kt, a, AF_INET));
- }
- break;
-#endif /* INET */
-#ifdef INET6
- case AF_INET6:
- switch (dyn->pfid_acnt6) {
- case 0:
- return (0);
- case 1:
- return (PF_MATCHA(0, &dyn->pfid_addr6,
- &dyn->pfid_mask6, a, AF_INET6));
- default:
- return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6));
- }
- break;
-#endif /* INET6 */
- default:
- return (0);
+ if (p == NULL)
+ return;
+ if (p->pfik_states <= 0) {
+ printf("pfi_detach_state: reference count <= 0\n");
+ return;
}
+ if (!--p->pfik_states)
+ TAILQ_REMOVE(&pfi_statehead, p, pfik_w_states);
+ pfi_maybe_destroy(p);
}
int
@@ -336,20 +512,15 @@ pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af)
if (aw->type != PF_ADDR_DYNIFTL)
return (0);
- if ((dyn = pool_get(&pfi_addr_pl, PR_NOWAIT)) == NULL)
+ dyn = pool_get(&pfi_addr_pl, PR_NOWAIT);
+ if (dyn == NULL)
return (1);
bzero(dyn, sizeof(*dyn));
s = splsoftnet();
- if (!strcmp(aw->v.ifname, "self"))
- dyn->pfid_kif = pfi_kif_get(IFG_ALL);
- else
- dyn->pfid_kif = pfi_kif_get(aw->v.ifname);
- if (dyn->pfid_kif == NULL) {
- rv = 1;
- goto _bad;
- }
- pfi_kif_ref(dyn->pfid_kif, PFI_KIF_REF_RULE);
+ dyn->pfid_kif = pfi_attach_rule(aw->v.ifname);
+ if (dyn->pfid_kif == NULL)
+ senderr(1);
dyn->pfid_net = pfi_unmask(&aw->v.a.mask);
if (af == AF_INET && dyn->pfid_net == 32)
@@ -366,23 +537,24 @@ pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af)
if (dyn->pfid_net != 128)
snprintf(tblname + strlen(tblname),
sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net);
- if ((ruleset = pf_find_or_create_ruleset(PF_RESERVED_ANCHOR)) == NULL) {
- rv = 1;
- goto _bad;
- }
+ ruleset = pf_find_or_create_ruleset(PF_RESERVED_ANCHOR);
+ if (ruleset == NULL)
+ senderr(1);
- if ((dyn->pfid_kt = pfr_attach_table(ruleset, tblname)) == NULL) {
- rv = 1;
- goto _bad;
- }
+ dyn->pfid_kt = pfr_attach_table(ruleset, tblname);
+ if (dyn->pfid_kt == NULL)
+ senderr(1);
dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE;
dyn->pfid_iflags = aw->iflags;
dyn->pfid_af = af;
+ dyn->pfid_hook_cookie = hook_establish(dyn->pfid_kif->pfik_ah_head, 1,
+ pfi_dynaddr_update, dyn);
+ if (dyn->pfid_hook_cookie == NULL)
+ senderr(1);
- TAILQ_INSERT_TAIL(&dyn->pfid_kif->pfik_dynaddrs, dyn, entry);
aw->p.dyn = dyn;
- pfi_kif_update(dyn->pfid_kif);
+ pfi_dynaddr_update(aw->p.dyn);
splx(s);
return (0);
@@ -392,32 +564,16 @@ _bad:
if (ruleset != NULL)
pf_remove_if_empty_ruleset(ruleset);
if (dyn->pfid_kif != NULL)
- pfi_kif_unref(dyn->pfid_kif, PFI_KIF_REF_RULE);
+ pfi_detach_rule(dyn->pfid_kif);
pool_put(&pfi_addr_pl, dyn);
splx(s);
return (rv);
}
void
-pfi_kif_update(struct pfi_kif *kif)
-{
- struct ifg_list *ifgl;
- struct pfi_dynaddr *p;
-
- /* update all dynaddr */
- TAILQ_FOREACH(p, &kif->pfik_dynaddrs, entry)
- pfi_dynaddr_update(p);
-
- /* again for all groups kif is member of */
- if (kif->pfik_ifp != NULL)
- TAILQ_FOREACH(ifgl, &kif->pfik_ifp->if_groups, ifgl_next)
- pfi_kif_update((struct pfi_kif *)
- ifgl->ifgl_group->ifg_pf_kif);
-}
-
-void
-pfi_dynaddr_update(struct pfi_dynaddr *dyn)
+pfi_dynaddr_update(void *p)
{
+ struct pfi_dynaddr *dyn = (struct pfi_dynaddr *)p;
struct pfi_kif *kif;
struct pfr_ktable *kt;
@@ -426,7 +582,6 @@ pfi_dynaddr_update(struct pfi_dynaddr *dyn)
kif = dyn->pfid_kif;
kt = dyn->pfid_kt;
-
if (kt->pfrkt_larg != pfi_update) {
/* this table needs to be brought up-to-date */
pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags);
@@ -439,18 +594,28 @@ void
pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags)
{
int e, size2 = 0;
- struct ifg_member *ifgm;
+ struct pfi_kif *p;
+ struct pfr_table t;
+ if ((kif->pfik_flags & PFI_IFLAG_INSTANCE) && kif->pfik_ifp == NULL) {
+ pfr_clr_addrs(&kt->pfrkt_t, NULL, 0);
+ return;
+ }
pfi_buffer_cnt = 0;
-
- if (kif->pfik_ifp != NULL)
+ if ((kif->pfik_flags & PFI_IFLAG_INSTANCE))
pfi_instance_add(kif->pfik_ifp, net, flags);
- else if (kif->pfik_group != NULL)
- TAILQ_FOREACH(ifgm, &kif->pfik_group->ifg_members, ifgm_next)
- pfi_instance_add(ifgm->ifgm_ifp, net, flags);
-
- if ((e = pfr_set_addrs(&kt->pfrkt_t, pfi_buffer, pfi_buffer_cnt, &size2,
- NULL, NULL, NULL, 0, PFR_TFLAG_ALLMASK)))
+ else if (strcmp(kif->pfik_name, "self")) {
+ TAILQ_FOREACH(p, &kif->pfik_grouphead, pfik_instances)
+ pfi_instance_add(p->pfik_ifp, net, flags);
+ } else {
+ RB_FOREACH(p, pfi_ifhead, &pfi_ifs)
+ if (p->pfik_flags & PFI_IFLAG_INSTANCE)
+ pfi_instance_add(p->pfik_ifp, net, flags);
+ }
+ t = kt->pfrkt_t;
+ t.pfrt_flags = 0;
+ if ((e = pfr_set_addrs(&t, pfi_buffer, pfi_buffer_cnt, &size2,
+ NULL, NULL, NULL, 0)))
printf("pfi_table_update: cannot set %d new addresses "
"into table %s: %d\n", pfi_buffer_cnt, kt->pfrkt_name, e);
}
@@ -470,6 +635,18 @@ pfi_instance_add(struct ifnet *ifp, int net, int flags)
af = ia->ifa_addr->sa_family;
if (af != AF_INET && af != AF_INET6)
continue;
+#ifdef __FreeBSD__
+ /*
+ * XXX: For point-to-point interfaces, (ifname:0) and IPv4,
+ * jump over addresses without a proper route to work
+ * around a problem with ppp not fully removing the
+ * address used during IPCP.
+ */
+ if ((ifp->if_flags & IFF_POINTOPOINT) &&
+ !(ia->ifa_flags & IFA_ROUTE) &&
+ (flags & PFI_AFLAG_NOALIAS) && (af == AF_INET))
+ continue;
+#endif
if ((flags & PFI_AFLAG_BROADCAST) && af == AF_INET6)
continue;
if ((flags & PFI_AFLAG_BROADCAST) &&
@@ -494,12 +671,13 @@ pfi_instance_add(struct ifnet *ifp, int net, int flags)
got6 = 1;
net2 = net;
if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) {
- if (af == AF_INET)
+ if (af == AF_INET) {
net2 = pfi_unmask(&((struct sockaddr_in *)
ia->ifa_netmask)->sin_addr);
- else if (af == AF_INET6)
+ } else if (af == AF_INET6) {
net2 = pfi_unmask(&((struct sockaddr_in6 *)
ia->ifa_netmask)->sin6_addr);
+ }
}
if (af == AF_INET && net2 > 32)
net2 = 32;
@@ -526,8 +704,13 @@ pfi_address_add(struct sockaddr *sa, int af, int net)
pfi_buffer_cnt, PFI_BUFFER_MAX);
return;
}
+#ifdef __FreeBSD__
+ p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE,
+ M_NOWAIT);
+#else
p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE,
M_DONTWAIT);
+#endif
if (p == NULL) {
printf("pfi_address_add: no memory to grow buffer "
"(%d/%d)\n", pfi_buffer_cnt, PFI_BUFFER_MAX);
@@ -547,9 +730,9 @@ pfi_address_add(struct sockaddr *sa, int af, int net)
p->pfra_net = net;
if (af == AF_INET)
p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr;
- else if (af == AF_INET6) {
+ if (af == AF_INET6) {
p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr;
- if (IN6_IS_SCOPE_EMBED(&p->pfra_ip6addr))
+ if (IN6_IS_ADDR_LINKLOCAL(&p->pfra_ip6addr))
p->pfra_ip6addr.s6_addr16[1] = 0;
}
/* mask network address bits */
@@ -569,8 +752,9 @@ pfi_dynaddr_remove(struct pf_addr_wrap *aw)
return;
s = splsoftnet();
- TAILQ_REMOVE(&aw->p.dyn->pfid_kif->pfik_dynaddrs, aw->p.dyn, entry);
- pfi_kif_unref(aw->p.dyn->pfid_kif, PFI_KIF_REF_RULE);
+ hook_disestablish(aw->p.dyn->pfid_kif->pfik_ah_head,
+ aw->p.dyn->pfid_hook_cookie);
+ pfi_detach_rule(aw->p.dyn->pfid_kif);
aw->p.dyn->pfid_kif = NULL;
pfr_detach_table(aw->p.dyn->pfid_kt);
aw->p.dyn->pfid_kt = NULL;
@@ -591,12 +775,11 @@ pfi_dynaddr_copyout(struct pf_addr_wrap *aw)
void
pfi_kifaddr_update(void *v)
{
- int s;
- struct pfi_kif *kif = (struct pfi_kif *)v;
+ int s;
s = splsoftnet();
pfi_update++;
- pfi_kif_update(kif);
+ pfi_dohooks(v);
splx(s);
}
@@ -606,16 +789,149 @@ pfi_if_compare(struct pfi_kif *p, struct pfi_kif *q)
return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ));
}
+struct pfi_kif *
+pfi_if_create(const char *name, struct pfi_kif *q, int flags)
+{
+ struct pfi_kif *p;
+
+#ifdef __FreeBSD__
+ p = malloc(sizeof(*p), PFI_MTYPE, M_NOWAIT);
+#else
+ p = malloc(sizeof(*p), PFI_MTYPE, M_DONTWAIT);
+#endif
+ if (p == NULL)
+ return (NULL);
+ bzero(p, sizeof(*p));
+#ifdef __FreeBSD__
+ p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE,
+ M_NOWAIT);
+#else
+ p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE,
+ M_DONTWAIT);
+#endif
+ if (p->pfik_ah_head == NULL) {
+ free(p, PFI_MTYPE);
+ return (NULL);
+ }
+ bzero(p->pfik_ah_head, sizeof(*p->pfik_ah_head));
+ TAILQ_INIT(p->pfik_ah_head);
+ TAILQ_INIT(&p->pfik_grouphead);
+ strlcpy(p->pfik_name, name, sizeof(p->pfik_name));
+ RB_INIT(&p->pfik_lan_ext);
+ RB_INIT(&p->pfik_ext_gwy);
+ p->pfik_flags = flags;
+ p->pfik_parent = q;
+#ifdef __FreeBSD__
+ /*
+ * It seems that the value of time_second is in unintialzied state when
+ * pf sets interface statistics clear time in boot phase if pf was
+ * statically linked to kernel. Instead of setting the bogus time value
+ * have pfi_get_ifaces handle this case. In pfi_get_ifaces it uses
+ * boottime.tv_sec if it sees the time is 0.
+ */
+ p->pfik_tzero = time_second > 1 ? time_second : 0;
+#else
+ p->pfik_tzero = time_second;
+#endif
+
+ RB_INSERT(pfi_ifhead, &pfi_ifs, p);
+ if (q != NULL) {
+ q->pfik_addcnt++;
+ TAILQ_INSERT_TAIL(&q->pfik_grouphead, p, pfik_instances);
+ }
+ pfi_ifcnt++;
+ return (p);
+}
+
+int
+pfi_maybe_destroy(struct pfi_kif *p)
+{
+ int i, j, k, s;
+ struct pfi_kif *q = p->pfik_parent;
+
+#ifdef __FreeBSD__
+ if ((p->pfik_flags & (PFI_IFLAG_ATTACHED | PFI_IFLAG_GROUP)) ||
+ ((p->pfik_rules > 0 || p->pfik_states > 0) &&
+ (p->pfik_flags & PFI_IFLAG_PLACEHOLDER) == 0))
+#else
+ if ((p->pfik_flags & (PFI_IFLAG_ATTACHED | PFI_IFLAG_GROUP)) ||
+ p->pfik_rules > 0 || p->pfik_states > 0)
+#endif
+ return (0);
+
+ s = splsoftnet();
+ if (q != NULL) {
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < 2; j++)
+ for (k = 0; k < 2; k++) {
+ q->pfik_bytes[i][j][k] +=
+ p->pfik_bytes[i][j][k];
+ q->pfik_packets[i][j][k] +=
+ p->pfik_packets[i][j][k];
+#ifdef __FreeBSD__
+ /* clear stats in case we return to the dummy group */
+ p->pfik_bytes[i][j][k] = 0;
+ p->pfik_packets[i][j][k] = 0;
+#endif
+ }
+ q->pfik_delcnt++;
+ TAILQ_REMOVE(&q->pfik_grouphead, p, pfik_instances);
+ }
+#ifdef __FreeBSD__
+ if (p->pfik_rules > 0 || p->pfik_states > 0) {
+ /* move back to the dummy group */
+ p->pfik_parent = pfi_dummy;
+ p->pfik_flags &= ~PFI_IFLAG_INSTANCE;
+ pfi_dummy->pfik_addcnt++;
+ TAILQ_INSERT_TAIL(&pfi_dummy->pfik_grouphead, p,
+ pfik_instances);
+ return (0);
+ }
+#endif
+ pfi_ifcnt--;
+ RB_REMOVE(pfi_ifhead, &pfi_ifs, p);
+ splx(s);
+
+ free(p->pfik_ah_head, PFI_MTYPE);
+ free(p, PFI_MTYPE);
+ return (1);
+}
+
+void
+pfi_copy_group(char *p, const char *q, int m)
+{
+ while (m > 1 && *q && !(*q >= '0' && *q <= '9')) {
+ *p++ = *q++;
+ m--;
+ }
+ if (m > 0)
+ *p++ = '\0';
+}
+
+void
+pfi_newgroup(const char *name, int flags)
+{
+ struct pfi_kif *p;
+
+ p = pfi_lookup_if(name);
+ if (p == NULL)
+ p = pfi_if_create(name, pfi_self, PFI_IFLAG_GROUP);
+ if (p == NULL) {
+ printf("pfi_newgroup: cannot allocate '%s' group", name);
+ return;
+ }
+ p->pfik_flags |= flags;
+}
+
void
pfi_fill_oldstatus(struct pf_status *pfs)
{
- struct pfi_kif *p;
- struct pfi_kif_cmp key;
- int i, j, k, s;
+ struct pfi_kif *p, key;
+ int i, j, k, s;
strlcpy(key.pfik_name, pfs->ifname, sizeof(key.pfik_name));
s = splsoftnet();
- p = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&key);
+ p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
if (p == NULL) {
splx(s);
return;
@@ -634,46 +950,92 @@ pfi_fill_oldstatus(struct pf_status *pfs)
}
int
-pfi_clr_istats(const char *name)
+pfi_clr_istats(const char *name, int *nzero, int flags)
{
struct pfi_kif *p;
- int s;
+ int n = 0, s;
+ long tzero = time_second;
+ ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE);
s = splsoftnet();
RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
- if (pfi_skip_if(name, p))
+ if (pfi_skip_if(name, p, flags))
continue;
bzero(p->pfik_packets, sizeof(p->pfik_packets));
bzero(p->pfik_bytes, sizeof(p->pfik_bytes));
- p->pfik_tzero = time_second;
+ p->pfik_tzero = tzero;
+ n++;
}
splx(s);
+ if (nzero != NULL)
+ *nzero = n;
+ return (0);
+}
+int
+pfi_set_flags(const char *name, int flags)
+{
+ struct pfi_kif *p;
+ int s;
+
+ if (flags & ~PFI_IFLAG_SETABLE_MASK)
+ return (EINVAL);
+
+ s = splsoftnet();
+ RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
+ if (pfi_skip_if(name, p, PFI_FLAG_GROUP|PFI_FLAG_INSTANCE))
+ continue;
+ p->pfik_flags |= flags;
+ }
+ splx(s);
return (0);
}
int
-pfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size)
+pfi_clear_flags(const char *name, int flags)
+{
+ struct pfi_kif *p;
+ int s;
+
+ if (flags & ~PFI_IFLAG_SETABLE_MASK)
+ return (EINVAL);
+
+ s = splsoftnet();
+ RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
+ if (pfi_skip_if(name, p, PFI_FLAG_GROUP|PFI_FLAG_INSTANCE))
+ continue;
+ p->pfik_flags &= ~flags;
+ }
+ splx(s);
+ return (0);
+}
+
+int
+pfi_get_ifaces(const char *name, struct pfi_if *buf, int *size, int flags)
{
- struct pfi_kif *p, *nextp;
+ struct pfi_kif *p;
int s, n = 0;
+#ifdef __FreeBSD__
+ int ec;
+#endif
+ ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE);
s = splsoftnet();
- for (p = RB_MIN(pfi_ifhead, &pfi_ifs); p; p = nextp) {
- nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p);
- if (pfi_skip_if(name, p))
+ RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
+ if (pfi_skip_if(name, p, flags))
continue;
if (*size > n++) {
if (!p->pfik_tzero)
p->pfik_tzero = time_second;
- pfi_kif_ref(p, PFI_KIF_REF_RULE);
+#ifdef __FreeBSD__
+ PF_COPYOUT(p, buf++, sizeof(*buf), ec);
+ if (ec) {
+#else
if (copyout(p, buf++, sizeof(*buf))) {
- pfi_kif_unref(p, PFI_KIF_REF_RULE);
+#endif
splx(s);
return (EFAULT);
}
- nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p);
- pfi_kif_unref(p, PFI_KIF_REF_RULE);
}
}
splx(s);
@@ -681,11 +1043,25 @@ pfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size)
return (0);
}
+struct pfi_kif *
+pfi_lookup_if(const char *name)
+{
+ struct pfi_kif *p, key;
+
+ strlcpy(key.pfik_name, name, sizeof(key.pfik_name));
+ p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
+ return (p);
+}
+
int
-pfi_skip_if(const char *filter, struct pfi_kif *p)
+pfi_skip_if(const char *filter, struct pfi_kif *p, int f)
{
int n;
+ if ((p->pfik_flags & PFI_IFLAG_GROUP) && !(f & PFI_FLAG_GROUP))
+ return (1);
+ if ((p->pfik_flags & PFI_IFLAG_INSTANCE) && !(f & PFI_FLAG_INSTANCE))
+ return (1);
if (filter == NULL || !*filter)
return (0);
if (!strcmp(p->pfik_name, filter))
@@ -700,38 +1076,6 @@ pfi_skip_if(const char *filter, struct pfi_kif *p)
return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9');
}
-int
-pfi_set_flags(const char *name, int flags)
-{
- struct pfi_kif *p;
- int s;
-
- s = splsoftnet();
- RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
- if (pfi_skip_if(name, p))
- continue;
- p->pfik_flags |= flags;
- }
- splx(s);
- return (0);
-}
-
-int
-pfi_clear_flags(const char *name, int flags)
-{
- struct pfi_kif *p;
- int s;
-
- s = splsoftnet();
- RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
- if (pfi_skip_if(name, p))
- continue;
- p->pfik_flags &= ~flags;
- }
- splx(s);
- return (0);
-}
-
/* from pf_print_state.c */
int
pfi_unmask(void *addr)
@@ -752,3 +1096,44 @@ pfi_unmask(void *addr)
return (b);
}
+void
+pfi_dohooks(struct pfi_kif *p)
+{
+ for (; p != NULL; p = p->pfik_parent)
+ dohooks(p->pfik_ah_head, 0);
+}
+
+int
+pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
+{
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ switch (dyn->pfid_acnt4) {
+ case 0:
+ return (0);
+ case 1:
+ return (PF_MATCHA(0, &dyn->pfid_addr4,
+ &dyn->pfid_mask4, a, AF_INET));
+ default:
+ return (pfr_match_addr(dyn->pfid_kt, a, AF_INET));
+ }
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ switch (dyn->pfid_acnt6) {
+ case 0:
+ return (0);
+ case 1:
+ return (PF_MATCHA(0, &dyn->pfid_addr6,
+ &dyn->pfid_mask6, a, AF_INET6));
+ default:
+ return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6));
+ }
+ break;
+#endif /* INET6 */
+ default:
+ return (0);
+ }
+}
diff --git a/sys/contrib/pf/net/pf_ioctl.c b/sys/contrib/pf/net/pf_ioctl.c
index 5694717..ddb2fec 100644
--- a/sys/contrib/pf/net/pf_ioctl.c
+++ b/sys/contrib/pf/net/pf_ioctl.c
@@ -1,4 +1,6 @@
-/* $OpenBSD: pf_ioctl.c,v 1.175 2007/02/26 22:47:43 deraadt Exp $ */
+/* $FreeBSD$ */
+/* $OpenBSD: pf_ioctl.c,v 1.139 2005/03/03 07:13:39 dhartmei Exp $ */
+/* add: $OpenBSD: pf_ioctl.c,v 1.168 2006/07/21 01:21:17 dhartmei Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -35,7 +37,38 @@
*
*/
+#ifdef __FreeBSD__
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#endif
+
+#ifdef __FreeBSD__
+#include "opt_bpf.h"
+#include "opt_pf.h"
+
+#ifdef DEV_BPF
+#define NBPFILTER DEV_BPF
+#else
+#define NBPFILTER 0
+#endif
+
+#ifdef DEV_PFLOG
+#define NPFLOG DEV_PFLOG
+#else
+#define NPFLOG 0
+#endif
+
+#ifdef DEV_PFSYNC
+#define NPFSYNC DEV_PFSYNC
+#else
+#define NPFSYNC 0
+#endif
+
+#else
+#include "bpfilter.h"
+#include "pflog.h"
#include "pfsync.h"
+#endif
#include <sys/param.h>
#include <sys/systm.h>
@@ -46,13 +79,15 @@
#include <sys/socketvar.h>
#include <sys/kernel.h>
#include <sys/time.h>
+#include <sys/malloc.h>
+#ifdef __FreeBSD__
+#include <sys/module.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#else
#include <sys/timeout.h>
#include <sys/pool.h>
-#include <sys/proc.h>
-#include <sys/malloc.h>
-#include <sys/kthread.h>
-#include <sys/rwlock.h>
-#include <uvm/uvm_extern.h>
+#endif
#include <net/if.h>
#include <net/if_types.h>
@@ -65,17 +100,18 @@
#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>
+#ifndef __FreeBSD__
#include <dev/rndvar.h>
-#include <crypto/md5.h>
+#endif
#include <net/pfvar.h>
#if NPFSYNC > 0
#include <net/if_pfsync.h>
#endif /* NPFSYNC > 0 */
-#if NPFLOG > 0
+#ifdef __FreeBSD__
#include <net/if_pflog.h>
-#endif /* NPFLOG > 0 */
+#endif
#ifdef INET6
#include <netinet/ip6.h>
@@ -86,16 +122,39 @@
#include <altq/altq.h>
#endif
+#ifdef __FreeBSD__
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <net/pfil.h>
+#endif /* __FreeBSD__ */
+
+#ifdef __FreeBSD__
+void init_zone_var(void);
+void cleanup_pf_zone(void);
+int pfattach(void);
+#else
void pfattach(int);
-void pf_thread_create(void *);
int pfopen(dev_t, int, int, struct proc *);
int pfclose(dev_t, int, int, struct proc *);
+#endif
struct pf_pool *pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t,
u_int8_t, u_int8_t, u_int8_t);
+int pf_get_ruleset_number(u_int8_t);
+void pf_init_ruleset(struct pf_ruleset *);
+int pf_anchor_setup(struct pf_rule *,
+ const struct pf_ruleset *, const char *);
+int pf_anchor_copyout(const struct pf_ruleset *,
+ const struct pf_rule *, struct pfioc_rule *);
+void pf_anchor_remove(struct pf_rule *);
void pf_mv_pool(struct pf_palist *, struct pf_palist *);
void pf_empty_pool(struct pf_palist *);
-int pfioctl(dev_t, u_long, caddr_t, int, struct proc *);
+#ifdef __FreeBSD__
+int pfioctl(struct cdev *, u_long, caddr_t, int, struct thread *);
+#else
+int pfioctl(struct cdev *, u_long, caddr_t, int, struct proc *);
+#endif
#ifdef ALTQ
int pf_begin_altq(u_int32_t *);
int pf_rollback_altq(u_int32_t);
@@ -105,13 +164,15 @@ int pf_disable_altq(struct pf_altq *);
#endif /* ALTQ */
int pf_begin_rules(u_int32_t *, int, const char *);
int pf_rollback_rules(u_int32_t, int, char *);
-int pf_setup_pfsync_matching(struct pf_ruleset *);
-void pf_hash_rule(MD5_CTX *, struct pf_rule *);
-void pf_hash_rule_addr(MD5_CTX *, struct pf_rule_addr *);
int pf_commit_rules(u_int32_t, int, char *);
+#ifdef __FreeBSD__
+extern struct callout pf_expire_to;
+#else
+extern struct timeout pf_expire_to;
+#endif
+
struct pf_rule pf_default_rule;
-struct rwlock pf_consistency_lock = RWLOCK_INITIALIZER;
#ifdef ALTQ
static int pf_altq_running;
#endif
@@ -123,15 +184,194 @@ TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags),
#if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE)
#error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE
#endif
-u_int16_t tagname2tag(struct pf_tags *, char *);
-void tag2tagname(struct pf_tags *, u_int16_t, char *);
-void tag_unref(struct pf_tags *, u_int16_t);
+static u_int16_t tagname2tag(struct pf_tags *, char *);
+static void tag2tagname(struct pf_tags *, u_int16_t, char *);
+static void tag_unref(struct pf_tags *, u_int16_t);
int pf_rtlabel_add(struct pf_addr_wrap *);
void pf_rtlabel_remove(struct pf_addr_wrap *);
void pf_rtlabel_copyout(struct pf_addr_wrap *);
#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x
+
+#ifdef __FreeBSD__
+static struct cdev *pf_dev;
+
+/*
+ * XXX - These are new and need to be checked when moveing to a new version
+ */
+static void pf_clear_states(void);
+static int pf_clear_tables(void);
+static void pf_clear_srcnodes(void);
+/*
+ * XXX - These are new and need to be checked when moveing to a new version
+ */
+
+/*
+ * Wrapper functions for pfil(9) hooks
+ */
+static int pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp,
+ int dir, struct inpcb *inp);
+static int pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp,
+ int dir, struct inpcb *inp);
+#ifdef INET6
+static int pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp,
+ int dir, struct inpcb *inp);
+static int pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp,
+ int dir, struct inpcb *inp);
+#endif
+
+static int hook_pf(void);
+static int dehook_pf(void);
+static int shutdown_pf(void);
+static int pf_load(void);
+static int pf_unload(void);
+
+static struct cdevsw pf_cdevsw = {
+ .d_ioctl = pfioctl,
+ .d_name = PF_NAME,
+ .d_version = D_VERSION,
+};
+
+static volatile int pf_pfil_hooked = 0;
+struct mtx pf_task_mtx;
+pflog_packet_t *pflog_packet_ptr = NULL;
+
+void
+init_pf_mutex(void)
+{
+ mtx_init(&pf_task_mtx, "pf task mtx", NULL, MTX_DEF);
+}
+
+void
+destroy_pf_mutex(void)
+{
+ mtx_destroy(&pf_task_mtx);
+}
+
+void
+init_zone_var(void)
+{
+ pf_src_tree_pl = pf_rule_pl = NULL;
+ pf_state_pl = pf_altq_pl = pf_pooladdr_pl = NULL;
+ pf_frent_pl = pf_frag_pl = pf_cache_pl = pf_cent_pl = NULL;
+ pf_state_scrub_pl = NULL;
+ pfr_ktable_pl = pfr_kentry_pl = NULL;
+}
+
+void
+cleanup_pf_zone(void)
+{
+ UMA_DESTROY(pf_src_tree_pl);
+ UMA_DESTROY(pf_rule_pl);
+ UMA_DESTROY(pf_state_pl);
+ UMA_DESTROY(pf_altq_pl);
+ UMA_DESTROY(pf_pooladdr_pl);
+ UMA_DESTROY(pf_frent_pl);
+ UMA_DESTROY(pf_frag_pl);
+ UMA_DESTROY(pf_cache_pl);
+ UMA_DESTROY(pf_cent_pl);
+ UMA_DESTROY(pfr_ktable_pl);
+ UMA_DESTROY(pfr_kentry_pl2);
+ UMA_DESTROY(pfr_kentry_pl);
+ UMA_DESTROY(pf_state_scrub_pl);
+ UMA_DESTROY(pfi_addr_pl);
+}
+
+int
+pfattach(void)
+{
+ u_int32_t *my_timeout = pf_default_rule.timeout;
+ int error = 1;
+
+ do {
+ UMA_CREATE(pf_src_tree_pl,struct pf_src_node, "pfsrctrpl");
+ UMA_CREATE(pf_rule_pl, struct pf_rule, "pfrulepl");
+ UMA_CREATE(pf_state_pl, struct pf_state, "pfstatepl");
+ UMA_CREATE(pf_altq_pl, struct pf_altq, "pfaltqpl");
+ UMA_CREATE(pf_pooladdr_pl, struct pf_pooladdr, "pfpooladdrpl");
+ UMA_CREATE(pfr_ktable_pl, struct pfr_ktable, "pfrktable");
+ UMA_CREATE(pfr_kentry_pl, struct pfr_kentry, "pfrkentry");
+ UMA_CREATE(pfr_kentry_pl2, struct pfr_kentry, "pfrkentry2");
+ UMA_CREATE(pf_frent_pl, struct pf_frent, "pffrent");
+ UMA_CREATE(pf_frag_pl, struct pf_fragment, "pffrag");
+ UMA_CREATE(pf_cache_pl, struct pf_fragment, "pffrcache");
+ UMA_CREATE(pf_cent_pl, struct pf_frcache, "pffrcent");
+ UMA_CREATE(pf_state_scrub_pl, struct pf_state_scrub,
+ "pfstatescrub");
+ UMA_CREATE(pfi_addr_pl, struct pfi_dynaddr, "pfiaddrpl");
+ error = 0;
+ } while(0);
+ if (error) {
+ cleanup_pf_zone();
+ return (error);
+ }
+ pfr_initialize();
+ pfi_initialize();
+ if ( (error = pf_osfp_initialize()) ) {
+ cleanup_pf_zone();
+ pf_osfp_cleanup();
+ return (error);
+ }
+
+ pf_pool_limits[PF_LIMIT_STATES].pp = pf_state_pl;
+ pf_pool_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT;
+ pf_pool_limits[PF_LIMIT_SRC_NODES].pp = pf_src_tree_pl;
+ pf_pool_limits[PF_LIMIT_SRC_NODES].limit = PFSNODE_HIWAT;
+ pf_pool_limits[PF_LIMIT_FRAGS].pp = pf_frent_pl;
+ pf_pool_limits[PF_LIMIT_FRAGS].limit = PFFRAG_FRENT_HIWAT;
+ uma_zone_set_max(pf_pool_limits[PF_LIMIT_STATES].pp,
+ pf_pool_limits[PF_LIMIT_STATES].limit);
+
+ RB_INIT(&tree_src_tracking);
+ RB_INIT(&pf_anchors);
+ pf_init_ruleset(&pf_main_ruleset);
+ TAILQ_INIT(&pf_altqs[0]);
+ TAILQ_INIT(&pf_altqs[1]);
+ TAILQ_INIT(&pf_pabuf);
+ pf_altqs_active = &pf_altqs[0];
+ pf_altqs_inactive = &pf_altqs[1];
+ TAILQ_INIT(&state_updates);
+
+ /* default rule should never be garbage collected */
+ pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
+ pf_default_rule.action = PF_PASS;
+ pf_default_rule.nr = -1;
+
+ /* initialize default timeouts */
+ my_timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
+ my_timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
+ my_timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
+ my_timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
+ my_timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
+ my_timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
+ my_timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
+ my_timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
+ my_timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
+ my_timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
+ my_timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
+ my_timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
+ my_timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
+ my_timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
+ my_timeout[PFTM_FRAG] = PFTM_FRAG_VAL;
+ my_timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
+ my_timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
+ my_timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
+
+ callout_init(&pf_expire_to, NET_CALLOUT_MPSAFE);
+ callout_reset(&pf_expire_to, my_timeout[PFTM_INTERVAL] * hz,
+ pf_purge_timeout, &pf_expire_to);
+
+ pf_normalize_init();
+ bzero(&pf_status, sizeof(pf_status));
+ pf_pfil_hooked = 0;
+
+ /* XXX do our best to avoid a conflict */
+ pf_status.hostid = arc4random();
+
+ return (error);
+}
+#else /* !__FreeBSD__ */
void
pfattach(int num)
{
@@ -154,10 +394,6 @@ pfattach(int num)
pool_sethardlimit(pf_pool_limits[PF_LIMIT_STATES].pp,
pf_pool_limits[PF_LIMIT_STATES].limit, NULL, 0);
- if (ctob(physmem) <= 100*1024*1024)
- pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit =
- PFR_KENTRY_HIWAT_SMALL;
-
RB_INIT(&tree_src_tracking);
RB_INIT(&pf_anchors);
pf_init_ruleset(&pf_main_ruleset);
@@ -166,13 +402,12 @@ pfattach(int num)
TAILQ_INIT(&pf_pabuf);
pf_altqs_active = &pf_altqs[0];
pf_altqs_inactive = &pf_altqs[1];
- TAILQ_INIT(&state_list);
+ TAILQ_INIT(&state_updates);
/* default rule should never be garbage collected */
pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
pf_default_rule.action = PF_PASS;
pf_default_rule.nr = -1;
- pf_default_rule.rtableid = -1;
/* initialize default timeouts */
timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
@@ -193,8 +428,9 @@ pfattach(int num)
timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
- timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
- timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
+
+ timeout_set(&pf_expire_to, pf_purge_timeout, &pf_expire_to);
+ timeout_add(&pf_expire_to, timeout[PFTM_INTERVAL] * hz);
pf_normalize_init();
bzero(&pf_status, sizeof(pf_status));
@@ -202,20 +438,10 @@ pfattach(int num)
/* XXX do our best to avoid a conflict */
pf_status.hostid = arc4random();
-
- /* require process context to purge states, so perform in a thread */
- kthread_create_deferred(pf_thread_create, NULL);
-}
-
-void
-pf_thread_create(void *v)
-{
- if (kthread_create(pf_purge_thread, NULL, NULL, "pfpurge"))
- panic("pfpurge thread");
}
int
-pfopen(dev_t dev, int flags, int fmt, struct proc *p)
+pfopen(struct cdev *dev, int flags, int fmt, struct proc *p)
{
if (minor(dev) >= 1)
return (ENXIO);
@@ -223,12 +449,13 @@ pfopen(dev_t dev, int flags, int fmt, struct proc *p)
}
int
-pfclose(dev_t dev, int flags, int fmt, struct proc *p)
+pfclose(struct cdev *dev, int flags, int fmt, struct proc *p)
{
if (minor(dev) >= 1)
return (ENXIO);
return (0);
}
+#endif /* __FreeBSD__ */
struct pf_pool *
pf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action,
@@ -274,6 +501,312 @@ pf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action,
return (&rule->rpool);
}
+int
+pf_get_ruleset_number(u_int8_t action)
+{
+ switch (action) {
+ case PF_SCRUB:
+ case PF_NOSCRUB:
+ return (PF_RULESET_SCRUB);
+ break;
+ case PF_PASS:
+ case PF_DROP:
+ return (PF_RULESET_FILTER);
+ break;
+ case PF_NAT:
+ case PF_NONAT:
+ return (PF_RULESET_NAT);
+ break;
+ case PF_BINAT:
+ case PF_NOBINAT:
+ return (PF_RULESET_BINAT);
+ break;
+ case PF_RDR:
+ case PF_NORDR:
+ return (PF_RULESET_RDR);
+ break;
+ default:
+ return (PF_RULESET_MAX);
+ break;
+ }
+}
+
+void
+pf_init_ruleset(struct pf_ruleset *ruleset)
+{
+ int i;
+
+ memset(ruleset, 0, sizeof(struct pf_ruleset));
+ for (i = 0; i < PF_RULESET_MAX; i++) {
+ TAILQ_INIT(&ruleset->rules[i].queues[0]);
+ TAILQ_INIT(&ruleset->rules[i].queues[1]);
+ ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0];
+ ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1];
+ }
+}
+
+struct pf_anchor *
+pf_find_anchor(const char *path)
+{
+ static struct pf_anchor key;
+
+ memset(&key, 0, sizeof(key));
+ strlcpy(key.path, path, sizeof(key.path));
+ return (RB_FIND(pf_anchor_global, &pf_anchors, &key));
+}
+
+struct pf_ruleset *
+pf_find_ruleset(const char *path)
+{
+ struct pf_anchor *anchor;
+
+ while (*path == '/')
+ path++;
+ if (!*path)
+ return (&pf_main_ruleset);
+ anchor = pf_find_anchor(path);
+ if (anchor == NULL)
+ return (NULL);
+ else
+ return (&anchor->ruleset);
+}
+
+struct pf_ruleset *
+pf_find_or_create_ruleset(const char *path)
+{
+ static char p[MAXPATHLEN];
+ char *q = NULL, *r; /* make the compiler happy */
+ struct pf_ruleset *ruleset;
+ struct pf_anchor *anchor = NULL, *dup, *parent = NULL;
+
+ while (*path == '/')
+ path++;
+ ruleset = pf_find_ruleset(path);
+ if (ruleset != NULL)
+ return (ruleset);
+ strlcpy(p, path, sizeof(p));
+#ifdef __FreeBSD__
+ while (parent == NULL && (q = rindex(p, '/')) != NULL) {
+#else
+ while (parent == NULL && (q = strrchr(p, '/')) != NULL) {
+#endif
+ *q = 0;
+ if ((ruleset = pf_find_ruleset(p)) != NULL) {
+ parent = ruleset->anchor;
+ break;
+ }
+ }
+ if (q == NULL)
+ q = p;
+ else
+ q++;
+ strlcpy(p, path, sizeof(p));
+ if (!*q)
+ return (NULL);
+#ifdef __FreeBSD__
+ while ((r = index(q, '/')) != NULL || *q) {
+#else
+ while ((r = strchr(q, '/')) != NULL || *q) {
+#endif
+ if (r != NULL)
+ *r = 0;
+ if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
+ (parent != NULL && strlen(parent->path) >=
+ MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1))
+ return (NULL);
+ anchor = (struct pf_anchor *)malloc(sizeof(*anchor), M_TEMP,
+ M_NOWAIT);
+ if (anchor == NULL)
+ return (NULL);
+ memset(anchor, 0, sizeof(*anchor));
+ RB_INIT(&anchor->children);
+ strlcpy(anchor->name, q, sizeof(anchor->name));
+ if (parent != NULL) {
+ strlcpy(anchor->path, parent->path,
+ sizeof(anchor->path));
+ strlcat(anchor->path, "/", sizeof(anchor->path));
+ }
+ strlcat(anchor->path, anchor->name, sizeof(anchor->path));
+ if ((dup = RB_INSERT(pf_anchor_global, &pf_anchors, anchor)) !=
+ NULL) {
+ printf("pf_find_or_create_ruleset: RB_INSERT1 "
+ "'%s' '%s' collides with '%s' '%s'\n",
+ anchor->path, anchor->name, dup->path, dup->name);
+ free(anchor, M_TEMP);
+ return (NULL);
+ }
+ if (parent != NULL) {
+ anchor->parent = parent;
+ if ((dup = RB_INSERT(pf_anchor_node, &parent->children,
+ anchor)) != NULL) {
+ printf("pf_find_or_create_ruleset: "
+ "RB_INSERT2 '%s' '%s' collides with "
+ "'%s' '%s'\n", anchor->path, anchor->name,
+ dup->path, dup->name);
+ RB_REMOVE(pf_anchor_global, &pf_anchors,
+ anchor);
+ free(anchor, M_TEMP);
+ return (NULL);
+ }
+ }
+ pf_init_ruleset(&anchor->ruleset);
+ anchor->ruleset.anchor = anchor;
+ parent = anchor;
+ if (r != NULL)
+ q = r + 1;
+ else
+ *q = 0;
+ }
+ return (&anchor->ruleset);
+}
+
+void
+pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
+{
+ struct pf_anchor *parent;
+ int i;
+
+ while (ruleset != NULL) {
+ if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL ||
+ !RB_EMPTY(&ruleset->anchor->children) ||
+ ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
+ ruleset->topen)
+ return;
+ for (i = 0; i < PF_RULESET_MAX; ++i)
+ if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
+ !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) ||
+ ruleset->rules[i].inactive.open)
+ return;
+ RB_REMOVE(pf_anchor_global, &pf_anchors, ruleset->anchor);
+ if ((parent = ruleset->anchor->parent) != NULL)
+ RB_REMOVE(pf_anchor_node, &parent->children,
+ ruleset->anchor);
+ free(ruleset->anchor, M_TEMP);
+ if (parent == NULL)
+ return;
+ ruleset = &parent->ruleset;
+ }
+}
+
+int
+pf_anchor_setup(struct pf_rule *r, const struct pf_ruleset *s,
+ const char *name)
+{
+ static char *p, path[MAXPATHLEN];
+ struct pf_ruleset *ruleset;
+
+ r->anchor = NULL;
+ r->anchor_relative = 0;
+ r->anchor_wildcard = 0;
+ if (!name[0])
+ return (0);
+ if (name[0] == '/')
+ strlcpy(path, name + 1, sizeof(path));
+ else {
+ /* relative path */
+ r->anchor_relative = 1;
+ if (s->anchor == NULL || !s->anchor->path[0])
+ path[0] = 0;
+ else
+ strlcpy(path, s->anchor->path, sizeof(path));
+ while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
+ if (!path[0]) {
+ printf("pf_anchor_setup: .. beyond root\n");
+ return (1);
+ }
+#ifdef __FreeBSD__
+ if ((p = rindex(path, '/')) != NULL)
+#else
+ if ((p = strrchr(path, '/')) != NULL)
+#endif
+ *p = 0;
+ else
+ path[0] = 0;
+ r->anchor_relative++;
+ name += 3;
+ }
+ if (path[0])
+ strlcat(path, "/", sizeof(path));
+ strlcat(path, name, sizeof(path));
+ }
+#ifdef __FreeBSD__
+ if ((p = rindex(path, '/')) != NULL && !strcmp(p, "/*")) {
+#else
+ if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
+#endif
+ r->anchor_wildcard = 1;
+ *p = 0;
+ }
+ ruleset = pf_find_or_create_ruleset(path);
+ if (ruleset == NULL || ruleset->anchor == NULL) {
+ printf("pf_anchor_setup: ruleset\n");
+ return (1);
+ }
+ r->anchor = ruleset->anchor;
+ r->anchor->refcnt++;
+ return (0);
+}
+
+int
+pf_anchor_copyout(const struct pf_ruleset *rs, const struct pf_rule *r,
+ struct pfioc_rule *pr)
+{
+ pr->anchor_call[0] = 0;
+ if (r->anchor == NULL)
+ return (0);
+ if (!r->anchor_relative) {
+ strlcpy(pr->anchor_call, "/", sizeof(pr->anchor_call));
+ strlcat(pr->anchor_call, r->anchor->path,
+ sizeof(pr->anchor_call));
+ } else {
+ char a[MAXPATHLEN], b[MAXPATHLEN], *p;
+ int i;
+
+ if (rs->anchor == NULL)
+ a[0] = 0;
+ else
+ strlcpy(a, rs->anchor->path, sizeof(a));
+ strlcpy(b, r->anchor->path, sizeof(b));
+ for (i = 1; i < r->anchor_relative; ++i) {
+#ifdef __FreeBSD__
+ if ((p = rindex(a, '/')) == NULL)
+#else
+ if ((p = strrchr(a, '/')) == NULL)
+#endif
+ p = a;
+ *p = 0;
+ strlcat(pr->anchor_call, "../",
+ sizeof(pr->anchor_call));
+ }
+ if (strncmp(a, b, strlen(a))) {
+ printf("pf_anchor_copyout: '%s' '%s'\n", a, b);
+ return (1);
+ }
+ if (strlen(b) > strlen(a))
+ strlcat(pr->anchor_call, b + (a[0] ? strlen(a) + 1 : 0),
+ sizeof(pr->anchor_call));
+ }
+ if (r->anchor_wildcard)
+ strlcat(pr->anchor_call, pr->anchor_call[0] ? "/*" : "*",
+ sizeof(pr->anchor_call));
+ return (0);
+}
+
+void
+pf_anchor_remove(struct pf_rule *r)
+{
+ if (r->anchor == NULL)
+ return;
+ if (r->anchor->refcnt <= 0) {
+ printf("pf_anchor_remove: broken refcount");
+ r->anchor = NULL;
+ return;
+ }
+ if (!--r->anchor->refcnt)
+ pf_remove_if_empty_ruleset(&r->anchor->ruleset);
+ r->anchor = NULL;
+}
+
void
pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb)
{
@@ -293,7 +826,7 @@ pf_empty_pool(struct pf_palist *poola)
while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) {
pfi_dynaddr_remove(&empty_pool_pa->addr);
pf_tbladdr_remove(&empty_pool_pa->addr);
- pfi_kif_unref(empty_pool_pa->kif, PFI_KIF_REF_RULE);
+ pfi_detach_rule(empty_pool_pa->kif);
TAILQ_REMOVE(poola, empty_pool_pa, entries);
pool_put(&pf_pooladdr_pl, empty_pool_pa);
}
@@ -339,13 +872,13 @@ pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
if (rule->overload_tbl)
pfr_detach_table(rule->overload_tbl);
}
- pfi_kif_unref(rule->kif, PFI_KIF_REF_RULE);
+ pfi_detach_rule(rule->kif);
pf_anchor_remove(rule);
pf_empty_pool(&rule->rpool.list);
pool_put(&pf_rule_pl, rule);
}
-u_int16_t
+static u_int16_t
tagname2tag(struct pf_tags *head, char *tagname)
{
struct pf_tagname *tag, *p = NULL;
@@ -390,7 +923,7 @@ tagname2tag(struct pf_tags *head, char *tagname)
return (tag->tag);
}
-void
+static void
tag2tagname(struct pf_tags *head, u_int16_t tagid, char *p)
{
struct pf_tagname *tag;
@@ -402,7 +935,7 @@ tag2tagname(struct pf_tags *head, u_int16_t tagid, char *p)
}
}
-void
+static void
tag_unref(struct pf_tags *head, u_int16_t tag)
{
struct pf_tagname *p, *next;
@@ -431,7 +964,7 @@ pf_tagname2tag(char *tagname)
void
pf_tag2tagname(u_int16_t tagid, char *p)
{
- tag2tagname(&pf_tags, tagid, p);
+ return (tag2tagname(&pf_tags, tagid, p));
}
void
@@ -449,28 +982,42 @@ pf_tag_ref(u_int16_t tag)
void
pf_tag_unref(u_int16_t tag)
{
- tag_unref(&pf_tags, tag);
+ return (tag_unref(&pf_tags, tag));
}
int
pf_rtlabel_add(struct pf_addr_wrap *a)
{
+#ifdef __FreeBSD__
+ /* XXX_IMPORT: later */
+ return (0);
+#else
if (a->type == PF_ADDR_RTLABEL &&
(a->v.rtlabel = rtlabel_name2id(a->v.rtlabelname)) == 0)
return (-1);
return (0);
+#endif
}
void
pf_rtlabel_remove(struct pf_addr_wrap *a)
{
+#ifdef __FreeBSD__
+ /* XXX_IMPORT: later */
+#else
if (a->type == PF_ADDR_RTLABEL)
rtlabel_unref(a->v.rtlabel);
+#endif
}
void
pf_rtlabel_copyout(struct pf_addr_wrap *a)
{
+#ifdef __FreeBSD__
+ /* XXX_IMPORT: later */
+ if (a->type == PF_ADDR_RTLABEL && a->v.rtlabel)
+ strlcpy(a->v.rtlabelname, "?", sizeof(a->v.rtlabelname));
+#else
const char *name;
if (a->type == PF_ADDR_RTLABEL && a->v.rtlabel) {
@@ -481,6 +1028,7 @@ pf_rtlabel_copyout(struct pf_addr_wrap *a)
strlcpy(a->v.rtlabelname, name,
sizeof(a->v.rtlabelname));
}
+#endif
}
#ifdef ALTQ
@@ -493,13 +1041,13 @@ pf_qname2qid(char *qname)
void
pf_qid2qname(u_int32_t qid, char *p)
{
- tag2tagname(&pf_qids, (u_int16_t)qid, p);
+ return (tag2tagname(&pf_qids, (u_int16_t)qid, p));
}
void
pf_qid_unref(u_int32_t qid)
{
- tag_unref(&pf_qids, (u_int16_t)qid);
+ return (tag_unref(&pf_qids, (u_int16_t)qid));
}
int
@@ -618,8 +1166,14 @@ pf_enable_altq(struct pf_altq *altq)
if (error == 0 && ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) {
tb.rate = altq->ifbandwidth;
tb.depth = altq->tbrsize;
- s = splnet();
+ s = splimp();
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
error = tbr_set(&ifp->if_snd, &tb);
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
splx(s);
}
@@ -648,8 +1202,14 @@ pf_disable_altq(struct pf_altq *altq)
if (error == 0) {
/* clear tokenbucket regulator */
tb.rate = 0;
- s = splnet();
+ s = splimp();
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
error = tbr_set(&ifp->if_snd, &tb);
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
splx(s);
}
@@ -668,10 +1228,8 @@ pf_begin_rules(u_int32_t *ticket, int rs_num, const char *anchor)
rs = pf_find_or_create_ruleset(anchor);
if (rs == NULL)
return (EINVAL);
- while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
+ while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL)
pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
- rs->rules[rs_num].inactive.rcount--;
- }
*ticket = ++rs->rules[rs_num].inactive.ticket;
rs->rules[rs_num].inactive.open = 1;
return (0);
@@ -689,105 +1247,19 @@ pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor)
if (rs == NULL || !rs->rules[rs_num].inactive.open ||
rs->rules[rs_num].inactive.ticket != ticket)
return (0);
- while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
+ while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL)
pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
- rs->rules[rs_num].inactive.rcount--;
- }
rs->rules[rs_num].inactive.open = 0;
return (0);
}
-#define PF_MD5_UPD(st, elm) \
- MD5Update(ctx, (u_int8_t *) &(st)->elm, sizeof((st)->elm))
-
-#define PF_MD5_UPD_STR(st, elm) \
- MD5Update(ctx, (u_int8_t *) (st)->elm, strlen((st)->elm))
-
-#define PF_MD5_UPD_HTONL(st, elm, stor) do { \
- (stor) = htonl((st)->elm); \
- MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int32_t));\
-} while (0)
-
-#define PF_MD5_UPD_HTONS(st, elm, stor) do { \
- (stor) = htons((st)->elm); \
- MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int16_t));\
-} while (0)
-
-void
-pf_hash_rule_addr(MD5_CTX *ctx, struct pf_rule_addr *pfr)
-{
- PF_MD5_UPD(pfr, addr.type);
- switch (pfr->addr.type) {
- case PF_ADDR_DYNIFTL:
- PF_MD5_UPD(pfr, addr.v.ifname);
- PF_MD5_UPD(pfr, addr.iflags);
- break;
- case PF_ADDR_TABLE:
- PF_MD5_UPD(pfr, addr.v.tblname);
- break;
- case PF_ADDR_ADDRMASK:
- /* XXX ignore af? */
- PF_MD5_UPD(pfr, addr.v.a.addr.addr32);
- PF_MD5_UPD(pfr, addr.v.a.mask.addr32);
- break;
- case PF_ADDR_RTLABEL:
- PF_MD5_UPD(pfr, addr.v.rtlabelname);
- break;
- }
-
- PF_MD5_UPD(pfr, port[0]);
- PF_MD5_UPD(pfr, port[1]);
- PF_MD5_UPD(pfr, neg);
- PF_MD5_UPD(pfr, port_op);
-}
-
-void
-pf_hash_rule(MD5_CTX *ctx, struct pf_rule *rule)
-{
- u_int16_t x;
- u_int32_t y;
-
- pf_hash_rule_addr(ctx, &rule->src);
- pf_hash_rule_addr(ctx, &rule->dst);
- PF_MD5_UPD_STR(rule, label);
- PF_MD5_UPD_STR(rule, ifname);
- PF_MD5_UPD_STR(rule, match_tagname);
- PF_MD5_UPD_HTONS(rule, match_tag, x); /* dup? */
- PF_MD5_UPD_HTONL(rule, os_fingerprint, y);
- PF_MD5_UPD_HTONL(rule, prob, y);
- PF_MD5_UPD_HTONL(rule, uid.uid[0], y);
- PF_MD5_UPD_HTONL(rule, uid.uid[1], y);
- PF_MD5_UPD(rule, uid.op);
- PF_MD5_UPD_HTONL(rule, gid.gid[0], y);
- PF_MD5_UPD_HTONL(rule, gid.gid[1], y);
- PF_MD5_UPD(rule, gid.op);
- PF_MD5_UPD_HTONL(rule, rule_flag, y);
- PF_MD5_UPD(rule, action);
- PF_MD5_UPD(rule, direction);
- PF_MD5_UPD(rule, af);
- PF_MD5_UPD(rule, quick);
- PF_MD5_UPD(rule, ifnot);
- PF_MD5_UPD(rule, match_tag_not);
- PF_MD5_UPD(rule, natpass);
- PF_MD5_UPD(rule, keep_state);
- PF_MD5_UPD(rule, proto);
- PF_MD5_UPD(rule, type);
- PF_MD5_UPD(rule, code);
- PF_MD5_UPD(rule, flags);
- PF_MD5_UPD(rule, flagset);
- PF_MD5_UPD(rule, allow_opts);
- PF_MD5_UPD(rule, rt);
- PF_MD5_UPD(rule, tos);
-}
-
int
pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
{
struct pf_ruleset *rs;
- struct pf_rule *rule, **old_array;
+ struct pf_rule *rule;
struct pf_rulequeue *old_rules;
- int s, error;
- u_int32_t old_rcount;
+ int s;
if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
return (EINVAL);
@@ -796,97 +1268,46 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
ticket != rs->rules[rs_num].inactive.ticket)
return (EBUSY);
- /* Calculate checksum for the main ruleset */
- if (rs == &pf_main_ruleset) {
- error = pf_setup_pfsync_matching(rs);
- if (error != 0)
- return (error);
- }
-
/* Swap rules, keep the old. */
s = splsoftnet();
old_rules = rs->rules[rs_num].active.ptr;
- old_rcount = rs->rules[rs_num].active.rcount;
- old_array = rs->rules[rs_num].active.ptr_array;
-
rs->rules[rs_num].active.ptr =
rs->rules[rs_num].inactive.ptr;
- rs->rules[rs_num].active.ptr_array =
- rs->rules[rs_num].inactive.ptr_array;
- rs->rules[rs_num].active.rcount =
- rs->rules[rs_num].inactive.rcount;
rs->rules[rs_num].inactive.ptr = old_rules;
- rs->rules[rs_num].inactive.ptr_array = old_array;
- rs->rules[rs_num].inactive.rcount = old_rcount;
-
rs->rules[rs_num].active.ticket =
rs->rules[rs_num].inactive.ticket;
pf_calc_skip_steps(rs->rules[rs_num].active.ptr);
-
/* Purge the old rule list. */
while ((rule = TAILQ_FIRST(old_rules)) != NULL)
pf_rm_rule(old_rules, rule);
- if (rs->rules[rs_num].inactive.ptr_array)
- free(rs->rules[rs_num].inactive.ptr_array, M_TEMP);
- rs->rules[rs_num].inactive.ptr_array = NULL;
- rs->rules[rs_num].inactive.rcount = 0;
rs->rules[rs_num].inactive.open = 0;
pf_remove_if_empty_ruleset(rs);
splx(s);
return (0);
}
+#ifdef __FreeBSD__
int
-pf_setup_pfsync_matching(struct pf_ruleset *rs)
-{
- MD5_CTX ctx;
- struct pf_rule *rule;
- int rs_cnt;
- u_int8_t digest[PF_MD5_DIGEST_LENGTH];
-
- MD5Init(&ctx);
- for (rs_cnt = 0; rs_cnt < PF_RULESET_MAX; rs_cnt++) {
- /* XXX PF_RULESET_SCRUB as well? */
- if (rs_cnt == PF_RULESET_SCRUB)
- continue;
-
- if (rs->rules[rs_cnt].inactive.ptr_array)
- free(rs->rules[rs_cnt].inactive.ptr_array, M_TEMP);
- rs->rules[rs_cnt].inactive.ptr_array = NULL;
-
- if (rs->rules[rs_cnt].inactive.rcount) {
- rs->rules[rs_cnt].inactive.ptr_array =
- malloc(sizeof(caddr_t) *
- rs->rules[rs_cnt].inactive.rcount,
- M_TEMP, M_NOWAIT);
-
- if (!rs->rules[rs_cnt].inactive.ptr_array)
- return (ENOMEM);
- }
-
- TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr,
- entries) {
- pf_hash_rule(&ctx, rule);
- (rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule;
- }
- }
-
- MD5Final(digest, &ctx);
- memcpy(pf_status.pf_chksum, digest, sizeof(pf_status.pf_chksum));
- return (0);
-}
-
+pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
+#else
int
-pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
+pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
+#endif
{
struct pf_pooladdr *pa = NULL;
struct pf_pool *pool = NULL;
+#ifndef __FreeBSD__
int s;
+#endif
int error = 0;
/* XXX keep in sync with switch() below */
+#ifdef __FreeBSD__
+ if (securelevel_gt(td->td_ucred, 2))
+#else
if (securelevel > 1)
+#endif
switch (cmd) {
case DIOCGETRULES:
case DIOCGETRULE:
@@ -922,6 +1343,10 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCGETSRCNODES:
case DIOCCLRSRCNODES:
case DIOCIGETIFACES:
+ case DIOCICLRISTATS:
+#ifdef __FreeBSD__
+ case DIOCGIFSPEED:
+#endif
case DIOCSETIFFLAG:
case DIOCCLRIFFLAG:
break;
@@ -940,6 +1365,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
if (!(flags & FWRITE))
switch (cmd) {
case DIOCGETRULES:
+ case DIOCGETRULE:
case DIOCGETADDRS:
case DIOCGETADDR:
case DIOCGETSTATE:
@@ -952,7 +1378,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCGETQSTATS:
case DIOCGETRULESETS:
case DIOCGETRULESET:
- case DIOCNATLOOK:
case DIOCRGETTABLES:
case DIOCRGETTSTATS:
case DIOCRGETADDRS:
@@ -961,6 +1386,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCOSFPGET:
case DIOCGETSRCNODES:
case DIOCIGETIFACES:
+#ifdef __FreeBSD__
+ case DIOCGIFSPEED:
+#endif
break;
case DIOCRCLRTABLES:
case DIOCRADDTABLES:
@@ -972,31 +1400,34 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCRSETADDRS:
case DIOCRSETTFLAGS:
if (((struct pfioc_table *)addr)->pfrio_flags &
- PFR_FLAG_DUMMY) {
- flags |= FWRITE; /* need write lock for dummy */
+ PFR_FLAG_DUMMY)
break; /* dummy operation ok */
- }
return (EACCES);
- case DIOCGETRULE:
- if (((struct pfioc_rule *)addr)->action == PF_GET_CLR_CNTR)
- return (EACCES);
- break;
default:
return (EACCES);
}
- if (flags & FWRITE)
- rw_enter_write(&pf_consistency_lock);
- else
- rw_enter_read(&pf_consistency_lock);
-
+#ifdef __FreeBSD__
+ PF_LOCK();
+#else
s = splsoftnet();
+#endif
switch (cmd) {
case DIOCSTART:
if (pf_status.running)
error = EEXIST;
else {
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+ error = hook_pf();
+ PF_LOCK();
+ if (error) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: pfil registeration fail\n"));
+ break;
+ }
+#endif
pf_status.running = 1;
pf_status.since = time_second;
if (pf_status.stateid == 0) {
@@ -1012,6 +1443,16 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = ENOENT;
else {
pf_status.running = 0;
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+ error = dehook_pf();
+ PF_LOCK();
+ if (error) {
+ pf_status.running = 1;
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: pfil unregisteration failed\n"));
+ }
+#endif
pf_status.since = time_second;
DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
}
@@ -1040,10 +1481,20 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
+#ifdef __FreeBSD__
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("ticket: %d != [%d]%d\n", pr->ticket, rs_num,
+ ruleset->rules[rs_num].inactive.ticket));
+#endif
error = EBUSY;
break;
}
if (pr->pool_ticket != ticket_pabuf) {
+#ifdef __FreeBSD__
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pool_ticket: %d != %d\n", pr->pool_ticket,
+ ticket_pabuf));
+#endif
error = EBUSY;
break;
}
@@ -1053,8 +1504,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
bcopy(&pr->rule, rule, sizeof(struct pf_rule));
- rule->cuid = p->p_cred->p_ruid;
- rule->cpid = p->p_pid;
rule->anchor = NULL;
rule->kif = NULL;
TAILQ_INIT(&rule->rpool.list);
@@ -1083,18 +1532,14 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
else
rule->nr = 0;
if (rule->ifname[0]) {
- rule->kif = pfi_kif_get(rule->ifname);
+ rule->kif = pfi_attach_rule(rule->ifname);
if (rule->kif == NULL) {
pool_put(&pf_rule_pl, rule);
error = EINVAL;
break;
}
- pfi_kif_ref(rule->kif, PFI_KIF_REF_RULE);
}
- if (rule->rtableid > 0 && !rtable_exists(rule->rtableid))
- error = EBUSY;
-
#ifdef ALTQ
/* set queue IDs */
if (rule->qname[0] != 0) {
@@ -1117,10 +1562,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = EBUSY;
if (rule->rt && !rule->direction)
error = EINVAL;
-#if NPFLOG > 0
- if (rule->logif >= PFLOGIFS_MAX)
- error = EINVAL;
-#endif
if (pf_rtlabel_add(&rule->src.addr) ||
pf_rtlabel_add(&rule->dst.addr))
error = EBUSY;
@@ -1159,11 +1600,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
- rule->evaluations = rule->packets[0] = rule->packets[1] =
- rule->bytes[0] = rule->bytes[1] = 0;
+ rule->evaluations = rule->packets = rule->bytes = 0;
TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
rule, entries);
- ruleset->rules[rs_num].inactive.rcount++;
break;
}
@@ -1239,12 +1678,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
else
pr->rule.skip[i].nr =
rule->skip[i].ptr->nr;
-
- if (pr->action == PF_GET_CLR_CNTR) {
- rule->evaluations = 0;
- rule->packets[0] = rule->packets[1] = 0;
- rule->bytes[0] = rule->bytes[1] = 0;
- }
break;
}
@@ -1300,8 +1733,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
bcopy(&pcr->rule, newrule, sizeof(struct pf_rule));
- newrule->cuid = p->p_cred->p_ruid;
- newrule->cpid = p->p_pid;
TAILQ_INIT(&newrule->rpool.list);
/* initialize refcounting */
newrule->states = 0;
@@ -1321,20 +1752,15 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
#endif /* INET6 */
if (newrule->ifname[0]) {
- newrule->kif = pfi_kif_get(newrule->ifname);
+ newrule->kif = pfi_attach_rule(newrule->ifname);
if (newrule->kif == NULL) {
pool_put(&pf_rule_pl, newrule);
error = EINVAL;
break;
}
- pfi_kif_ref(newrule->kif, PFI_KIF_REF_RULE);
} else
newrule->kif = NULL;
- if (newrule->rtableid > 0 &&
- !rtable_exists(newrule->rtableid))
- error = EBUSY;
-
#ifdef ALTQ
/* set queue IDs */
if (newrule->qname[0] != 0) {
@@ -1400,9 +1826,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list);
- newrule->evaluations = 0;
- newrule->packets[0] = newrule->packets[1] = 0;
- newrule->bytes[0] = newrule->bytes[1] = 0;
+ newrule->evaluations = newrule->packets = 0;
+ newrule->bytes = 0;
}
pf_empty_pool(&pf_pabuf);
@@ -1425,10 +1850,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
}
- if (pcr->action == PF_CHANGE_REMOVE) {
+ if (pcr->action == PF_CHANGE_REMOVE)
pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule);
- ruleset->rules[rs_num].active.rcount--;
- } else {
+ else {
if (oldrule == NULL)
TAILQ_INSERT_TAIL(
ruleset->rules[rs_num].active.ptr,
@@ -1440,7 +1864,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
TAILQ_INSERT_AFTER(
ruleset->rules[rs_num].active.ptr,
oldrule, newrule, entries);
- ruleset->rules[rs_num].active.rcount++;
}
nr = 0;
@@ -1457,24 +1880,23 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
case DIOCCLRSTATES: {
- struct pf_state *state, *nexts;
+ struct pf_state *state;
struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
int killed = 0;
- for (state = RB_MIN(pf_state_tree_id, &tree_id); state;
- state = nexts) {
- nexts = RB_NEXT(pf_state_tree_id, &tree_id, state);
-
+ RB_FOREACH(state, pf_state_tree_id, &tree_id) {
if (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname,
state->u.s.kif->pfik_name)) {
+ state->timeout = PFTM_PURGE;
#if NPFSYNC
/* don't send out individual delete messages */
state->sync_flags = PFSTATE_NOSYNC;
#endif
- pf_unlink_state(state);
killed++;
}
}
+ pf_purge_expired_states();
+ pf_status.states = 0;
psk->psk_af = killed;
#if NPFSYNC
pfsync_clear_states(pf_status.hostid, psk->psk_ifname);
@@ -1483,52 +1905,37 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
case DIOCKILLSTATES: {
- struct pf_state *state, *nexts;
- struct pf_state_host *src, *dst;
+ struct pf_state *state;
struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
int killed = 0;
- for (state = RB_MIN(pf_state_tree_id, &tree_id); state;
- state = nexts) {
- nexts = RB_NEXT(pf_state_tree_id, &tree_id, state);
-
- if (state->direction == PF_OUT) {
- src = &state->lan;
- dst = &state->ext;
- } else {
- src = &state->ext;
- dst = &state->lan;
- }
+ RB_FOREACH(state, pf_state_tree_id, &tree_id) {
if ((!psk->psk_af || state->af == psk->psk_af)
&& (!psk->psk_proto || psk->psk_proto ==
state->proto) &&
PF_MATCHA(psk->psk_src.neg,
&psk->psk_src.addr.v.a.addr,
&psk->psk_src.addr.v.a.mask,
- &src->addr, state->af) &&
+ &state->lan.addr, state->af) &&
PF_MATCHA(psk->psk_dst.neg,
&psk->psk_dst.addr.v.a.addr,
&psk->psk_dst.addr.v.a.mask,
- &dst->addr, state->af) &&
+ &state->ext.addr, state->af) &&
(psk->psk_src.port_op == 0 ||
pf_match_port(psk->psk_src.port_op,
psk->psk_src.port[0], psk->psk_src.port[1],
- src->port)) &&
+ state->lan.port)) &&
(psk->psk_dst.port_op == 0 ||
pf_match_port(psk->psk_dst.port_op,
psk->psk_dst.port[0], psk->psk_dst.port[1],
- dst->port)) &&
+ state->ext.port)) &&
(!psk->psk_ifname[0] || !strcmp(psk->psk_ifname,
state->u.s.kif->pfik_name))) {
-#if NPFSYNC > 0
- /* send immediate delete of state */
- pfsync_delete_state(state);
- state->sync_flags |= PFSTATE_NOSYNC;
-#endif
- pf_unlink_state(state);
+ state->timeout = PFTM_PURGE;
killed++;
}
}
+ pf_purge_expired_states();
psk->psk_af = killed;
break;
}
@@ -1548,7 +1955,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = ENOMEM;
break;
}
- kif = pfi_kif_get(ps->state.u.ifname);
+ kif = pfi_lookup_create(ps->state.u.ifname);
if (kif == NULL) {
pool_put(&pf_state_pl, state);
error = ENOENT;
@@ -1566,7 +1973,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
state->bytes[0] = state->bytes[1] = 0;
if (pf_insert_state(kif, state)) {
- pfi_kif_unref(kif, PFI_KIF_REF_NONE);
+ pfi_maybe_destroy(kif);
pool_put(&pf_state_pl, state);
error = ENOMEM;
}
@@ -1577,7 +1984,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
struct pfioc_state *ps = (struct pfioc_state *)addr;
struct pf_state *state;
u_int32_t nr;
- int secs;
nr = 0;
RB_FOREACH(state, pf_state_tree_id, &tree_id) {
@@ -1589,19 +1995,15 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = EBUSY;
break;
}
- secs = time_second;
- bcopy(state, &ps->state, sizeof(ps->state));
- strlcpy(ps->state.u.ifname, state->u.s.kif->pfik_name,
- sizeof(ps->state.u.ifname));
+ bcopy(state, &ps->state, sizeof(struct pf_state));
ps->state.rule.nr = state->rule.ptr->nr;
ps->state.nat_rule.nr = (state->nat_rule.ptr == NULL) ?
-1 : state->nat_rule.ptr->nr;
ps->state.anchor.nr = (state->anchor.ptr == NULL) ?
-1 : state->anchor.ptr->nr;
- ps->state.creation = secs - ps->state.creation;
ps->state.expire = pf_state_expires(state);
- if (ps->state.expire > secs)
- ps->state.expire -= secs;
+ if (ps->state.expire > time_second)
+ ps->state.expire -= time_second;
else
ps->state.expire = 0;
break;
@@ -1610,57 +2012,52 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCGETSTATES: {
struct pfioc_states *ps = (struct pfioc_states *)addr;
struct pf_state *state;
- struct pf_state *p, *pstore;
+ struct pf_state *p, pstore;
+ struct pfi_kif *kif;
u_int32_t nr = 0;
int space = ps->ps_len;
if (space == 0) {
- nr = pf_status.states;
+ TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states)
+ nr += kif->pfik_states;
ps->ps_len = sizeof(struct pf_state) * nr;
break;
}
- pstore = malloc(sizeof(*pstore), M_TEMP, M_WAITOK);
-
p = ps->ps_states;
-
- state = TAILQ_FIRST(&state_list);
- while (state) {
- if (state->timeout != PFTM_UNLINKED) {
+ TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states)
+ RB_FOREACH(state, pf_state_tree_ext_gwy,
+ &kif->pfik_ext_gwy) {
int secs = time_second;
if ((nr+1) * sizeof(*p) > (unsigned)ps->ps_len)
break;
- bcopy(state, pstore, sizeof(*pstore));
- strlcpy(pstore->u.ifname,
- state->u.s.kif->pfik_name,
- sizeof(pstore->u.ifname));
- pstore->rule.nr = state->rule.ptr->nr;
- pstore->nat_rule.nr = (state->nat_rule.ptr ==
+ bcopy(state, &pstore, sizeof(pstore));
+ strlcpy(pstore.u.ifname, kif->pfik_name,
+ sizeof(pstore.u.ifname));
+ pstore.rule.nr = state->rule.ptr->nr;
+ pstore.nat_rule.nr = (state->nat_rule.ptr ==
NULL) ? -1 : state->nat_rule.ptr->nr;
- pstore->anchor.nr = (state->anchor.ptr ==
+ pstore.anchor.nr = (state->anchor.ptr ==
NULL) ? -1 : state->anchor.ptr->nr;
- pstore->creation = secs - pstore->creation;
- pstore->expire = pf_state_expires(state);
- if (pstore->expire > secs)
- pstore->expire -= secs;
+ pstore.creation = secs - pstore.creation;
+ pstore.expire = pf_state_expires(state);
+ if (pstore.expire > secs)
+ pstore.expire -= secs;
else
- pstore->expire = 0;
- error = copyout(pstore, p, sizeof(*p));
- if (error) {
- free(pstore, M_TEMP);
+ pstore.expire = 0;
+#ifdef __FreeBSD__
+ PF_COPYOUT(&pstore, p, sizeof(*p), error);
+#else
+ error = copyout(&pstore, p, sizeof(*p));
+#endif
+ if (error)
goto fail;
- }
p++;
nr++;
}
- state = TAILQ_NEXT(state, u.s.entry_list);
- }
-
ps->ps_len = sizeof(struct pf_state) * nr;
-
- free(pstore, M_TEMP);
break;
}
@@ -1690,16 +2087,16 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
bzero(pf_status.counters, sizeof(pf_status.counters));
bzero(pf_status.fcounters, sizeof(pf_status.fcounters));
bzero(pf_status.scounters, sizeof(pf_status.scounters));
- pf_status.since = time_second;
if (*pf_status.ifname)
- pfi_clr_istats(pf_status.ifname);
+ pfi_clr_istats(pf_status.ifname, NULL,
+ PFI_FLAG_INSTANCE);
break;
}
case DIOCNATLOOK: {
struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr;
struct pf_state *state;
- struct pf_state_cmp key;
+ struct pf_state key;
int m = 0, direction = pnl->direction;
key.af = pnl->af;
@@ -1708,9 +2105,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
if (!pnl->proto ||
PF_AZERO(&pnl->saddr, pnl->af) ||
PF_AZERO(&pnl->daddr, pnl->af) ||
- ((pnl->proto == IPPROTO_TCP ||
- pnl->proto == IPPROTO_UDP) &&
- (!pnl->dport || !pnl->sport)))
+ !pnl->dport || !pnl->sport)
error = EINVAL;
else {
/*
@@ -1766,11 +2161,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
goto fail;
}
old = pf_default_rule.timeout[pt->timeout];
- if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0)
- pt->seconds = 1;
pf_default_rule.timeout[pt->timeout] = pt->seconds;
- if (pt->timeout == PFTM_INTERVAL && pt->seconds < old)
- wakeup(pf_purge_thread);
pt->seconds = old;
break;
}
@@ -1806,11 +2197,15 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = EINVAL;
goto fail;
}
+#ifdef __FreeBSD__
+ uma_zone_set_max(pf_pool_limits[pl->index].pp, pl->limit);
+#else
if (pool_sethardlimit(pf_pool_limits[pl->index].pp,
pl->limit, NULL, 0) != 0) {
error = EBUSY;
goto fail;
}
+#endif
old_limit = pf_pool_limits[pl->index].limit;
pf_pool_limits[pl->index].limit = pl->limit;
pl->limit = old_limit;
@@ -1825,18 +2220,35 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
case DIOCCLRRULECTRS: {
- /* obsoleted by DIOCGETRULE with action=PF_GET_CLR_CNTR */
struct pf_ruleset *ruleset = &pf_main_ruleset;
struct pf_rule *rule;
TAILQ_FOREACH(rule,
- ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) {
- rule->evaluations = 0;
- rule->packets[0] = rule->packets[1] = 0;
- rule->bytes[0] = rule->bytes[1] = 0;
- }
+ ruleset->rules[PF_RULESET_FILTER].active.ptr, entries)
+ rule->evaluations = rule->packets =
+ rule->bytes = 0;
+ break;
+ }
+
+#ifdef __FreeBSD__
+ case DIOCGIFSPEED: {
+ struct pf_ifspeed *psp = (struct pf_ifspeed *)addr;
+ struct pf_ifspeed ps;
+ struct ifnet *ifp;
+
+ if (psp->ifname[0] != 0) {
+ /* Can we completely trust user-land? */
+ strlcpy(ps.ifname, psp->ifname, IFNAMSIZ);
+ ifp = ifunit(ps.ifname);
+ if (ifp != NULL)
+ psp->baudrate = ifp->if_baudrate;
+ else
+ error = EINVAL;
+ } else
+ error = EINVAL;
break;
}
+#endif /* __FreeBSD__ */
#ifdef ALTQ
case DIOCSTARTALTQ: {
@@ -1907,7 +2319,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
}
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
error = altq_add(altq);
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
if (error) {
pool_put(&pf_altq_pl, altq);
break;
@@ -1978,7 +2396,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = EBUSY;
break;
}
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
error = altq_getqstats(altq, pq->buf, &nbytes);
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
if (error == 0) {
pq->scheduler = altq->scheduler;
pq->nbytes = nbytes;
@@ -2027,17 +2451,16 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr));
if (pa->ifname[0]) {
- pa->kif = pfi_kif_get(pa->ifname);
+ pa->kif = pfi_attach_rule(pa->ifname);
if (pa->kif == NULL) {
pool_put(&pf_pooladdr_pl, pa);
error = EINVAL;
break;
}
- pfi_kif_ref(pa->kif, PFI_KIF_REF_RULE);
}
if (pfi_dynaddr_setup(&pa->addr, pp->af)) {
pfi_dynaddr_remove(&pa->addr);
- pfi_kif_unref(pa->kif, PFI_KIF_REF_RULE);
+ pfi_detach_rule(pa->kif);
pool_put(&pf_pooladdr_pl, pa);
error = EINVAL;
break;
@@ -2137,19 +2560,18 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
#endif /* INET6 */
if (newpa->ifname[0]) {
- newpa->kif = pfi_kif_get(newpa->ifname);
+ newpa->kif = pfi_attach_rule(newpa->ifname);
if (newpa->kif == NULL) {
pool_put(&pf_pooladdr_pl, newpa);
error = EINVAL;
break;
}
- pfi_kif_ref(newpa->kif, PFI_KIF_REF_RULE);
} else
newpa->kif = NULL;
if (pfi_dynaddr_setup(&newpa->addr, pca->af) ||
pf_tbladdr_setup(ruleset, &newpa->addr)) {
pfi_dynaddr_remove(&newpa->addr);
- pfi_kif_unref(newpa->kif, PFI_KIF_REF_RULE);
+ pfi_detach_rule(newpa->kif);
pool_put(&pf_pooladdr_pl, newpa);
error = EINVAL;
break;
@@ -2178,7 +2600,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
TAILQ_REMOVE(&pool->list, oldpa, entries);
pfi_dynaddr_remove(&oldpa->addr);
pf_tbladdr_remove(&oldpa->addr);
- pfi_kif_unref(oldpa->kif, PFI_KIF_REF_RULE);
+ pfi_detach_rule(oldpa->kif);
pool_put(&pf_pooladdr_pl, oldpa);
} else {
if (oldpa == NULL)
@@ -2388,7 +2810,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer,
io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd,
&io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags |
- PFR_FLAG_USERIOCTL, 0);
+ PFR_FLAG_USERIOCTL);
break;
}
@@ -2468,203 +2890,171 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
case DIOCXBEGIN: {
- struct pfioc_trans *io = (struct pfioc_trans *)addr;
- struct pfioc_trans_e *ioe;
- struct pfr_table *table;
- int i;
+ struct pfioc_trans *io = (struct pfioc_trans *)
+ addr;
+ static struct pfioc_trans_e ioe;
+ static struct pfr_table table;
+ int i;
- if (io->esize != sizeof(*ioe)) {
+ if (io->esize != sizeof(ioe)) {
error = ENODEV;
goto fail;
}
- ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe),
- M_TEMP, M_WAITOK);
- table = (struct pfr_table *)malloc(sizeof(*table),
- M_TEMP, M_WAITOK);
for (i = 0; i < io->size; i++) {
- if (copyin(io->array+i, ioe, sizeof(*ioe))) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
+#ifdef __FreeBSD__
+ PF_COPYIN(io->array+i, &ioe, sizeof(ioe), error);
+ if (error) {
+#else
+ if (copyin(io->array+i, &ioe, sizeof(ioe))) {
+#endif
error = EFAULT;
goto fail;
}
- switch (ioe->rs_num) {
+ switch (ioe.rs_num) {
#ifdef ALTQ
case PF_RULESET_ALTQ:
- if (ioe->anchor[0]) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
+ if (ioe.anchor[0]) {
error = EINVAL;
goto fail;
}
- if ((error = pf_begin_altq(&ioe->ticket))) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
+ if ((error = pf_begin_altq(&ioe.ticket)))
goto fail;
- }
break;
#endif /* ALTQ */
case PF_RULESET_TABLE:
- bzero(table, sizeof(*table));
- strlcpy(table->pfrt_anchor, ioe->anchor,
- sizeof(table->pfrt_anchor));
- if ((error = pfr_ina_begin(table,
- &ioe->ticket, NULL, 0))) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
+ bzero(&table, sizeof(table));
+ strlcpy(table.pfrt_anchor, ioe.anchor,
+ sizeof(table.pfrt_anchor));
+ if ((error = pfr_ina_begin(&table,
+ &ioe.ticket, NULL, 0)))
goto fail;
- }
break;
default:
- if ((error = pf_begin_rules(&ioe->ticket,
- ioe->rs_num, ioe->anchor))) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
+ if ((error = pf_begin_rules(&ioe.ticket,
+ ioe.rs_num, ioe.anchor)))
goto fail;
- }
break;
}
- if (copyout(ioe, io->array+i, sizeof(io->array[i]))) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
+#ifdef __FreeBSD__
+ PF_COPYOUT(&ioe, io->array+i, sizeof(io->array[i]),
+ error);
+ if (error) {
+#else
+ if (copyout(&ioe, io->array+i, sizeof(io->array[i]))) {
+#endif
error = EFAULT;
goto fail;
}
}
- free(table, M_TEMP);
- free(ioe, M_TEMP);
break;
}
case DIOCXROLLBACK: {
- struct pfioc_trans *io = (struct pfioc_trans *)addr;
- struct pfioc_trans_e *ioe;
- struct pfr_table *table;
- int i;
+ struct pfioc_trans *io = (struct pfioc_trans *)
+ addr;
+ static struct pfioc_trans_e ioe;
+ static struct pfr_table table;
+ int i;
- if (io->esize != sizeof(*ioe)) {
+ if (io->esize != sizeof(ioe)) {
error = ENODEV;
goto fail;
}
- ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe),
- M_TEMP, M_WAITOK);
- table = (struct pfr_table *)malloc(sizeof(*table),
- M_TEMP, M_WAITOK);
for (i = 0; i < io->size; i++) {
- if (copyin(io->array+i, ioe, sizeof(*ioe))) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
+#ifdef __FreeBSD__
+ PF_COPYIN(io->array+i, &ioe, sizeof(ioe), error);
+ if (error) {
+#else
+ if (copyin(io->array+i, &ioe, sizeof(ioe))) {
+#endif
error = EFAULT;
goto fail;
}
- switch (ioe->rs_num) {
+ switch (ioe.rs_num) {
#ifdef ALTQ
case PF_RULESET_ALTQ:
- if (ioe->anchor[0]) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
+ if (ioe.anchor[0]) {
error = EINVAL;
goto fail;
}
- if ((error = pf_rollback_altq(ioe->ticket))) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
+ if ((error = pf_rollback_altq(ioe.ticket)))
goto fail; /* really bad */
- }
break;
#endif /* ALTQ */
case PF_RULESET_TABLE:
- bzero(table, sizeof(*table));
- strlcpy(table->pfrt_anchor, ioe->anchor,
- sizeof(table->pfrt_anchor));
- if ((error = pfr_ina_rollback(table,
- ioe->ticket, NULL, 0))) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
+ bzero(&table, sizeof(table));
+ strlcpy(table.pfrt_anchor, ioe.anchor,
+ sizeof(table.pfrt_anchor));
+ if ((error = pfr_ina_rollback(&table,
+ ioe.ticket, NULL, 0)))
goto fail; /* really bad */
- }
break;
default:
- if ((error = pf_rollback_rules(ioe->ticket,
- ioe->rs_num, ioe->anchor))) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
+ if ((error = pf_rollback_rules(ioe.ticket,
+ ioe.rs_num, ioe.anchor)))
goto fail; /* really bad */
- }
break;
}
}
- free(table, M_TEMP);
- free(ioe, M_TEMP);
break;
}
case DIOCXCOMMIT: {
- struct pfioc_trans *io = (struct pfioc_trans *)addr;
- struct pfioc_trans_e *ioe;
- struct pfr_table *table;
- struct pf_ruleset *rs;
- int i;
-
- if (io->esize != sizeof(*ioe)) {
+ struct pfioc_trans *io = (struct pfioc_trans *)
+ addr;
+ static struct pfioc_trans_e ioe;
+ static struct pfr_table table;
+ struct pf_ruleset *rs;
+ int i;
+
+ if (io->esize != sizeof(ioe)) {
error = ENODEV;
goto fail;
}
- ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe),
- M_TEMP, M_WAITOK);
- table = (struct pfr_table *)malloc(sizeof(*table),
- M_TEMP, M_WAITOK);
/* first makes sure everything will succeed */
for (i = 0; i < io->size; i++) {
- if (copyin(io->array+i, ioe, sizeof(*ioe))) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
+#ifdef __FreeBSD__
+ PF_COPYIN(io->array+i, &ioe, sizeof(ioe), error);
+ if (error) {
+#else
+ if (copyin(io->array+i, &ioe, sizeof(ioe))) {
+#endif
error = EFAULT;
goto fail;
}
- switch (ioe->rs_num) {
+ switch (ioe.rs_num) {
#ifdef ALTQ
case PF_RULESET_ALTQ:
- if (ioe->anchor[0]) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
+ if (ioe.anchor[0]) {
error = EINVAL;
goto fail;
}
- if (!altqs_inactive_open || ioe->ticket !=
+ if (!altqs_inactive_open || ioe.ticket !=
ticket_altqs_inactive) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
error = EBUSY;
goto fail;
}
break;
#endif /* ALTQ */
case PF_RULESET_TABLE:
- rs = pf_find_ruleset(ioe->anchor);
- if (rs == NULL || !rs->topen || ioe->ticket !=
+ rs = pf_find_ruleset(ioe.anchor);
+ if (rs == NULL || !rs->topen || ioe.ticket !=
rs->tticket) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
error = EBUSY;
goto fail;
}
break;
default:
- if (ioe->rs_num < 0 || ioe->rs_num >=
+ if (ioe.rs_num < 0 || ioe.rs_num >=
PF_RULESET_MAX) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
error = EINVAL;
goto fail;
}
- rs = pf_find_ruleset(ioe->anchor);
+ rs = pf_find_ruleset(ioe.anchor);
if (rs == NULL ||
- !rs->rules[ioe->rs_num].inactive.open ||
- rs->rules[ioe->rs_num].inactive.ticket !=
- ioe->ticket) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
+ !rs->rules[ioe.rs_num].inactive.open ||
+ rs->rules[ioe.rs_num].inactive.ticket !=
+ ioe.ticket) {
error = EBUSY;
goto fail;
}
@@ -2673,51 +3063,44 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
/* now do the commit - no errors should happen here */
for (i = 0; i < io->size; i++) {
- if (copyin(io->array+i, ioe, sizeof(*ioe))) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
+#ifdef __FreeBSD__
+ PF_COPYIN(io->array+i, &ioe, sizeof(ioe), error);
+ if (error) {
+#else
+ if (copyin(io->array+i, &ioe, sizeof(ioe))) {
+#endif
error = EFAULT;
goto fail;
}
- switch (ioe->rs_num) {
+ switch (ioe.rs_num) {
#ifdef ALTQ
case PF_RULESET_ALTQ:
- if ((error = pf_commit_altq(ioe->ticket))) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
+ if ((error = pf_commit_altq(ioe.ticket)))
goto fail; /* really bad */
- }
break;
#endif /* ALTQ */
case PF_RULESET_TABLE:
- bzero(table, sizeof(*table));
- strlcpy(table->pfrt_anchor, ioe->anchor,
- sizeof(table->pfrt_anchor));
- if ((error = pfr_ina_commit(table, ioe->ticket,
- NULL, NULL, 0))) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
+ bzero(&table, sizeof(table));
+ strlcpy(table.pfrt_anchor, ioe.anchor,
+ sizeof(table.pfrt_anchor));
+ if ((error = pfr_ina_commit(&table, ioe.ticket,
+ NULL, NULL, 0)))
goto fail; /* really bad */
- }
break;
default:
- if ((error = pf_commit_rules(ioe->ticket,
- ioe->rs_num, ioe->anchor))) {
- free(table, M_TEMP);
- free(ioe, M_TEMP);
+ if ((error = pf_commit_rules(ioe.ticket,
+ ioe.rs_num, ioe.anchor)))
goto fail; /* really bad */
- }
break;
}
}
- free(table, M_TEMP);
- free(ioe, M_TEMP);
break;
}
case DIOCGETSRCNODES: {
struct pfioc_src_nodes *psn = (struct pfioc_src_nodes *)addr;
- struct pf_src_node *n, *p, *pstore;
+ struct pf_src_node *n;
+ struct pf_src_node *p, pstore;
u_int32_t nr = 0;
int space = psn->psn_len;
@@ -2728,8 +3111,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
- pstore = malloc(sizeof(*pstore), M_TEMP, M_WAITOK);
-
p = psn->psn_src_nodes;
RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
int secs = time_second, diff;
@@ -2737,35 +3118,35 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
if ((nr + 1) * sizeof(*p) > (unsigned)psn->psn_len)
break;
- bcopy(n, pstore, sizeof(*pstore));
+ bcopy(n, &pstore, sizeof(pstore));
if (n->rule.ptr != NULL)
- pstore->rule.nr = n->rule.ptr->nr;
- pstore->creation = secs - pstore->creation;
- if (pstore->expire > secs)
- pstore->expire -= secs;
+ pstore.rule.nr = n->rule.ptr->nr;
+ pstore.creation = secs - pstore.creation;
+ if (pstore.expire > secs)
+ pstore.expire -= secs;
else
- pstore->expire = 0;
+ pstore.expire = 0;
/* adjust the connection rate estimate */
diff = secs - n->conn_rate.last;
if (diff >= n->conn_rate.seconds)
- pstore->conn_rate.count = 0;
+ pstore.conn_rate.count = 0;
else
- pstore->conn_rate.count -=
+ pstore.conn_rate.count -=
n->conn_rate.count * diff /
n->conn_rate.seconds;
- error = copyout(pstore, p, sizeof(*p));
- if (error) {
- free(pstore, M_TEMP);
+#ifdef __FreeBSD__
+ PF_COPYOUT(&pstore, p, sizeof(*p), error);
+#else
+ error = copyout(&pstore, p, sizeof(*p));
+#endif
+ if (error)
goto fail;
- }
p++;
nr++;
}
psn->psn_len = sizeof(struct pf_src_node) * nr;
-
- free(pstore, M_TEMP);
break;
}
@@ -2781,50 +3162,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
n->expire = 1;
n->states = 0;
}
- pf_purge_expired_src_nodes(1);
+ pf_purge_expired_src_nodes();
pf_status.src_nodes = 0;
break;
}
- case DIOCKILLSRCNODES: {
- struct pf_src_node *sn;
- struct pf_state *s;
- struct pfioc_src_node_kill *psnk = \
- (struct pfioc_src_node_kill *) addr;
- int killed = 0;
-
- RB_FOREACH(sn, pf_src_tree, &tree_src_tracking) {
- if (PF_MATCHA(psnk->psnk_src.neg, \
- &psnk->psnk_src.addr.v.a.addr, \
- &psnk->psnk_src.addr.v.a.mask, \
- &sn->addr, sn->af) &&
- PF_MATCHA(psnk->psnk_dst.neg, \
- &psnk->psnk_dst.addr.v.a.addr, \
- &psnk->psnk_dst.addr.v.a.mask, \
- &sn->raddr, sn->af)) {
- /* Handle state to src_node linkage */
- if (sn->states != 0) {
- RB_FOREACH(s, pf_state_tree_id,
- &tree_id) {
- if (s->src_node == sn)
- s->src_node = NULL;
- if (s->nat_src_node == sn)
- s->nat_src_node = NULL;
- }
- sn->states = 0;
- }
- sn->expire = 1;
- killed++;
- }
- }
-
- if (killed > 0)
- pf_purge_expired_src_nodes(1);
-
- psnk->psnk_af = killed;
- break;
- }
-
case DIOCSETHOSTID: {
u_int32_t *hostid = (u_int32_t *)addr;
@@ -2842,12 +3184,20 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCIGETIFACES: {
struct pfioc_iface *io = (struct pfioc_iface *)addr;
- if (io->pfiio_esize != sizeof(struct pfi_kif)) {
+ if (io->pfiio_esize != sizeof(struct pfi_if)) {
error = ENODEV;
break;
}
error = pfi_get_ifaces(io->pfiio_name, io->pfiio_buffer,
- &io->pfiio_size);
+ &io->pfiio_size, io->pfiio_flags);
+ break;
+ }
+
+ case DIOCICLRISTATS: {
+ struct pfioc_iface *io = (struct pfioc_iface *)addr;
+
+ error = pfi_clr_istats(io->pfiio_name, &io->pfiio_nzero,
+ io->pfiio_flags);
break;
}
@@ -2870,10 +3220,405 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
fail:
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#else
splx(s);
- if (flags & FWRITE)
- rw_exit_write(&pf_consistency_lock);
- else
- rw_exit_read(&pf_consistency_lock);
+#endif
return (error);
}
+
+#ifdef __FreeBSD__
+/*
+ * XXX - Check for version missmatch!!!
+ */
+static void
+pf_clear_states(void)
+{
+ struct pf_state *state;
+
+ RB_FOREACH(state, pf_state_tree_id, &tree_id) {
+ state->timeout = PFTM_PURGE;
+#if NPFSYNC
+ /* don't send out individual delete messages */
+ state->sync_flags = PFSTATE_NOSYNC;
+#endif
+ }
+ pf_purge_expired_states();
+ pf_status.states = 0;
+#if 0 /* NPFSYNC */
+/*
+ * XXX This is called on module unload, we do not want to sync that over? */
+ */
+ pfsync_clear_states(pf_status.hostid, psk->psk_ifname);
+#endif
+}
+
+static int
+pf_clear_tables(void)
+{
+ struct pfioc_table io;
+ int error;
+
+ bzero(&io, sizeof(io));
+
+ error = pfr_clr_tables(&io.pfrio_table, &io.pfrio_ndel,
+ io.pfrio_flags);
+
+ return (error);
+}
+
+static void
+pf_clear_srcnodes(void)
+{
+ struct pf_src_node *n;
+ struct pf_state *state;
+
+ RB_FOREACH(state, pf_state_tree_id, &tree_id) {
+ state->src_node = NULL;
+ state->nat_src_node = NULL;
+ }
+ RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
+ n->expire = 1;
+ n->states = 0;
+ }
+ pf_purge_expired_src_nodes();
+ pf_status.src_nodes = 0;
+}
+/*
+ * XXX - Check for version missmatch!!!
+ */
+
+/*
+ * Duplicate pfctl -Fa operation to get rid of as much as we can.
+ */
+static int
+shutdown_pf(void)
+{
+ int error = 0;
+ u_int32_t t[5];
+ char nn = '\0';
+
+ callout_stop(&pf_expire_to);
+
+ pf_status.running = 0;
+ do {
+ if ((error = pf_begin_rules(&t[0], PF_RULESET_SCRUB, &nn))
+ != 0) {
+ DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: SCRUB\n"));
+ break;
+ }
+ if ((error = pf_begin_rules(&t[1], PF_RULESET_FILTER, &nn))
+ != 0) {
+ DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: FILTER\n"));
+ break; /* XXX: rollback? */
+ }
+ if ((error = pf_begin_rules(&t[2], PF_RULESET_NAT, &nn))
+ != 0) {
+ DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: NAT\n"));
+ break; /* XXX: rollback? */
+ }
+ if ((error = pf_begin_rules(&t[3], PF_RULESET_BINAT, &nn))
+ != 0) {
+ DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: BINAT\n"));
+ break; /* XXX: rollback? */
+ }
+ if ((error = pf_begin_rules(&t[4], PF_RULESET_RDR, &nn))
+ != 0) {
+ DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: RDR\n"));
+ break; /* XXX: rollback? */
+ }
+
+ /* XXX: these should always succeed here */
+ pf_commit_rules(t[0], PF_RULESET_SCRUB, &nn);
+ pf_commit_rules(t[1], PF_RULESET_FILTER, &nn);
+ pf_commit_rules(t[2], PF_RULESET_NAT, &nn);
+ pf_commit_rules(t[3], PF_RULESET_BINAT, &nn);
+ pf_commit_rules(t[4], PF_RULESET_RDR, &nn);
+
+ if ((error = pf_clear_tables()) != 0)
+ break;
+
+#ifdef ALTQ
+ if ((error = pf_begin_altq(&t[0])) != 0) {
+ DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: ALTQ\n"));
+ break;
+ }
+ pf_commit_altq(t[0]);
+#endif
+
+ pf_clear_states();
+
+ pf_clear_srcnodes();
+
+ /* status does not use malloced mem so no need to cleanup */
+ /* fingerprints and interfaces have thier own cleanup code */
+ } while(0);
+
+ return (error);
+}
+
+static int
+pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
+ struct inpcb *inp)
+{
+ /*
+ * XXX Wed Jul 9 22:03:16 2003 UTC
+ * OpenBSD has changed its byte ordering convention on ip_len/ip_off
+ * in network stack. OpenBSD's network stack have converted
+ * ip_len/ip_off to host byte order frist as FreeBSD.
+ * Now this is not true anymore , so we should convert back to network
+ * byte order.
+ */
+ struct ip *h = NULL;
+ int chk;
+
+ if ((*m)->m_pkthdr.len >= (int)sizeof(struct ip)) {
+ /* if m_pkthdr.len is less than ip header, pf will handle. */
+ h = mtod(*m, struct ip *);
+ HTONS(h->ip_len);
+ HTONS(h->ip_off);
+ }
+ chk = pf_test(PF_IN, ifp, m, NULL, inp);
+ if (chk && *m) {
+ m_freem(*m);
+ *m = NULL;
+ }
+ if (*m != NULL) {
+ /* pf_test can change ip header location */
+ h = mtod(*m, struct ip *);
+ NTOHS(h->ip_len);
+ NTOHS(h->ip_off);
+ }
+ return chk;
+}
+
+static int
+pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
+ struct inpcb *inp)
+{
+ /*
+ * XXX Wed Jul 9 22:03:16 2003 UTC
+ * OpenBSD has changed its byte ordering convention on ip_len/ip_off
+ * in network stack. OpenBSD's network stack have converted
+ * ip_len/ip_off to host byte order frist as FreeBSD.
+ * Now this is not true anymore , so we should convert back to network
+ * byte order.
+ */
+ struct ip *h = NULL;
+ int chk;
+
+ /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */
+ if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
+ in_delayed_cksum(*m);
+ (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
+ }
+ if ((*m)->m_pkthdr.len >= (int)sizeof(*h)) {
+ /* if m_pkthdr.len is less than ip header, pf will handle. */
+ h = mtod(*m, struct ip *);
+ HTONS(h->ip_len);
+ HTONS(h->ip_off);
+ }
+ chk = pf_test(PF_OUT, ifp, m, NULL, inp);
+ if (chk && *m) {
+ m_freem(*m);
+ *m = NULL;
+ }
+ if (*m != NULL) {
+ /* pf_test can change ip header location */
+ h = mtod(*m, struct ip *);
+ NTOHS(h->ip_len);
+ NTOHS(h->ip_off);
+ }
+ return chk;
+}
+
+#ifdef INET6
+static int
+pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
+ struct inpcb *inp)
+{
+ /*
+ * IPv6 is not affected by ip_len/ip_off byte order changes.
+ */
+ int chk;
+
+ /*
+ * In case of loopback traffic IPv6 uses the real interface in
+ * order to support scoped addresses. In order to support stateful
+ * filtering we have change this to lo0 as it is the case in IPv4.
+ */
+ chk = pf_test6(PF_IN, (*m)->m_flags & M_LOOP ? &loif[0] : ifp, m,
+ NULL, inp);
+ if (chk && *m) {
+ m_freem(*m);
+ *m = NULL;
+ }
+ return chk;
+}
+
+static int
+pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
+ struct inpcb *inp)
+{
+ /*
+ * IPv6 does not affected ip_len/ip_off byte order changes.
+ */
+ int chk;
+
+ /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */
+ if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
+ in_delayed_cksum(*m);
+ (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
+ }
+ chk = pf_test6(PF_OUT, ifp, m, NULL, inp);
+ if (chk && *m) {
+ m_freem(*m);
+ *m = NULL;
+ }
+ return chk;
+}
+#endif /* INET6 */
+
+static int
+hook_pf(void)
+{
+ struct pfil_head *pfh_inet;
+#ifdef INET6
+ struct pfil_head *pfh_inet6;
+#endif
+
+ PF_ASSERT(MA_NOTOWNED);
+
+ if (pf_pfil_hooked)
+ return (0);
+
+ pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
+ if (pfh_inet == NULL)
+ return (ESRCH); /* XXX */
+ pfil_add_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
+ pfil_add_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
+#ifdef INET6
+ pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
+ if (pfh_inet6 == NULL) {
+ pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK,
+ pfh_inet);
+ pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
+ pfh_inet);
+ return (ESRCH); /* XXX */
+ }
+ pfil_add_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
+ pfil_add_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6);
+#endif
+
+ pf_pfil_hooked = 1;
+ return (0);
+}
+
+static int
+dehook_pf(void)
+{
+ struct pfil_head *pfh_inet;
+#ifdef INET6
+ struct pfil_head *pfh_inet6;
+#endif
+
+ PF_ASSERT(MA_NOTOWNED);
+
+ if (pf_pfil_hooked == 0)
+ return (0);
+
+ pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
+ if (pfh_inet == NULL)
+ return (ESRCH); /* XXX */
+ pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK,
+ pfh_inet);
+ pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
+ pfh_inet);
+#ifdef INET6
+ pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
+ if (pfh_inet6 == NULL)
+ return (ESRCH); /* XXX */
+ pfil_remove_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK,
+ pfh_inet6);
+ pfil_remove_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK,
+ pfh_inet6);
+#endif
+
+ pf_pfil_hooked = 0;
+ return (0);
+}
+
+static int
+pf_load(void)
+{
+ init_zone_var();
+ init_pf_mutex();
+ pf_dev = make_dev(&pf_cdevsw, 0, 0, 0, 0600, PF_NAME);
+ if (pfattach() < 0) {
+ destroy_dev(pf_dev);
+ destroy_pf_mutex();
+ return (ENOMEM);
+ }
+ return (0);
+}
+
+static int
+pf_unload(void)
+{
+ int error = 0;
+
+ PF_LOCK();
+ pf_status.running = 0;
+ PF_UNLOCK();
+ error = dehook_pf();
+ if (error) {
+ /*
+ * Should not happen!
+ * XXX Due to error code ESRCH, kldunload will show
+ * a message like 'No such process'.
+ */
+ printf("%s : pfil unregisteration fail\n", __FUNCTION__);
+ return error;
+ }
+ PF_LOCK();
+ shutdown_pf();
+ pfi_cleanup();
+ pf_osfp_flush();
+ pf_osfp_cleanup();
+ cleanup_pf_zone();
+ PF_UNLOCK();
+ destroy_dev(pf_dev);
+ destroy_pf_mutex();
+ return error;
+}
+
+static int
+pf_modevent(module_t mod, int type, void *data)
+{
+ int error = 0;
+
+ switch(type) {
+ case MOD_LOAD:
+ error = pf_load();
+ break;
+
+ case MOD_UNLOAD:
+ error = pf_unload();
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ return error;
+}
+
+static moduledata_t pf_mod = {
+ "pf",
+ pf_modevent,
+ 0
+};
+
+DECLARE_MODULE(pf, pf_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_FIRST);
+MODULE_VERSION(pf, PF_MODVER);
+#endif /* __FreeBSD__ */
diff --git a/sys/contrib/pf/net/pf_norm.c b/sys/contrib/pf/net/pf_norm.c
index df339ae..0153644 100644
--- a/sys/contrib/pf/net/pf_norm.c
+++ b/sys/contrib/pf/net/pf_norm.c
@@ -1,4 +1,6 @@
-/* $OpenBSD: pf_norm.c,v 1.107 2006/04/16 00:59:52 pascoe Exp $ */
+/* $FreeBSD$ */
+/* $OpenBSD: pf_norm.c,v 1.97 2004/09/21 16:59:12 aaron Exp $ */
+/* add: $OpenBSD: pf_norm.c,v 1.106 2006/03/25 20:55:24 dhartmei Exp $ */
/*
* Copyright 2001 Niels Provos <provos@citi.umich.edu>
@@ -25,7 +27,18 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#ifdef __FreeBSD__
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#include "opt_pf.h"
+#ifdef DEV_PFLOG
+#define NPFLOG DEV_PFLOG
+#else
+#define NPFLOG 0
+#endif
+#else
#include "pflog.h"
+#endif
#include <sys/param.h>
#include <sys/systm.h>
@@ -35,9 +48,11 @@
#include <sys/socket.h>
#include <sys/kernel.h>
#include <sys/time.h>
+#ifndef __FreeBSD__
#include <sys/pool.h>
#include <dev/rndvar.h>
+#endif
#include <net/if.h>
#include <net/if_types.h>
#include <net/bpf.h>
@@ -60,6 +75,9 @@
#include <net/pfvar.h>
+#ifndef __FreeBSD__
+#include <inttypes.h>
+
struct pf_frent {
LIST_ENTRY(pf_frent) fr_next;
struct ip *fr_ip;
@@ -71,12 +89,14 @@ struct pf_frcache {
uint16_t fr_off;
uint16_t fr_end;
};
+#endif
#define PFFRAG_SEENLAST 0x0001 /* Seen the last fragment for this */
#define PFFRAG_NOBUFFER 0x0002 /* Non-buffering fragment cache */
#define PFFRAG_DROP 0x0004 /* Drop all fragments */
#define BUFFER_FRAGMENTS(fr) (!((fr)->fr_flags & PFFRAG_NOBUFFER))
+#ifndef __FreeBSD__
struct pf_fragment {
RB_ENTRY(pf_fragment) fr_entry;
TAILQ_ENTRY(pf_fragment) frag_next;
@@ -94,12 +114,18 @@ struct pf_fragment {
LIST_HEAD(pf_cacheq, pf_frcache) fru_cache; /* non-buf */
} fr_u;
};
+#endif
TAILQ_HEAD(pf_fragqueue, pf_fragment) pf_fragqueue;
TAILQ_HEAD(pf_cachequeue, pf_fragment) pf_cachequeue;
+#ifndef __FreeBSD__
static __inline int pf_frag_compare(struct pf_fragment *,
struct pf_fragment *);
+#else
+static int pf_frag_compare(struct pf_fragment *,
+ struct pf_fragment *);
+#endif
RB_HEAD(pf_frag_tree, pf_fragment) pf_frag_tree, pf_cache_tree;
RB_PROTOTYPE(pf_frag_tree, pf_fragment, fr_entry, pf_frag_compare);
RB_GENERATE(pf_frag_tree, pf_fragment, fr_entry, pf_frag_compare);
@@ -125,13 +151,28 @@ int pf_normalize_tcpopt(struct pf_rule *, struct mbuf *,
} while(0)
/* Globals */
+#ifdef __FreeBSD__
+uma_zone_t pf_frent_pl, pf_frag_pl, pf_cache_pl, pf_cent_pl;
+uma_zone_t pf_state_scrub_pl;
+#else
struct pool pf_frent_pl, pf_frag_pl, pf_cache_pl, pf_cent_pl;
struct pool pf_state_scrub_pl;
+#endif
int pf_nfrents, pf_ncache;
void
pf_normalize_init(void)
{
+#ifdef __FreeBSD__
+ /*
+ * XXX
+ * No high water mark support(It's hint not hard limit).
+ * uma_zone_set_max(pf_frag_pl, PFFRAG_FRAG_HIWAT);
+ */
+ uma_zone_set_max(pf_frent_pl, PFFRAG_FRENT_HIWAT);
+ uma_zone_set_max(pf_cache_pl, PFFRAG_FRCACHE_HIWAT);
+ uma_zone_set_max(pf_cent_pl, PFFRAG_FRCENT_HIWAT);
+#else
pool_init(&pf_frent_pl, sizeof(struct pf_frent), 0, 0, 0, "pffrent",
NULL);
pool_init(&pf_frag_pl, sizeof(struct pf_fragment), 0, 0, 0, "pffrag",
@@ -147,12 +188,17 @@ pf_normalize_init(void)
pool_sethardlimit(&pf_frent_pl, PFFRAG_FRENT_HIWAT, NULL, 0);
pool_sethardlimit(&pf_cache_pl, PFFRAG_FRCACHE_HIWAT, NULL, 0);
pool_sethardlimit(&pf_cent_pl, PFFRAG_FRCENT_HIWAT, NULL, 0);
+#endif
TAILQ_INIT(&pf_fragqueue);
TAILQ_INIT(&pf_cachequeue);
}
+#ifdef __FreeBSD__
+static int
+#else
static __inline int
+#endif
pf_frag_compare(struct pf_fragment *a, struct pf_fragment *b)
{
int diff;
@@ -180,7 +226,12 @@ pf_purge_expired_fragments(void)
pf_default_rule.timeout[PFTM_FRAG];
while ((frag = TAILQ_LAST(&pf_fragqueue, pf_fragqueue)) != NULL) {
+#ifdef __FreeBSD__
+ KASSERT((BUFFER_FRAGMENTS(frag)),
+ ("BUFFER_FRAGMENTS(frag) == 0: %s", __FUNCTION__));
+#else
KASSERT(BUFFER_FRAGMENTS(frag));
+#endif
if (frag->fr_timeout > expire)
break;
@@ -189,14 +240,26 @@ pf_purge_expired_fragments(void)
}
while ((frag = TAILQ_LAST(&pf_cachequeue, pf_cachequeue)) != NULL) {
+#ifdef __FreeBSD__
+ KASSERT((!BUFFER_FRAGMENTS(frag)),
+ ("BUFFER_FRAGMENTS(frag) != 0: %s", __FUNCTION__));
+#else
KASSERT(!BUFFER_FRAGMENTS(frag));
+#endif
if (frag->fr_timeout > expire)
break;
DPFPRINTF(("expiring %d(%p)\n", frag->fr_id, frag));
pf_free_fragment(frag);
+#ifdef __FreeBSD__
+ KASSERT((TAILQ_EMPTY(&pf_cachequeue) ||
+ TAILQ_LAST(&pf_cachequeue, pf_cachequeue) != frag),
+ ("!(TAILQ_EMPTY() || TAILQ_LAST() == farg): %s",
+ __FUNCTION__));
+#else
KASSERT(TAILQ_EMPTY(&pf_cachequeue) ||
TAILQ_LAST(&pf_cachequeue, pf_cachequeue) != frag);
+#endif
}
}
@@ -255,9 +318,17 @@ pf_free_fragment(struct pf_fragment *frag)
frcache = LIST_FIRST(&frag->fr_cache)) {
LIST_REMOVE(frcache, fr_next);
+#ifdef __FreeBSD__
+ KASSERT((LIST_EMPTY(&frag->fr_cache) ||
+ LIST_FIRST(&frag->fr_cache)->fr_off >
+ frcache->fr_end),
+ ("! (LIST_EMPTY() || LIST_FIRST()->fr_off >"
+ " frcache->fr_end): %s", __FUNCTION__));
+#else
KASSERT(LIST_EMPTY(&frag->fr_cache) ||
LIST_FIRST(&frag->fr_cache)->fr_off >
frcache->fr_end);
+#endif
pool_put(&pf_cent_pl, frcache);
pf_ncache--;
@@ -330,7 +401,12 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag,
u_int16_t ip_len = ntohs(ip->ip_len) - ip->ip_hl * 4;
u_int16_t max = ip_len + off;
+#ifdef __FreeBSD__
+ KASSERT((*frag == NULL || BUFFER_FRAGMENTS(*frag)),
+ ("! (*frag == NULL || BUFFER_FRAGMENTS(*frag)): %s", __FUNCTION__));
+#else
KASSERT(*frag == NULL || BUFFER_FRAGMENTS(*frag));
+#endif
/* Strip off ip header */
m->m_data += hlen;
@@ -373,7 +449,12 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag,
frep = frea;
}
+#ifdef __FreeBSD__
+ KASSERT((frep != NULL || frea != NULL),
+ ("!(frep != NULL || frea != NULL): %s", __FUNCTION__));;
+#else
KASSERT(frep != NULL || frea != NULL);
+#endif
if (frep != NULL &&
FR_IP_OFF(frep) + ntohs(frep->fr_ip->ip_len) - frep->fr_ip->ip_hl *
@@ -412,7 +493,7 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag,
break;
}
- /* This fragment is completely overlapped, lose it */
+ /* This fragment is completely overlapped, loose it */
next = LIST_NEXT(frea, fr_next);
m_freem(frea->fr_m);
LIST_REMOVE(frea, fr_next);
@@ -458,7 +539,11 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag,
/* We have all the data */
frent = LIST_FIRST(&(*frag)->fr_queue);
+#ifdef __FreeBSD__
+ KASSERT((frent != NULL), ("frent == NULL: %s", __FUNCTION__));
+#else
KASSERT(frent != NULL);
+#endif
if ((frent->fr_ip->ip_hl << 2) + off > IP_MAXPACKET) {
DPFPRINTF(("drop: too big: %d\n", off));
pf_free_fragment(*frag);
@@ -481,8 +566,17 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag,
m2 = frent->fr_m;
pool_put(&pf_frent_pl, frent);
pf_nfrents--;
+#ifdef __FreeBSD__
+ m->m_pkthdr.csum_flags &= m2->m_pkthdr.csum_flags;
+ m->m_pkthdr.csum_data += m2->m_pkthdr.csum_data;
+#endif
m_cat(m, m2);
}
+#ifdef __FreeBSD__
+ while (m->m_pkthdr.csum_data & 0xffff0000)
+ m->m_pkthdr.csum_data = (m->m_pkthdr.csum_data & 0xffff) +
+ (m->m_pkthdr.csum_data >> 16);
+#endif
ip->ip_src = (*frag)->fr_src;
ip->ip_dst = (*frag)->fr_dst;
@@ -527,7 +621,12 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff,
u_int16_t max = ip_len + off;
int hosed = 0;
+#ifdef __FreeBSD__
+ KASSERT((*frag == NULL || !BUFFER_FRAGMENTS(*frag)),
+ ("!(*frag == NULL || !BUFFER_FRAGMENTS(*frag)): %s", __FUNCTION__));
+#else
KASSERT(*frag == NULL || !BUFFER_FRAGMENTS(*frag));
+#endif
/* Create a new range queue for this packet */
if (*frag == NULL) {
@@ -580,7 +679,12 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff,
frp = fra;
}
+#ifdef __FreeBSD__
+ KASSERT((frp != NULL || fra != NULL),
+ ("!(frp != NULL || fra != NULL): %s", __FUNCTION__));
+#else
KASSERT(frp != NULL || fra != NULL);
+#endif
if (frp != NULL) {
int precut;
@@ -622,10 +726,24 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff,
* than this mbuf magic. For my next trick,
* I'll pull a rabbit out of my laptop.
*/
+#ifdef __FreeBSD__
+ *m0 = m_dup(m, M_DONTWAIT);
+#else
*m0 = m_copym2(m, 0, h->ip_hl << 2, M_NOWAIT);
+#endif
if (*m0 == NULL)
goto no_mem;
+#ifdef __FreeBSD__
+ /* From KAME Project : We have missed this! */
+ m_adj(*m0, (h->ip_hl << 2) -
+ (*m0)->m_pkthdr.len);
+
+ KASSERT(((*m0)->m_next == NULL),
+ ("(*m0)->m_next != NULL: %s",
+ __FUNCTION__));
+#else
KASSERT((*m0)->m_next == NULL);
+#endif
m_adj(m, precut + (h->ip_hl << 2));
m_cat(*m0, m);
m = *m0;
@@ -640,9 +758,15 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff,
h = mtod(m, struct ip *);
-
+#ifdef __FreeBSD__
+ KASSERT(((int)m->m_len ==
+ ntohs(h->ip_len) - precut),
+ ("m->m_len != ntohs(h->ip_len) - precut: %s",
+ __FUNCTION__));
+#else
KASSERT((int)m->m_len ==
ntohs(h->ip_len) - precut);
+#endif
h->ip_off = htons(ntohs(h->ip_off) +
(precut >> 3));
h->ip_len = htons(ntohs(h->ip_len) - precut);
@@ -698,8 +822,14 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff,
m->m_pkthdr.len = plen;
}
h = mtod(m, struct ip *);
+#ifdef __FreeBSD__
+ KASSERT(((int)m->m_len == ntohs(h->ip_len) - aftercut),
+ ("m->m_len != ntohs(h->ip_len) - aftercut: %s",
+ __FUNCTION__));
+#else
KASSERT((int)m->m_len ==
ntohs(h->ip_len) - aftercut);
+#endif
h->ip_len = htons(ntohs(h->ip_len) - aftercut);
} else {
hosed++;
@@ -737,7 +867,12 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff,
} else if (frp && fra->fr_off <= frp->fr_end) {
/* Need to merge in a modified 'frp' */
+#ifdef __FreeBSD__
+ KASSERT((cur == NULL), ("cur != NULL: %s",
+ __FUNCTION__));
+#else
KASSERT(cur == NULL);
+#endif
DPFPRINTF(("fragcache[%d]: adjacent(merge "
"%d-%d) %d-%d (%d-%d)\n",
h->ip_id, frp->fr_off, frp->fr_end, off,
@@ -831,7 +966,8 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr);
while (r != NULL) {
r->evaluations++;
- if (pfi_kif_match(r->kif, kif) == r->ifnot)
+ if (r->kif != NULL &&
+ (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
r = r->skip[PF_SKIP_IFP].ptr;
else if (r->direction && r->direction != dir)
r = r->skip[PF_SKIP_DIR].ptr;
@@ -840,23 +976,19 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
else if (r->proto && r->proto != h->ip_p)
r = r->skip[PF_SKIP_PROTO].ptr;
else if (PF_MISMATCHAW(&r->src.addr,
- (struct pf_addr *)&h->ip_src.s_addr, AF_INET,
- r->src.neg, kif))
+ (struct pf_addr *)&h->ip_src.s_addr, AF_INET, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
else if (PF_MISMATCHAW(&r->dst.addr,
- (struct pf_addr *)&h->ip_dst.s_addr, AF_INET,
- r->dst.neg, NULL))
+ (struct pf_addr *)&h->ip_dst.s_addr, AF_INET, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else
break;
}
- if (r == NULL || r->action == PF_NOSCRUB)
+ if (r == NULL)
return (PF_PASS);
- else {
- r->packets[dir == PF_OUT]++;
- r->bytes[dir == PF_OUT] += pd->tot_len;
- }
+ else
+ r->packets++;
/* Check for illegal packets */
if (hlen < (int)sizeof(struct ip))
@@ -929,18 +1061,6 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
if (m == NULL)
return (PF_DROP);
- /* use mtag from concatenated mbuf chain */
- pd->pf_mtag = pf_find_mtag(m);
-#ifdef DIAGNOSTIC
- if (pd->pf_mtag == NULL) {
- printf("%s: pf_find_mtag returned NULL(1)\n", __func__);
- if ((pd->pf_mtag = pf_get_mtag(m)) == NULL) {
- m_freem(m);
- *m0 = NULL;
- goto no_mem;
- }
- }
-#endif
if (frag != NULL && (frag->fr_flags & PFFRAG_DROP))
goto drop;
@@ -949,13 +1069,15 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
/* non-buffering fragment cache (drops or masks overlaps) */
int nomem = 0;
- if (dir == PF_OUT && pd->pf_mtag->flags & PF_TAG_FRAGCACHE) {
- /*
- * Already passed the fragment cache in the
- * input direction. If we continued, it would
- * appear to be a dup and would be dropped.
- */
- goto fragment_pass;
+ if (dir == PF_OUT) {
+ if (m_tag_find(m, PACKET_TAG_PF_FRAGCACHE, NULL) !=
+ NULL) {
+ /* Already passed the fragment cache in the
+ * input direction. If we continued, it would
+ * appear to be a dup and would be dropped.
+ */
+ goto fragment_pass;
+ }
}
frag = pf_find_fragment(h, &pf_cache_tree);
@@ -976,21 +1098,14 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
goto drop;
}
- /* use mtag from copied and trimmed mbuf chain */
- pd->pf_mtag = pf_find_mtag(m);
-#ifdef DIAGNOSTIC
- if (pd->pf_mtag == NULL) {
- printf("%s: pf_find_mtag returned NULL(2)\n", __func__);
- if ((pd->pf_mtag = pf_get_mtag(m)) == NULL) {
- m_freem(m);
- *m0 = NULL;
+ if (dir == PF_IN) {
+ struct m_tag *mtag;
+
+ mtag = m_tag_get(PACKET_TAG_PF_FRAGCACHE, 0, M_NOWAIT);
+ if (mtag == NULL)
goto no_mem;
- }
+ m_tag_prepend(m, mtag);
}
-#endif
- if (dir == PF_IN)
- pd->pf_mtag->flags |= PF_TAG_FRAGCACHE;
-
if (frag != NULL && (frag->fr_flags & PFFRAG_DROP))
goto drop;
goto fragment_pass;
@@ -1039,13 +1154,13 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
no_mem:
REASON_SET(reason, PFRES_MEMORY);
if (r != NULL && r->log)
- PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL, pd);
+ PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL);
return (PF_DROP);
drop:
REASON_SET(reason, PFRES_NORM);
if (r != NULL && r->log)
- PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL, pd);
+ PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL);
return (PF_DROP);
bad:
@@ -1057,7 +1172,7 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
REASON_SET(reason, PFRES_FRAG);
if (r != NULL && r->log)
- PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL, pd);
+ PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL);
return (PF_DROP);
}
@@ -1085,7 +1200,8 @@ pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif,
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr);
while (r != NULL) {
r->evaluations++;
- if (pfi_kif_match(r->kif, kif) == r->ifnot)
+ if (r->kif != NULL &&
+ (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
r = r->skip[PF_SKIP_IFP].ptr;
else if (r->direction && r->direction != dir)
r = r->skip[PF_SKIP_DIR].ptr;
@@ -1096,23 +1212,19 @@ pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif,
r = r->skip[PF_SKIP_PROTO].ptr;
#endif
else if (PF_MISMATCHAW(&r->src.addr,
- (struct pf_addr *)&h->ip6_src, AF_INET6,
- r->src.neg, kif))
+ (struct pf_addr *)&h->ip6_src, AF_INET6, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
else if (PF_MISMATCHAW(&r->dst.addr,
- (struct pf_addr *)&h->ip6_dst, AF_INET6,
- r->dst.neg, NULL))
+ (struct pf_addr *)&h->ip6_dst, AF_INET6, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else
break;
}
- if (r == NULL || r->action == PF_NOSCRUB)
+ if (r == NULL)
return (PF_PASS);
- else {
- r->packets[dir == PF_OUT]++;
- r->bytes[dir == PF_OUT] += pd->tot_len;
- }
+ else
+ r->packets++;
/* Check for illegal packets */
if (sizeof(struct ip6_hdr) + IPV6_MAXPACKET < m->m_pkthdr.len)
@@ -1224,19 +1336,19 @@ pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif,
shortpkt:
REASON_SET(reason, PFRES_SHORT);
if (r != NULL && r->log)
- PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL, pd);
+ PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL);
return (PF_DROP);
drop:
REASON_SET(reason, PFRES_NORM);
if (r != NULL && r->log)
- PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL, pd);
+ PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL);
return (PF_DROP);
badfrag:
REASON_SET(reason, PFRES_FRAG);
if (r != NULL && r->log)
- PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL, pd);
+ PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL);
return (PF_DROP);
}
#endif /* INET6 */
@@ -1255,7 +1367,8 @@ pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff,
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr);
while (r != NULL) {
r->evaluations++;
- if (pfi_kif_match(r->kif, kif) == r->ifnot)
+ if (r->kif != NULL &&
+ (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
r = r->skip[PF_SKIP_IFP].ptr;
else if (r->direction && r->direction != dir)
r = r->skip[PF_SKIP_DIR].ptr;
@@ -1263,14 +1376,12 @@ pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff,
r = r->skip[PF_SKIP_AF].ptr;
else if (r->proto && r->proto != pd->proto)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&r->src.addr, pd->src, af,
- r->src.neg, kif))
+ else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
else if (r->src.port_op && !pf_match_port(r->src.port_op,
r->src.port[0], r->src.port[1], th->th_sport))
r = r->skip[PF_SKIP_SRC_PORT].ptr;
- else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af,
- r->dst.neg, NULL))
+ else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
r->dst.port[0], r->dst.port[1], th->th_dport))
@@ -1287,10 +1398,8 @@ pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff,
if (rm == NULL || rm->action == PF_NOSCRUB)
return (PF_PASS);
- else {
- r->packets[dir == PF_OUT]++;
- r->bytes[dir == PF_OUT] += pd->tot_len;
- }
+ else
+ r->packets++;
if (rm->rule_flag & PFRULE_REASSEMBLE_TCP)
pd->flags |= PFDESC_TCP_NORM;
@@ -1345,14 +1454,14 @@ pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff,
/* copy back packet headers if we sanitized */
if (rewrite)
- m_copyback(m, off, sizeof(*th), th);
+ m_copyback(m, off, sizeof(*th), (caddr_t)th);
return (PF_PASS);
tcp_drop:
REASON_SET(&reason, PFRES_NORM);
if (rm != NULL && r->log)
- PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, r, NULL, NULL, pd);
+ PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, r, NULL, NULL);
return (PF_DROP);
}
@@ -1364,7 +1473,12 @@ pf_normalize_tcp_init(struct mbuf *m, int off, struct pf_pdesc *pd,
u_int8_t hdr[60];
u_int8_t *opt;
+#ifdef __FreeBSD__
+ KASSERT((src->scrub == NULL),
+ ("pf_normalize_tcp_init: src->scrub != NULL"));
+#else
KASSERT(src->scrub == NULL);
+#endif
src->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT);
if (src->scrub == NULL)
@@ -1463,7 +1577,12 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd,
int copyback = 0;
int got_ts = 0;
+#ifdef __FreeBSD__
+ KASSERT((src->scrub || dst->scrub),
+ ("pf_normalize_tcp_statefull: src->scrub && dst->scrub!"));
+#else
KASSERT(src->scrub || dst->scrub);
+#endif
/*
* Enforce the minimum TTL seen for this connection. Negate a common
@@ -1687,6 +1806,19 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd,
/* Calculate max ticks since the last timestamp */
#define TS_MAXFREQ 1100 /* RFC max TS freq of 1Khz + 10% skew */
#define TS_MICROSECS 1000000 /* microseconds per second */
+#ifdef __FreeBSD__
+#ifndef timersub
+#define timersub(tvp, uvp, vvp) \
+ do { \
+ (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
+ if ((vvp)->tv_usec < 0) { \
+ (vvp)->tv_sec--; \
+ (vvp)->tv_usec += 1000000; \
+ } \
+ } while (0)
+#endif
+#endif
timersub(&uptime, &src->scrub->pfss_last, &delta_ts);
tsval_from_last = (delta_ts.tv_sec + ts_fudge) * TS_MAXFREQ;
tsval_from_last += delta_ts.tv_usec / (TS_MICROSECS/TS_MAXFREQ);
@@ -1711,6 +1843,18 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd,
tsval_from_last) ? '1' : ' ',
SEQ_GT(tsecr, dst->scrub->pfss_tsval) ? '2' : ' ',
SEQ_LT(tsecr, dst->scrub->pfss_tsval0)? '3' : ' '));
+#ifdef __FreeBSD__
+ DPFPRINTF((" tsval: %u tsecr: %u +ticks: %u "
+ "idle: %jus %lums\n",
+ tsval, tsecr, tsval_from_last,
+ (uintmax_t)delta_ts.tv_sec,
+ delta_ts.tv_usec / 1000));
+ DPFPRINTF((" src->tsval: %u tsecr: %u\n",
+ src->scrub->pfss_tsval, src->scrub->pfss_tsecr));
+ DPFPRINTF((" dst->tsval: %u tsecr: %u tsval0: %u"
+ "\n", dst->scrub->pfss_tsval,
+ dst->scrub->pfss_tsecr, dst->scrub->pfss_tsval0));
+#else
DPFPRINTF((" tsval: %lu tsecr: %lu +ticks: %lu "
"idle: %lus %lums\n",
tsval, tsecr, tsval_from_last, delta_ts.tv_sec,
@@ -1720,6 +1864,7 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd,
DPFPRINTF((" dst->tsval: %lu tsecr: %lu tsval0: %lu"
"\n", dst->scrub->pfss_tsval,
dst->scrub->pfss_tsecr, dst->scrub->pfss_tsval0));
+#endif
if (pf_status.debug >= PF_DEBUG_MISC) {
pf_print_state(state);
pf_print_flags(th->th_flags);
@@ -1786,7 +1931,7 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd,
* timestamps. And require all data packets to contain a timestamp
* if the first does. PAWS implicitly requires that all data packets be
* timestamped. But I think there are middle-man devices that hijack
- * TCP streams immediately after the 3whs and don't timestamp their
+ * TCP streams immedietly after the 3whs and don't timestamp their
* packets (seen in a WWW accelerator or cache).
*/
if (pd->p_len > 0 && src->scrub && (src->scrub->pfss_flags &
diff --git a/sys/contrib/pf/net/pf_osfp.c b/sys/contrib/pf/net/pf_osfp.c
index 15dca8e..ce1efee 100644
--- a/sys/contrib/pf/net/pf_osfp.c
+++ b/sys/contrib/pf/net/pf_osfp.c
@@ -1,4 +1,5 @@
-/* $OpenBSD: pf_osfp.c,v 1.12 2006/12/13 18:14:10 itojun Exp $ */
+/* $FreeBSD$ */
+/* $OpenBSD: pf_osfp.c,v 1.10 2004/04/09 19:30:41 frantzen Exp $ */
/*
* Copyright (c) 2003 Mike Frantzen <frantzen@w4g.org>
@@ -32,17 +33,19 @@
#include <net/if.h>
#include <net/pfvar.h>
+#ifdef INET6
#include <netinet/ip6.h>
-#ifdef _KERNEL
-#include <netinet6/in6_var.h>
-#endif
-
+#endif /* INET6 */
#ifdef _KERNEL
# define DPFPRINTF(format, x...) \
if (pf_status.debug >= PF_DEBUG_NOISY) \
printf(format , ##x)
+#ifdef __FreeBSD__
+typedef uma_zone_t pool_t;
+#else
typedef struct pool pool_t;
+#endif
#else
/* Userland equivalents so we can lend code to tcpdump et al. */
@@ -52,12 +55,15 @@ typedef struct pool pool_t;
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
-# include <netdb.h>
# define pool_t int
# define pool_get(pool, flags) malloc(*(pool))
# define pool_put(pool, item) free(item)
# define pool_init(pool, size, a, ao, f, m, p) (*(pool)) = (size)
+# ifdef __FreeBSD__
+# define NTOHS(x) (x) = ntohs((u_int16_t)(x))
+# endif
+
# ifdef PFDEBUG
# include <sys/stdarg.h>
# define DPFPRINTF(format, x...) fprintf(stderr, format , ##x)
@@ -89,96 +95,38 @@ pf_osfp_fingerprint(struct pf_pdesc *pd, struct mbuf *m, int off,
const struct tcphdr *tcp)
{
struct ip *ip;
- struct ip6_hdr *ip6;
char hdr[60];
- if ((pd->af != PF_INET && pd->af != PF_INET6) ||
- pd->proto != IPPROTO_TCP || (tcp->th_off << 2) < sizeof(*tcp))
+ /* XXX don't have a fingerprint database for IPv6 :-( */
+ if (pd->af != PF_INET || pd->proto != IPPROTO_TCP || (tcp->th_off << 2)
+ < sizeof(*tcp))
return (NULL);
- if (pd->af == PF_INET) {
- ip = mtod(m, struct ip *);
- ip6 = (struct ip6_hdr *)NULL;
- } else {
- ip = (struct ip *)NULL;
- ip6 = mtod(m, struct ip6_hdr *);
- }
- if (!pf_pull_hdr(m, off, hdr, tcp->th_off << 2, NULL, NULL,
- pd->af)) return (NULL);
+ ip = mtod(m, struct ip *);
+ if (!pf_pull_hdr(m, off, hdr, tcp->th_off << 2, NULL, NULL, pd->af))
+ return (NULL);
- return (pf_osfp_fingerprint_hdr(ip, ip6, (struct tcphdr *)hdr));
+ return (pf_osfp_fingerprint_hdr(ip, (struct tcphdr *)hdr));
}
#endif /* _KERNEL */
struct pf_osfp_enlist *
-pf_osfp_fingerprint_hdr(const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcp)
+pf_osfp_fingerprint_hdr(const struct ip *ip, const struct tcphdr *tcp)
{
struct pf_os_fingerprint fp, *fpresult;
int cnt, optlen = 0;
const u_int8_t *optp;
-#ifdef _KERNEL
- char srcname[128];
-#else
- char srcname[NI_MAXHOST];
-#endif
- if ((tcp->th_flags & (TH_SYN|TH_ACK)) != TH_SYN)
+ if ((tcp->th_flags & (TH_SYN|TH_ACK)) != TH_SYN || (ip->ip_off &
+ htons(IP_OFFMASK)))
return (NULL);
- if (ip) {
- if ((ip->ip_off & htons(IP_OFFMASK)) != 0)
- return (NULL);
- }
memset(&fp, 0, sizeof(fp));
- if (ip) {
-#ifndef _KERNEL
- struct sockaddr_in sin;
-#endif
-
- fp.fp_psize = ntohs(ip->ip_len);
- fp.fp_ttl = ip->ip_ttl;
- if (ip->ip_off & htons(IP_DF))
- fp.fp_flags |= PF_OSFP_DF;
-#ifdef _KERNEL
- strlcpy(srcname, inet_ntoa(ip->ip_src), sizeof(srcname));
-#else
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_len = sizeof(struct sockaddr_in);
- sin.sin_addr = ip->ip_src;
- (void)getnameinfo((struct sockaddr *)&sin,
- sizeof(struct sockaddr_in), srcname, sizeof(srcname),
- NULL, 0, NI_NUMERICHOST);
-#endif
- }
-#ifdef INET6
- else if (ip6) {
-#ifndef _KERNEL
- struct sockaddr_in6 sin6;
-#endif
-
- /* jumbo payload? */
- fp.fp_psize = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen);
- fp.fp_ttl = ip6->ip6_hlim;
+ fp.fp_psize = ntohs(ip->ip_len);
+ fp.fp_ttl = ip->ip_ttl;
+ if (ip->ip_off & htons(IP_DF))
fp.fp_flags |= PF_OSFP_DF;
- fp.fp_flags |= PF_OSFP_INET6;
-#ifdef _KERNEL
- strlcpy(srcname, ip6_sprintf((struct in6_addr *)&ip6->ip6_src),
- sizeof(srcname));
-#else
- memset(&sin6, 0, sizeof(sin6));
- sin6.sin6_family = AF_INET6;
- sin6.sin6_len = sizeof(struct sockaddr_in6);
- sin6.sin6_addr = ip6->ip6_src;
- (void)getnameinfo((struct sockaddr *)&sin6,
- sizeof(struct sockaddr_in6), srcname, sizeof(srcname),
- NULL, 0, NI_NUMERICHOST);
-#endif
- }
-#endif
- else
- return (NULL);
fp.fp_wsize = ntohs(tcp->th_win);
@@ -241,7 +189,7 @@ pf_osfp_fingerprint_hdr(const struct ip *ip, const struct ip6_hdr *ip6, const st
DPFPRINTF("fingerprinted %s:%d %d:%d:%d:%d:%llx (%d) "
"(TS=%s,M=%s%d,W=%s%d)\n",
- srcname, ntohs(tcp->th_sport),
+ inet_ntoa(ip->ip_src), ntohs(tcp->th_sport),
fp.fp_wsize, fp.fp_ttl, (fp.fp_flags & PF_OSFP_DF) != 0,
fp.fp_psize, (long long int)fp.fp_tcpopts, fp.fp_optcnt,
(fp.fp_flags & PF_OSFP_TS0) ? "0" : "",
@@ -289,16 +237,47 @@ pf_osfp_match(struct pf_osfp_enlist *list, pf_osfp_t os)
}
/* Initialize the OS fingerprint system */
+#ifdef __FreeBSD__
+int
+#else
void
+#endif
pf_osfp_initialize(void)
{
+#if defined(__FreeBSD__) && defined(_KERNEL)
+ int error = ENOMEM;
+
+ do {
+ pf_osfp_entry_pl = pf_osfp_pl = NULL;
+ UMA_CREATE(pf_osfp_entry_pl, struct pf_osfp_entry, "pfospfen");
+ UMA_CREATE(pf_osfp_pl, struct pf_os_fingerprint, "pfosfp");
+ error = 0;
+ } while(0);
+#else
pool_init(&pf_osfp_entry_pl, sizeof(struct pf_osfp_entry), 0, 0, 0,
"pfosfpen", &pool_allocator_nointr);
pool_init(&pf_osfp_pl, sizeof(struct pf_os_fingerprint), 0, 0, 0,
"pfosfp", &pool_allocator_nointr);
+#endif
SLIST_INIT(&pf_osfp_list);
+#ifdef __FreeBSD__
+#ifdef _KERNEL
+ return (error);
+#else
+ return (0);
+#endif
+#endif
}
+#if defined(__FreeBSD__) && (_KERNEL)
+void
+pf_osfp_cleanup(void)
+{
+ UMA_DESTROY(pf_osfp_entry_pl);
+ UMA_DESTROY(pf_osfp_pl);
+}
+#endif
+
/* Flush the fingerprint list */
void
pf_osfp_flush(void)
diff --git a/sys/contrib/pf/net/pf_subr.c b/sys/contrib/pf/net/pf_subr.c
new file mode 100644
index 0000000..3de2924
--- /dev/null
+++ b/sys/contrib/pf/net/pf_subr.c
@@ -0,0 +1,127 @@
+/* $FreeBSD$ */
+/* from $OpenBSD: kern_subr.c,v 1.26 2003/10/31 11:10:41 markus Exp $ */
+/* $NetBSD: kern_subr.c,v 1.15 1996/04/09 17:21:56 ragge Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)kern_subr.c 8.3 (Berkeley) 1/21/94
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/kernel.h>
+#include <sys/resourcevar.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+
+#include <net/pfvar.h>
+
+/*
+ * This implements additional functions used by pf which can not be ported
+ * easyly. At this point it boils down to mostly the Net/OpenBSD hook
+ * implementation.
+ *
+ * BEWARE: this is not locked! Required locking is done by the caller.
+ */
+
+void *
+hook_establish(struct hook_desc_head *head, int tail, void (*fn)(void *),
+ void *arg)
+{
+ struct hook_desc *hdp;
+
+ hdp = (struct hook_desc *)malloc(sizeof (*hdp), M_DEVBUF, M_NOWAIT);
+ if (hdp == NULL)
+ return (NULL);
+
+ hdp->hd_fn = fn;
+ hdp->hd_arg = arg;
+ if (tail)
+ TAILQ_INSERT_TAIL(head, hdp, hd_list);
+ else
+ TAILQ_INSERT_HEAD(head, hdp, hd_list);
+
+ return (hdp);
+}
+
+void
+hook_disestablish(struct hook_desc_head *head, void *vhook)
+{
+ struct hook_desc *hdp;
+
+#ifdef DIAGNOSTIC
+ for (hdp = TAILQ_FIRST(head); hdp != NULL;
+ hdp = TAILQ_NEXT(hdp, hd_list))
+ if (hdp == vhook)
+ break;
+ if (hdp == NULL)
+ panic("hook_disestablish: hook not established");
+#endif
+ hdp = vhook;
+ TAILQ_REMOVE(head, hdp, hd_list);
+ free(hdp, M_DEVBUF);
+}
+
+/*
+ * Run hooks. Startup hooks are invoked right after scheduler_start but
+ * before root is mounted. Shutdown hooks are invoked immediately before the
+ * system is halted or rebooted, i.e. after file systems unmounted,
+ * after crash dump done, etc.
+ */
+void
+dohooks(struct hook_desc_head *head, int flags)
+{
+ struct hook_desc *hdp;
+
+ if ((flags & HOOK_REMOVE) == 0) {
+ TAILQ_FOREACH(hdp, head, hd_list) {
+ (*hdp->hd_fn)(hdp->hd_arg);
+ }
+ } else {
+ while ((hdp = TAILQ_FIRST(head)) != NULL) {
+ TAILQ_REMOVE(head, hdp, hd_list);
+ (*hdp->hd_fn)(hdp->hd_arg);
+ if ((flags & HOOK_FREE) != 0)
+ free(hdp, M_DEVBUF);
+ }
+ }
+}
diff --git a/sys/contrib/pf/net/pf_table.c b/sys/contrib/pf/net/pf_table.c
index a79ed37..033616e 100644
--- a/sys/contrib/pf/net/pf_table.c
+++ b/sys/contrib/pf/net/pf_table.c
@@ -1,4 +1,5 @@
-/* $OpenBSD: pf_table.c,v 1.68 2006/05/02 10:08:45 dhartmei Exp $ */
+/* $FreeBSD$ */
+/* $OpenBSD: pf_table.c,v 1.62 2004/12/07 18:02:04 mcbride Exp $ */
/*
* Copyright (c) 2002 Cedric Berger
@@ -30,16 +31,27 @@
*
*/
+#ifdef __FreeBSD__
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#endif
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/socket.h>
#include <sys/mbuf.h>
#include <sys/kernel.h>
+#ifdef __FreeBSD__
+#include <sys/malloc.h>
+#endif
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
+#ifndef __FreeBSD__
#include <netinet/ip_ipsp.h>
+#endif
+
#include <net/pfvar.h>
#define ACCEPT_FLAGS(oklist) \
@@ -49,6 +61,43 @@
return (EINVAL); \
} while (0)
+#ifdef __FreeBSD__
+static inline int
+_copyin(const void *uaddr, void *kaddr, size_t len)
+{
+ int r;
+
+ PF_UNLOCK();
+ r = copyin(uaddr, kaddr, len);
+ PF_LOCK();
+
+ return (r);
+}
+
+static inline int
+_copyout(const void *uaddr, void *kaddr, size_t len)
+{
+ int r;
+
+ PF_UNLOCK();
+ r = copyout(uaddr, kaddr, len);
+ PF_LOCK();
+
+ return (r);
+}
+
+#define COPYIN(from, to, size) \
+ ((flags & PFR_FLAG_USERIOCTL) ? \
+ _copyin((from), (to), (size)) : \
+ (bcopy((from), (to), (size)), 0))
+
+#define COPYOUT(from, to, size) \
+ ((flags & PFR_FLAG_USERIOCTL) ? \
+ _copyout((from), (to), (size)) : \
+ (bcopy((from), (to), (size)), 0))
+
+#else
+
#define COPYIN(from, to, size) \
((flags & PFR_FLAG_USERIOCTL) ? \
copyin((from), (to), (size)) : \
@@ -59,6 +108,8 @@
copyout((from), (to), (size)) : \
(bcopy((from), (to), (size)), 0))
+#endif
+
#define FILLIN_SIN(sin, addr) \
do { \
(sin).sin_len = sizeof(sin); \
@@ -123,9 +174,15 @@ struct pfr_walktree {
#define senderr(e) do { rv = (e); goto _bad; } while (0)
+#ifdef __FreeBSD__
+uma_zone_t pfr_ktable_pl;
+uma_zone_t pfr_kentry_pl;
+uma_zone_t pfr_kentry_pl2;
+#else
struct pool pfr_ktable_pl;
struct pool pfr_kentry_pl;
struct pool pfr_kentry_pl2;
+#endif
struct sockaddr_in pfr_sin;
struct sockaddr_in6 pfr_sin6;
union sockaddr_union pfr_mask;
@@ -188,12 +245,14 @@ int pfr_ktable_cnt;
void
pfr_initialize(void)
{
+#ifndef __FreeBSD__
pool_init(&pfr_ktable_pl, sizeof(struct pfr_ktable), 0, 0, 0,
"pfrktable", &pool_allocator_oldnointr);
pool_init(&pfr_kentry_pl, sizeof(struct pfr_kentry), 0, 0, 0,
"pfrkentry", &pool_allocator_oldnointr);
pool_init(&pfr_kentry_pl2, sizeof(struct pfr_kentry), 0, 0, 0,
"pfrkentry2", NULL);
+#endif
pfr_sin.sin_len = sizeof(pfr_sin);
pfr_sin.sin_family = AF_INET;
@@ -221,6 +280,7 @@ pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
pfr_enqueue_addrs(kt, &workq, ndel, 0);
if (!(flags & PFR_FLAG_DUMMY)) {
+ s = 0;
if (flags & PFR_FLAG_ATOMIC)
s = splsoftnet();
pfr_remove_kentries(kt, &workq);
@@ -243,7 +303,7 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
struct pfr_kentryworkq workq;
struct pfr_kentry *p, *q;
struct pfr_addr ad;
- int i, rv, s, xadd = 0;
+ int i, rv, s = 0, xadd = 0;
long tzero = time_second;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
@@ -287,9 +347,10 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
xadd++;
}
}
- if (flags & PFR_FLAG_FEEDBACK)
+ if (flags & PFR_FLAG_FEEDBACK) {
if (COPYOUT(&ad, addr+i, sizeof(ad)))
senderr(EFAULT);
+ }
}
pfr_clean_node_mask(tmpkt, &workq);
if (!(flags & PFR_FLAG_DUMMY)) {
@@ -321,7 +382,7 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
struct pfr_kentryworkq workq;
struct pfr_kentry *p;
struct pfr_addr ad;
- int i, rv, s, xdel = 0, log = 1;
+ int i, rv, s = 0, xdel = 0, log = 1;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
@@ -404,19 +465,17 @@ _bad:
int
pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
- int *size2, int *nadd, int *ndel, int *nchange, int flags,
- u_int32_t ignore_pfrt_flags)
+ int *size2, int *nadd, int *ndel, int *nchange, int flags)
{
struct pfr_ktable *kt, *tmpkt;
struct pfr_kentryworkq addq, delq, changeq;
struct pfr_kentry *p, *q;
struct pfr_addr ad;
- int i, rv, s, xadd = 0, xdel = 0, xchange = 0;
+ int i, rv, s = 0, xadd = 0, xdel = 0, xchange = 0;
long tzero = time_second;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
- if (pfr_validate_table(tbl, ignore_pfrt_flags, flags &
- PFR_FLAG_USERIOCTL))
+ if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
return (EINVAL);
kt = pfr_lookup_table(tbl);
if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
@@ -578,9 +637,18 @@ pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
w.pfrw_addr = addr;
w.pfrw_free = kt->pfrkt_cnt;
w.pfrw_flags = flags;
+#ifdef __FreeBSD__
+ rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
+#else
rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
+#endif
if (!rv)
+#ifdef __FreeBSD__
+ rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree,
+ &w);
+#else
rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
+#endif
if (rv)
return (rv);
@@ -600,7 +668,7 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
struct pfr_ktable *kt;
struct pfr_walktree w;
struct pfr_kentryworkq workq;
- int rv, s;
+ int rv, s = 0;
long tzero = time_second;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC); /* XXX PFR_FLAG_CLSTATS disabled */
@@ -621,9 +689,18 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
w.pfrw_flags = flags;
if (flags & PFR_FLAG_ATOMIC)
s = splsoftnet();
+#ifdef __FreeBSD__
+ rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
+#else
rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
+#endif
if (!rv)
+#ifdef __FreeBSD__
+ rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree,
+ &w);
+#else
rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
+#endif
if (!rv && (flags & PFR_FLAG_CLSTATS)) {
pfr_enqueue_addrs(kt, &workq, NULL, 0);
pfr_clstats_kentries(&workq, tzero, 0);
@@ -650,7 +727,7 @@ pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size,
struct pfr_kentryworkq workq;
struct pfr_kentry *p;
struct pfr_addr ad;
- int i, rv, s, xzero = 0;
+ int i, rv, s = 0, xzero = 0;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
if (pfr_validate_table(tbl, 0, 0))
@@ -738,10 +815,20 @@ pfr_enqueue_addrs(struct pfr_ktable *kt, struct pfr_kentryworkq *workq,
w.pfrw_op = sweep ? PFRW_SWEEP : PFRW_ENQUEUE;
w.pfrw_workq = workq;
if (kt->pfrkt_ip4 != NULL)
+#ifdef __FreeBSD__
+ if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree,
+ &w))
+#else
if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
+#endif
printf("pfr_enqueue_addrs: IPv4 walktree failed.\n");
if (kt->pfrkt_ip6 != NULL)
+#ifdef __FreeBSD__
+ if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree,
+ &w))
+#else
if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
+#endif
printf("pfr_enqueue_addrs: IPv6 walktree failed.\n");
if (naddr != NULL)
*naddr = w.pfrw_cnt;
@@ -754,9 +841,17 @@ pfr_mark_addrs(struct pfr_ktable *kt)
bzero(&w, sizeof(w));
w.pfrw_op = PFRW_MARK;
+#ifdef __FreeBSD__
+ if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
+#else
if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
+#endif
printf("pfr_mark_addrs: IPv4 walktree failed.\n");
+#ifdef __FreeBSD__
+ if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
+#else
if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
+#endif
printf("pfr_mark_addrs: IPv6 walktree failed.\n");
}
@@ -765,7 +860,7 @@ struct pfr_kentry *
pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact)
{
union sockaddr_union sa, mask;
- struct radix_node_head *head;
+ struct radix_node_head *head = NULL; /* make the compiler happy */
struct pfr_kentry *ke;
int s;
@@ -780,7 +875,13 @@ pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact)
if (ADDR_NETWORK(ad)) {
pfr_prepare_network(&mask, ad->pfra_af, ad->pfra_net);
s = splsoftnet(); /* rn_lookup makes use of globals */
+#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
+ RADIX_NODE_HEAD_LOCK(head);
+#endif
ke = (struct pfr_kentry *)rn_lookup(&sa, &mask, head);
+#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
+ RADIX_NODE_HEAD_UNLOCK(head);
+#endif
splx(s);
if (ke && KENTRY_RNF_ROOT(ke))
ke = NULL;
@@ -968,7 +1069,7 @@ pfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke)
{
union sockaddr_union mask;
struct radix_node *rn;
- struct radix_node_head *head;
+ struct radix_node_head *head = NULL; /* make the compiler happy */
int s;
bzero(ke->pfrke_node, sizeof(ke->pfrke_node));
@@ -978,11 +1079,17 @@ pfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke)
head = kt->pfrkt_ip6;
s = splsoftnet();
+#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
+ RADIX_NODE_HEAD_LOCK(head);
+#endif
if (KENTRY_NETWORK(ke)) {
pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net);
rn = rn_addroute(&ke->pfrke_sa, &mask, head, ke->pfrke_node);
} else
rn = rn_addroute(&ke->pfrke_sa, NULL, head, ke->pfrke_node);
+#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
+ RADIX_NODE_HEAD_UNLOCK(head);
+#endif
splx(s);
return (rn == NULL ? -1 : 0);
@@ -993,7 +1100,7 @@ pfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke)
{
union sockaddr_union mask;
struct radix_node *rn;
- struct radix_node_head *head;
+ struct radix_node_head *head = NULL; /* make the compiler happy */
int s;
if (ke->pfrke_af == AF_INET)
@@ -1002,11 +1109,25 @@ pfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke)
head = kt->pfrkt_ip6;
s = splsoftnet();
+#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
+ RADIX_NODE_HEAD_LOCK(head);
+#endif
if (KENTRY_NETWORK(ke)) {
pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net);
+#ifdef __FreeBSD__
+ rn = rn_delete(&ke->pfrke_sa, &mask, head);
+#else
rn = rn_delete(&ke->pfrke_sa, &mask, head, NULL);
+#endif
} else
+#ifdef __FreeBSD__
+ rn = rn_delete(&ke->pfrke_sa, NULL, head);
+#else
rn = rn_delete(&ke->pfrke_sa, NULL, head, NULL);
+#endif
+#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
+ RADIX_NODE_HEAD_UNLOCK(head);
+#endif
splx(s);
if (rn == NULL) {
@@ -1115,7 +1236,7 @@ pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags)
{
struct pfr_ktableworkq workq;
struct pfr_ktable *p;
- int s, xdel = 0;
+ int s = 0, xdel = 0;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_ALLRSETS);
if (pfr_fix_anchor(filter->pfrt_anchor))
@@ -1152,7 +1273,7 @@ pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
{
struct pfr_ktableworkq addq, changeq;
struct pfr_ktable *p, *q, *r, key;
- int i, rv, s, xadd = 0;
+ int i, rv, s = 0, xadd = 0;
long tzero = time_second;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
@@ -1232,7 +1353,7 @@ pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
{
struct pfr_ktableworkq workq;
struct pfr_ktable *p, *q, key;
- int i, s, xdel = 0;
+ int i, s = 0, xdel = 0;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
SLIST_INIT(&workq);
@@ -1306,7 +1427,7 @@ pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
{
struct pfr_ktable *p;
struct pfr_ktableworkq workq;
- int s, n, nn;
+ int s = 0, n, nn;
long tzero = time_second;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC|PFR_FLAG_ALLRSETS);
@@ -1331,7 +1452,8 @@ pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
if (!(flags & PFR_FLAG_ATOMIC))
s = splsoftnet();
if (COPYOUT(&p->pfrkt_ts, tbl++, sizeof(*tbl))) {
- splx(s);
+ if (!(flags & PFR_FLAG_ATOMIC))
+ splx(s);
return (EFAULT);
}
if (!(flags & PFR_FLAG_ATOMIC))
@@ -1356,7 +1478,7 @@ pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
{
struct pfr_ktableworkq workq;
struct pfr_ktable *p, key;
- int i, s, xzero = 0;
+ int i, s = 0, xzero = 0;
long tzero = time_second;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_ADDRSTOO);
@@ -1390,7 +1512,7 @@ pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag,
{
struct pfr_ktableworkq workq;
struct pfr_ktable *p, *q, key;
- int i, s, xchange = 0, xdel = 0;
+ int i, s = 0, xchange = 0, xdel = 0;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
if ((setflag & ~PFR_TFLAG_USRMASK) ||
@@ -1609,7 +1731,7 @@ pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd,
struct pfr_ktable *p, *q;
struct pfr_ktableworkq workq;
struct pf_ruleset *rs;
- int s, xadd = 0, xchange = 0;
+ int s = 0, xadd = 0, xchange = 0;
long tzero = time_second;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
@@ -1927,10 +2049,21 @@ pfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr)
pfr_clean_node_mask(kt, &addrq);
pfr_destroy_kentries(&addrq);
}
+#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
+ if (kt->pfrkt_ip4 != NULL) {
+ RADIX_NODE_HEAD_DESTROY(kt->pfrkt_ip4);
+ free((caddr_t)kt->pfrkt_ip4, M_RTABLE);
+ }
+ if (kt->pfrkt_ip6 != NULL) {
+ RADIX_NODE_HEAD_DESTROY(kt->pfrkt_ip6);
+ free((caddr_t)kt->pfrkt_ip6, M_RTABLE);
+ }
+#else
if (kt->pfrkt_ip4 != NULL)
free((caddr_t)kt->pfrkt_ip4, M_RTABLE);
if (kt->pfrkt_ip6 != NULL)
free((caddr_t)kt->pfrkt_ip6, M_RTABLE);
+#endif
if (kt->pfrkt_shadow != NULL)
pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr);
if (kt->pfrkt_rs != NULL) {
@@ -2049,7 +2182,7 @@ pfr_attach_table(struct pf_ruleset *rs, char *name)
bzero(&tbl, sizeof(tbl));
strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name));
if (ac != NULL)
- strlcpy(tbl.pfrt_anchor, ac->path, sizeof(tbl.pfrt_anchor));
+ strlcpy(tbl.pfrt_anchor, ac->name, sizeof(tbl.pfrt_anchor));
kt = pfr_lookup_table(&tbl);
if (kt == NULL) {
kt = pfr_create_ktable(&tbl, time_second, 1);
@@ -2085,12 +2218,13 @@ pfr_detach_table(struct pfr_ktable *kt)
pfr_setflags_ktable(kt, kt->pfrkt_flags&~PFR_TFLAG_REFERENCED);
}
+
int
pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter,
struct pf_addr **raddr, struct pf_addr **rmask, sa_family_t af)
{
- struct pfr_kentry *ke, *ke2;
- struct pf_addr *addr;
+ struct pfr_kentry *ke, *ke2 = NULL;
+ struct pf_addr *addr = NULL;
union sockaddr_union mask;
int idx = -1, use_counter = 0;
@@ -2180,12 +2314,20 @@ pfr_kentry_byidx(struct pfr_ktable *kt, int idx, int af)
switch (af) {
#ifdef INET
case AF_INET:
+#ifdef __FreeBSD__
+ kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
+#else
rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
+#endif
return (w.pfrw_kentry);
#endif /* INET */
#ifdef INET6
case AF_INET6:
+#ifdef __FreeBSD__
+ kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
+#else
rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
+#endif
return (w.pfrw_kentry);
#endif /* INET6 */
default:
@@ -2207,8 +2349,16 @@ pfr_dynaddr_update(struct pfr_ktable *kt, struct pfi_dynaddr *dyn)
dyn->pfid_acnt4 = 0;
dyn->pfid_acnt6 = 0;
if (!dyn->pfid_af || dyn->pfid_af == AF_INET)
+#ifdef __FreeBSD__
+ kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
+#else
rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
+#endif
if (!dyn->pfid_af || dyn->pfid_af == AF_INET6)
+#ifdef __FreeBSD__
+ kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
+#else
rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
+#endif
splx(s);
}
diff --git a/sys/contrib/pf/net/pfvar.h b/sys/contrib/pf/net/pfvar.h
index d650f79..f741130 100644
--- a/sys/contrib/pf/net/pfvar.h
+++ b/sys/contrib/pf/net/pfvar.h
@@ -1,4 +1,5 @@
-/* $OpenBSD: pfvar.h,v 1.244 2007/02/23 21:31:51 deraadt Exp $ */
+/* $FreeBSD$ */
+/* $OpenBSD: pfvar.h,v 1.213 2005/03/03 07:13:39 dhartmei Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -37,26 +38,30 @@
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/tree.h>
-#include <sys/rwlock.h>
#include <net/radix.h>
#include <net/route.h>
+#ifdef __FreeBSD__
+#include <net/if_clone.h>
+#include <vm/uma.h>
+#else
#include <netinet/ip_ipsp.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <netinet/in.h>
+#endif
+
#include <netinet/tcp_fsm.h>
struct ip;
-struct ip6_hdr;
+#ifdef __FreeBSD__
+struct inpcb;
+#endif
#define PF_TCPS_PROXY_SRC ((TCP_NSTATES)+0)
#define PF_TCPS_PROXY_DST ((TCP_NSTATES)+1)
-#define PF_MD5_DIGEST_LENGTH 16
-#ifdef MD5_DIGEST_LENGTH
-#if PF_MD5_DIGEST_LENGTH != MD5_DIGEST_LENGTH
-#error
-#endif
-#endif
-
enum { PF_INOUT, PF_IN, PF_OUT };
enum { PF_LAN_EXT, PF_EXT_GWY, PF_ID };
enum { PF_PASS, PF_DROP, PF_SCRUB, PF_NOSCRUB, PF_NAT, PF_NONAT,
@@ -69,8 +74,6 @@ enum { PF_DEBUG_NONE, PF_DEBUG_URGENT, PF_DEBUG_MISC, PF_DEBUG_NOISY };
enum { PF_CHANGE_NONE, PF_CHANGE_ADD_HEAD, PF_CHANGE_ADD_TAIL,
PF_CHANGE_ADD_BEFORE, PF_CHANGE_ADD_AFTER,
PF_CHANGE_REMOVE, PF_CHANGE_GET_TICKET };
-enum { PF_GET_NONE, PF_GET_CLR_CNTR };
-
/*
* Note about PFTM_*: real indices into pf_rule.timeout[] come before
* PFTM_MAX, special cases afterwards. See pf_state_expires().
@@ -82,8 +85,7 @@ enum { PFTM_TCP_FIRST_PACKET, PFTM_TCP_OPENING, PFTM_TCP_ESTABLISHED,
PFTM_OTHER_FIRST_PACKET, PFTM_OTHER_SINGLE,
PFTM_OTHER_MULTIPLE, PFTM_FRAG, PFTM_INTERVAL,
PFTM_ADAPTIVE_START, PFTM_ADAPTIVE_END, PFTM_SRC_NODE,
- PFTM_TS_DIFF, PFTM_MAX, PFTM_PURGE, PFTM_UNLINKED,
- PFTM_UNTIL_PACKET };
+ PFTM_TS_DIFF, PFTM_MAX, PFTM_PURGE, PFTM_UNTIL_PACKET };
/* PFTM default values */
#define PFTM_TCP_FIRST_PACKET_VAL 120 /* First TCP packet */
@@ -106,22 +108,17 @@ enum { PFTM_TCP_FIRST_PACKET, PFTM_TCP_OPENING, PFTM_TCP_ESTABLISHED,
#define PFTM_TS_DIFF_VAL 30 /* Allowed TS diff */
enum { PF_NOPFROUTE, PF_FASTROUTE, PF_ROUTETO, PF_DUPTO, PF_REPLYTO };
-enum { PF_LIMIT_STATES, PF_LIMIT_SRC_NODES, PF_LIMIT_FRAGS,
- PF_LIMIT_TABLES, PF_LIMIT_TABLE_ENTRIES, PF_LIMIT_MAX };
+enum { PF_LIMIT_STATES, PF_LIMIT_SRC_NODES, PF_LIMIT_FRAGS, PF_LIMIT_MAX };
#define PF_POOL_IDMASK 0x0f
enum { PF_POOL_NONE, PF_POOL_BITMASK, PF_POOL_RANDOM,
PF_POOL_SRCHASH, PF_POOL_ROUNDROBIN };
enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL,
- PF_ADDR_TABLE, PF_ADDR_RTLABEL, PF_ADDR_URPFFAILED };
+ PF_ADDR_TABLE, PF_ADDR_RTLABEL };
#define PF_POOL_TYPEMASK 0x0f
#define PF_POOL_STICKYADDR 0x20
#define PF_WSCALE_FLAG 0x80
#define PF_WSCALE_MASK 0x0f
-#define PF_LOG 0x01
-#define PF_LOG_ALL 0x02
-#define PF_LOG_SOCKET_LOOKUP 0x04
-
struct pf_addr {
union {
struct in_addr v4;
@@ -153,6 +150,9 @@ struct pf_addr_wrap {
} a;
char ifname[IFNAMSIZ];
char tblname[PF_TABLE_NAME_SIZE];
+#ifdef __FreeBSD__
+#define RTLABEL_LEN 32
+#endif
char rtlabelname[RTLABEL_LEN];
u_int32_t rtlabel;
} v;
@@ -169,25 +169,100 @@ struct pf_addr_wrap {
#ifdef _KERNEL
struct pfi_dynaddr {
- TAILQ_ENTRY(pfi_dynaddr) entry;
- struct pf_addr pfid_addr4;
- struct pf_addr pfid_mask4;
- struct pf_addr pfid_addr6;
- struct pf_addr pfid_mask6;
- struct pfr_ktable *pfid_kt;
- struct pfi_kif *pfid_kif;
- void *pfid_hook_cookie;
- int pfid_net; /* mask or 128 */
- int pfid_acnt4; /* address count IPv4 */
- int pfid_acnt6; /* address count IPv6 */
- sa_family_t pfid_af; /* rule af */
- u_int8_t pfid_iflags; /* PFI_AFLAG_* */
+ struct pf_addr pfid_addr4;
+ struct pf_addr pfid_mask4;
+ struct pf_addr pfid_addr6;
+ struct pf_addr pfid_mask6;
+ struct pfr_ktable *pfid_kt;
+ struct pfi_kif *pfid_kif;
+ void *pfid_hook_cookie;
+ int pfid_net; /* optional mask, or 128 */
+ int pfid_acnt4; /* address count, IPv4 */
+ int pfid_acnt6; /* address count, IPv6 */
+ sa_family_t pfid_af; /* rule address family */
+ u_int8_t pfid_iflags; /* PFI_AFLAG_* */
};
/*
* Address manipulation macros
*/
+#ifdef __FreeBSD__
+#define splsoftnet() splnet()
+
+#define HTONL(x) (x) = htonl((__uint32_t)(x))
+#define HTONS(x) (x) = htons((__uint16_t)(x))
+#define NTOHL(x) (x) = ntohl((__uint32_t)(x))
+#define NTOHS(x) (x) = ntohs((__uint16_t)(x))
+
+#define PF_NAME "pf"
+
+#define PR_NOWAIT M_NOWAIT
+#define pool_get(p, f) uma_zalloc(*(p), (f))
+#define pool_put(p, o) uma_zfree(*(p), (o))
+
+#define UMA_CREATE(var, type, desc) \
+ var = uma_zcreate(desc, sizeof(type), \
+ NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); \
+ if (var == NULL) break
+#define UMA_DESTROY(var) \
+ if(var) uma_zdestroy(var)
+
+extern struct mtx pf_task_mtx;
+
+#define PF_ASSERT(h) mtx_assert(&pf_task_mtx, (h))
+
+#define PF_LOCK() do { \
+ PF_ASSERT(MA_NOTOWNED); \
+ mtx_lock(&pf_task_mtx); \
+} while(0)
+#define PF_UNLOCK() do { \
+ PF_ASSERT(MA_OWNED); \
+ mtx_unlock(&pf_task_mtx); \
+} while(0)
+
+#define PF_COPYIN(uaddr, kaddr, len, r) do { \
+ PF_UNLOCK(); \
+ r = copyin((uaddr), (kaddr), (len)); \
+ PF_LOCK(); \
+} while(0)
+
+#define PF_COPYOUT(kaddr, uaddr, len, r) do { \
+ PF_UNLOCK(); \
+ r = copyout((kaddr), (uaddr), (len)); \
+ PF_LOCK(); \
+} while(0)
+
+extern void init_pf_mutex(void);
+extern void destroy_pf_mutex(void);
+
+#define PF_MODVER 1
+#define PFLOG_MODVER 1
+#define PFSYNC_MODVER 1
+
+#define PFLOG_MINVER 1
+#define PFLOG_PREFVER PFLOG_MODVER
+#define PFLOG_MAXVER 1
+#define PFSYNC_MINVER 1
+#define PFSYNC_PREFVER PFSYNC_MODVER
+#define PFSYNC_MAXVER 1
+
+/* prototyped for pf_subr.c */
+struct hook_desc {
+ TAILQ_ENTRY(hook_desc) hd_list;
+ void (*hd_fn)(void *);
+ void *hd_arg;
+};
+TAILQ_HEAD(hook_desc_head, hook_desc);
+
+void *hook_establish(struct hook_desc_head *, int, void (*)(void *), void *);
+void hook_disestablish(struct hook_desc_head *, void *);
+void dohooks(struct hook_desc_head *, int);
+
+#define HOOK_REMOVE 0x01
+#define HOOK_FREE 0x02
+#endif /* __FreeBSD__ */
+
#ifdef INET
#ifndef INET6
#define PF_INET_ONLY
@@ -317,26 +392,23 @@ struct pfi_dynaddr {
#endif /* PF_INET6_ONLY */
#endif /* PF_INET_INET6 */
-#define PF_MISMATCHAW(aw, x, af, neg, ifp) \
- ( \
- (((aw)->type == PF_ADDR_NOROUTE && \
- pf_routable((x), (af), NULL)) || \
- (((aw)->type == PF_ADDR_URPFFAILED && (ifp) != NULL && \
- pf_routable((x), (af), (ifp))) || \
- ((aw)->type == PF_ADDR_RTLABEL && \
- !pf_rtlabel_match((x), (af), (aw))) || \
- ((aw)->type == PF_ADDR_TABLE && \
- !pfr_match_addr((aw)->p.tbl, (x), (af))) || \
- ((aw)->type == PF_ADDR_DYNIFTL && \
- !pfi_match_addr((aw)->p.dyn, (x), (af))) || \
- ((aw)->type == PF_ADDR_ADDRMASK && \
- !PF_AZERO(&(aw)->v.a.mask, (af)) && \
- !PF_MATCHA(0, &(aw)->v.a.addr, \
- &(aw)->v.a.mask, (x), (af))))) != \
- (neg) \
+#define PF_MISMATCHAW(aw, x, af, neg) \
+ ( \
+ (((aw)->type == PF_ADDR_NOROUTE && \
+ pf_routable((x), (af))) || \
+ ((aw)->type == PF_ADDR_RTLABEL && \
+ !pf_rtlabel_match((x), (af), (aw))) || \
+ ((aw)->type == PF_ADDR_TABLE && \
+ !pfr_match_addr((aw)->p.tbl, (x), (af))) || \
+ ((aw)->type == PF_ADDR_DYNIFTL && \
+ !pfi_match_addr((aw)->p.dyn, (x), (af))) || \
+ ((aw)->type == PF_ADDR_ADDRMASK && \
+ !PF_AZERO(&(aw)->v.a.mask, (af)) && \
+ !PF_MATCHA(0, &(aw)->v.a.addr, \
+ &(aw)->v.a.mask, (x), (af)))) != \
+ (neg) \
)
-
struct pf_rule_uid {
uid_t uid[2];
u_int8_t op;
@@ -454,7 +526,6 @@ struct pf_os_fingerprint {
#define PF_OSFP_MSS_DC 0x0800 /* TCP MSS dont-care */
#define PF_OSFP_DF 0x1000 /* IPv4 don't fragment bit */
#define PF_OSFP_TS0 0x2000 /* Zero timestamp */
-#define PF_OSFP_INET6 0x4000 /* IPv6 */
u_int8_t fp_optcnt; /* TCP option count */
u_int8_t fp_wscale; /* TCP window scaling */
u_int8_t fp_ttl; /* IPv4 TTL */
@@ -510,11 +581,11 @@ struct pf_rule {
union pf_rule_ptr skip[PF_SKIP_COUNT];
#define PF_RULE_LABEL_SIZE 64
char label[PF_RULE_LABEL_SIZE];
-#define PF_QNAME_SIZE 64
+#define PF_QNAME_SIZE 16
char ifname[IFNAMSIZ];
char qname[PF_QNAME_SIZE];
char pqname[PF_QNAME_SIZE];
-#define PF_TAG_NAME_SIZE 64
+#define PF_TAG_NAME_SIZE 16
char tagname[PF_TAG_NAME_SIZE];
char match_tagname[PF_TAG_NAME_SIZE];
@@ -524,8 +595,8 @@ struct pf_rule {
struct pf_pool rpool;
u_int64_t evaluations;
- u_int64_t packets[2];
- u_int64_t bytes[2];
+ u_int64_t packets;
+ u_int64_t bytes;
struct pfi_kif *kif;
struct pf_anchor *anchor;
@@ -533,7 +604,6 @@ struct pf_rule {
pf_osfp_t os_fingerprint;
- int rtableid;
u_int32_t timeout[PFTM_MAX];
u_int32_t states;
u_int32_t max_states;
@@ -550,8 +620,6 @@ struct pf_rule {
u_int32_t rt_listid;
u_int32_t nr;
u_int32_t prob;
- uid_t cuid;
- pid_t cpid;
u_int16_t return_icmp;
u_int16_t return_icmp6;
@@ -566,7 +634,6 @@ struct pf_rule {
u_int8_t action;
u_int8_t direction;
u_int8_t log;
- u_int8_t logif;
u_int8_t quick;
u_int8_t ifnot;
u_int8_t match_tag_not;
@@ -614,10 +681,9 @@ struct pf_rule {
/* rule flags again */
#define PFRULE_IFBOUND 0x00010000 /* if-bound */
+#define PFRULE_GRBOUND 0x00020000 /* group-bound */
#define PFSTATE_HIWAT 10000 /* default state table size */
-#define PFSTATE_ADAPT_START 6000 /* default adaptive timeout start */
-#define PFSTATE_ADAPT_END 12000 /* default adaptive timeout end */
struct pf_threshold {
@@ -635,8 +701,8 @@ struct pf_src_node {
struct pf_addr raddr;
union pf_rule_ptr rule;
struct pfi_kif *kif;
- u_int64_t bytes[2];
- u_int64_t packets[2];
+ u_int32_t bytes;
+ u_int32_t packets;
u_int32_t states;
u_int32_t conn;
struct pf_threshold conn_rate;
@@ -678,53 +744,26 @@ struct pf_state_peer {
u_int8_t state; /* active state level */
u_int8_t wscale; /* window scaling factor */
u_int16_t mss; /* Maximum segment size option */
- u_int8_t tcp_est; /* Did we reach TCPS_ESTABLISHED */
struct pf_state_scrub *scrub; /* state is scrubbed */
- u_int8_t pad[3];
};
TAILQ_HEAD(pf_state_queue, pf_state);
-/* keep synced with struct pf_state, used in RB_FIND */
-struct pf_state_cmp {
- u_int64_t id;
- u_int32_t creatorid;
- struct pf_state_host lan;
- struct pf_state_host gwy;
- struct pf_state_host ext;
- sa_family_t af;
- u_int8_t proto;
- u_int8_t direction;
- u_int8_t pad;
-};
-
struct pf_state {
u_int64_t id;
- u_int32_t creatorid;
- struct pf_state_host lan;
- struct pf_state_host gwy;
- struct pf_state_host ext;
- sa_family_t af;
- u_int8_t proto;
- u_int8_t direction;
- u_int8_t pad;
- u_int8_t log;
- u_int8_t allow_opts;
- u_int8_t timeout;
- u_int8_t sync_flags;
-#define PFSTATE_NOSYNC 0x01
-#define PFSTATE_FROMSYNC 0x02
-#define PFSTATE_STALE 0x04
union {
struct {
RB_ENTRY(pf_state) entry_lan_ext;
RB_ENTRY(pf_state) entry_ext_gwy;
RB_ENTRY(pf_state) entry_id;
- TAILQ_ENTRY(pf_state) entry_list;
+ TAILQ_ENTRY(pf_state) entry_updates;
struct pfi_kif *kif;
} s;
char ifname[IFNAMSIZ];
} u;
+ struct pf_state_host lan;
+ struct pf_state_host gwy;
+ struct pf_state_host ext;
struct pf_state_peer src;
struct pf_state_peer dst;
union pf_rule_ptr rule;
@@ -734,12 +773,30 @@ struct pf_state {
struct pfi_kif *rt_kif;
struct pf_src_node *src_node;
struct pf_src_node *nat_src_node;
- u_int64_t packets[2];
- u_int64_t bytes[2];
u_int32_t creation;
u_int32_t expire;
u_int32_t pfsync_time;
+ u_int32_t packets[2];
+ u_int32_t bytes[2];
+ u_int32_t creatorid;
u_int16_t tag;
+ sa_family_t af;
+ u_int8_t proto;
+ u_int8_t direction;
+ u_int8_t log;
+ u_int8_t allow_opts;
+ u_int8_t timeout;
+ u_int8_t sync_flags;
+#define PFSTATE_NOSYNC 0x01
+#define PFSTATE_FROMSYNC 0x02
+#define PFSTATE_STALE 0x04
+#ifdef __FreeBSD__
+ u_int8_t local_flags;
+#define PFSTATE_EXPIRING 0x01
+#define PFSTATE_SRC_CONN 0x02
+#else
+ u_int8_t pad;
+#endif
};
TAILQ_HEAD(pf_rulequeue, pf_rule);
@@ -751,8 +808,6 @@ struct pf_ruleset {
struct pf_rulequeue queues[2];
struct {
struct pf_rulequeue *ptr;
- struct pf_rule **ptr_array;
- u_int32_t rcount;
u_int32_t ticket;
int open;
} active, inactive;
@@ -774,7 +829,6 @@ struct pf_anchor {
char path[MAXPATHLEN];
struct pf_ruleset ruleset;
int refcnt; /* anchor rules */
- int match;
};
RB_PROTOTYPE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare);
RB_PROTOTYPE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare);
@@ -841,6 +895,15 @@ struct pfr_tstats {
#define pfrts_name pfrts_t.pfrt_name
#define pfrts_flags pfrts_t.pfrt_flags
+#ifndef _SOCKADDR_UNION_DEFINED
+#define _SOCKADDR_UNION_DEFINED
+union sockaddr_union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+};
+#endif /* _SOCKADDR_UNION_DEFINED */
+
SLIST_HEAD(pfr_kentryworkq, pfr_kentry);
struct pfr_kentry {
struct radix_node pfrke_node[2];
@@ -891,47 +954,56 @@ RB_HEAD(pf_state_tree_ext_gwy, pf_state);
RB_PROTOTYPE(pf_state_tree_ext_gwy, pf_state,
u.s.entry_ext_gwy, pf_state_compare_ext_gwy);
-TAILQ_HEAD(pfi_statehead, pfi_kif);
-RB_HEAD(pfi_ifhead, pfi_kif);
-
-/* keep synced with pfi_kif, used in RB_FIND */
-struct pfi_kif_cmp {
- char pfik_name[IFNAMSIZ];
+struct pfi_if {
+ char pfif_name[IFNAMSIZ];
+ u_int64_t pfif_packets[2][2][2];
+ u_int64_t pfif_bytes[2][2][2];
+ u_int64_t pfif_addcnt;
+ u_int64_t pfif_delcnt;
+ long pfif_tzero;
+ int pfif_states;
+ int pfif_rules;
+ int pfif_flags;
};
+TAILQ_HEAD(pfi_grouphead, pfi_kif);
+TAILQ_HEAD(pfi_statehead, pfi_kif);
+RB_HEAD(pfi_ifhead, pfi_kif);
struct pfi_kif {
- char pfik_name[IFNAMSIZ];
+ struct pfi_if pfik_if;
RB_ENTRY(pfi_kif) pfik_tree;
- u_int64_t pfik_packets[2][2][2];
- u_int64_t pfik_bytes[2][2][2];
- u_int32_t pfik_tzero;
- int pfik_flags;
struct pf_state_tree_lan_ext pfik_lan_ext;
struct pf_state_tree_ext_gwy pfik_ext_gwy;
+ struct pfi_grouphead pfik_grouphead;
+ TAILQ_ENTRY(pfi_kif) pfik_instances;
TAILQ_ENTRY(pfi_kif) pfik_w_states;
+ struct hook_desc_head *pfik_ah_head;
void *pfik_ah_cookie;
+ struct pfi_kif *pfik_parent;
struct ifnet *pfik_ifp;
- struct ifg_group *pfik_group;
int pfik_states;
int pfik_rules;
- TAILQ_HEAD(, pfi_dynaddr) pfik_dynaddrs;
};
-
-enum pfi_kif_refs {
- PFI_KIF_REF_NONE,
- PFI_KIF_REF_STATE,
- PFI_KIF_REF_RULE
-};
-
+#define pfik_name pfik_if.pfif_name
+#define pfik_packets pfik_if.pfif_packets
+#define pfik_bytes pfik_if.pfif_bytes
+#define pfik_tzero pfik_if.pfif_tzero
+#define pfik_flags pfik_if.pfif_flags
+#define pfik_addcnt pfik_if.pfif_addcnt
+#define pfik_delcnt pfik_if.pfif_delcnt
+#define pfik_states pfik_if.pfif_states
+#define pfik_rules pfik_if.pfif_rules
+
+#define PFI_IFLAG_GROUP 0x0001 /* group of interfaces */
+#define PFI_IFLAG_INSTANCE 0x0002 /* single instance */
+#define PFI_IFLAG_CLONABLE 0x0010 /* clonable group */
+#define PFI_IFLAG_DYNAMIC 0x0020 /* dynamic group */
+#define PFI_IFLAG_ATTACHED 0x0040 /* interface attached */
#define PFI_IFLAG_SKIP 0x0100 /* skip filtering on interface */
+#define PFI_IFLAG_SETABLE_MASK 0x0100 /* setable via DIOC{SET,CLR}IFFLAG */
+#define PFI_IFLAG_PLACEHOLDER 0x8000 /* placeholder group/interface */
struct pf_pdesc {
- struct {
- int done;
- uid_t uid;
- gid_t gid;
- pid_t pid;
- } lookup;
u_int64_t tot_len; /* Make Mickey money */
union {
struct tcphdr *tcp;
@@ -949,7 +1021,6 @@ struct pf_pdesc {
struct pf_addr *dst;
struct ether_header
*eh;
- struct pf_mtag *pf_mtag;
u_int16_t *ip_sum;
u_int32_t p_len; /* total length of payload */
u_int16_t flags; /* Let SCRUB trigger behavior in
@@ -1090,7 +1161,6 @@ struct pf_status {
u_int32_t debug;
u_int32_t hostid;
char ifname[IFNAMSIZ];
- u_int8_t pf_chksum[PF_MD5_DIGEST_LENGTH];
};
struct cbq_opts {
@@ -1153,20 +1223,6 @@ struct pf_altq {
u_int32_t qid; /* return value */
};
-#define PF_TAG_GENERATED 0x01
-#define PF_TAG_FRAGCACHE 0x02
-#define PF_TAG_TRANSLATE_LOCALHOST 0x04
-
-struct pf_mtag {
- void *hdr; /* saved hdr pos in mbuf, for ECN */
- u_int rtableid; /* alternate routing table id */
- u_int32_t qid; /* queue id */
- u_int16_t tag; /* tag id */
- u_int8_t flags;
- u_int8_t routed;
- sa_family_t af; /* for ECN */
-};
-
struct pf_tag {
u_int16_t tag; /* tag id */
};
@@ -1183,10 +1239,6 @@ struct pf_tagname {
#define PFFRAG_FRCENT_HIWAT 50000 /* Number of fragment cache entries */
#define PFFRAG_FRCACHE_HIWAT 10000 /* Number of fragment descriptors */
-#define PFR_KTABLE_HIWAT 1000 /* Number of tables */
-#define PFR_KENTRY_HIWAT 200000 /* Number of table entries */
-#define PFR_KENTRY_HIWAT_SMALL 100000 /* Number of table entries (tiny hosts) */
-
/*
* ioctl parameter structures
*/
@@ -1232,13 +1284,6 @@ struct pfioc_state {
struct pf_state state;
};
-struct pfioc_src_node_kill {
- /* XXX returns the number of src nodes killed in psnk_af */
- sa_family_t psnk_af;
- struct pf_rule_addr psnk_src;
- struct pf_rule_addr psnk_dst;
-};
-
struct pfioc_state_kill {
/* XXX returns the number of states killed in psk_af */
sa_family_t psk_af;
@@ -1346,6 +1391,11 @@ struct pfioc_table {
#define pfrio_setflag pfrio_size2
#define pfrio_clrflag pfrio_nadd
+
+#define PFI_FLAG_GROUP 0x0001 /* gets groups of interfaces */
+#define PFI_FLAG_INSTANCE 0x0002 /* gets single interfaces */
+#define PFI_FLAG_ALLMASK 0x0003
+
struct pfioc_iface {
char pfiio_name[IFNAMSIZ];
void *pfiio_buffer;
@@ -1424,9 +1474,16 @@ struct pfioc_iface {
#define DIOCCLRSRCNODES _IO('D', 85)
#define DIOCSETHOSTID _IOWR('D', 86, u_int32_t)
#define DIOCIGETIFACES _IOWR('D', 87, struct pfioc_iface)
+#define DIOCICLRISTATS _IOWR('D', 88, struct pfioc_iface)
#define DIOCSETIFFLAG _IOWR('D', 89, struct pfioc_iface)
#define DIOCCLRIFFLAG _IOWR('D', 90, struct pfioc_iface)
-#define DIOCKILLSRCNODES _IOWR('D', 91, struct pfioc_src_node_kill)
+#ifdef __FreeBSD__
+struct pf_ifspeed {
+ char ifname[IFNAMSIZ];
+ u_int32_t baudrate;
+};
+#define DIOCGIFSPEED _IOWR('D', 91, struct pf_ifspeed)
+#endif
#ifdef _KERNEL
RB_HEAD(pf_src_tree, pf_src_node);
@@ -1437,13 +1494,16 @@ RB_HEAD(pf_state_tree_id, pf_state);
RB_PROTOTYPE(pf_state_tree_id, pf_state,
entry_id, pf_state_compare_id);
extern struct pf_state_tree_id tree_id;
-extern struct pf_state_queue state_list;
+extern struct pf_state_queue state_updates;
+extern struct pf_anchor_global pf_anchors;
+extern struct pf_ruleset pf_main_ruleset;
TAILQ_HEAD(pf_poolqueue, pf_pool);
extern struct pf_poolqueue pf_pools[2];
TAILQ_HEAD(pf_altqqueue, pf_altq);
extern struct pf_altqqueue pf_altqs[2];
extern struct pf_palist pf_pabuf;
+extern struct pfi_kif **pfi_index2kif;
extern u_int32_t ticket_altqs_active;
extern u_int32_t ticket_altqs_inactive;
@@ -1458,25 +1518,38 @@ extern int pf_tbladdr_setup(struct pf_ruleset *,
extern void pf_tbladdr_remove(struct pf_addr_wrap *);
extern void pf_tbladdr_copyout(struct pf_addr_wrap *);
extern void pf_calc_skip_steps(struct pf_rulequeue *);
+#ifdef __FreeBSD__
+extern uma_zone_t pf_src_tree_pl, pf_rule_pl;
+extern uma_zone_t pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
+extern uma_zone_t pfr_ktable_pl, pfr_kentry_pl, pfr_kentry_pl2;
+extern uma_zone_t pf_cache_pl, pf_cent_pl;
+extern uma_zone_t pf_state_scrub_pl;
+extern uma_zone_t pfi_addr_pl;
+#else
extern struct pool pf_src_tree_pl, pf_rule_pl;
extern struct pool pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
extern struct pool pf_state_scrub_pl;
-extern void pf_purge_thread(void *);
-extern void pf_purge_expired_src_nodes(int);
-extern void pf_purge_expired_states(u_int32_t);
-extern void pf_unlink_state(struct pf_state *);
-extern void pf_free_state(struct pf_state *);
+#endif
+extern void pf_purge_timeout(void *);
+extern void pf_purge_expired_src_nodes(void);
+extern void pf_purge_expired_states(void);
+extern void pf_purge_expired_state(struct pf_state *);
extern int pf_insert_state(struct pfi_kif *,
struct pf_state *);
extern int pf_insert_src_node(struct pf_src_node **,
struct pf_rule *, struct pf_addr *,
sa_family_t);
void pf_src_tree_remove_state(struct pf_state *);
-extern struct pf_state *pf_find_state_byid(struct pf_state_cmp *);
-extern struct pf_state *pf_find_state_all(struct pf_state_cmp *key,
+extern struct pf_state *pf_find_state_byid(struct pf_state *);
+extern struct pf_state *pf_find_state_all(struct pf_state *key,
u_int8_t tree, int *more);
extern void pf_print_state(struct pf_state *);
extern void pf_print_flags(u_int8_t);
+extern struct pf_anchor *pf_find_anchor(const char *);
+extern struct pf_ruleset *pf_find_ruleset(const char *);
+extern struct pf_ruleset *pf_find_or_create_ruleset(const char *);
+extern void pf_remove_if_empty_ruleset(
+ struct pf_ruleset *);
extern u_int16_t pf_cksum_fixup(u_int16_t, u_int16_t, u_int16_t,
u_int8_t);
@@ -1488,11 +1561,21 @@ void pf_rm_rule(struct pf_rulequeue *,
struct pf_rule *);
#ifdef INET
+#ifdef __FreeBSD__
+int pf_test(int, struct ifnet *, struct mbuf **, struct ether_header *,
+ struct inpcb *);
+#else
int pf_test(int, struct ifnet *, struct mbuf **, struct ether_header *);
+#endif
#endif /* INET */
#ifdef INET6
+#ifdef __FreeBSD__
+int pf_test6(int, struct ifnet *, struct mbuf **, struct ether_header *,
+ struct inpcb *);
+#else
int pf_test6(int, struct ifnet *, struct mbuf **, struct ether_header *);
+#endif
void pf_poolmask(struct pf_addr *, struct pf_addr*,
struct pf_addr *, struct pf_addr *, u_int8_t);
void pf_addr_inc(struct pf_addr *, sa_family_t);
@@ -1502,8 +1585,7 @@ void *pf_pull_hdr(struct mbuf *, int, void *, int, u_short *, u_short *,
sa_family_t);
void pf_change_a(void *, u_int16_t *, u_int32_t, u_int8_t);
int pflog_packet(struct pfi_kif *, struct mbuf *, sa_family_t, u_int8_t,
- u_int8_t, struct pf_rule *, struct pf_rule *, struct pf_ruleset *,
- struct pf_pdesc *);
+ u_int8_t, struct pf_rule *, struct pf_rule *, struct pf_ruleset *);
int pf_match_addr(u_int8_t, struct pf_addr *, struct pf_addr *,
struct pf_addr *, sa_family_t);
int pf_match(u_int8_t, u_int32_t, u_int32_t, u_int32_t);
@@ -1527,9 +1609,8 @@ int pf_normalize_tcp_stateful(struct mbuf *, int, struct pf_pdesc *,
u_int32_t
pf_state_expires(const struct pf_state *);
void pf_purge_expired_fragments(void);
-int pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *);
+int pf_routable(struct pf_addr *addr, sa_family_t af);
int pf_rtlabel_match(struct pf_addr *, sa_family_t, struct pf_addr_wrap *);
-int pf_socket_lookup(int, struct pf_pdesc *);
void pfr_initialize(void);
int pfr_match_addr(struct pfr_ktable *, struct pf_addr *, sa_family_t);
void pfr_update_stats(struct pfr_ktable *, struct pf_addr *, sa_family_t,
@@ -1554,7 +1635,7 @@ int pfr_add_addrs(struct pfr_table *, struct pfr_addr *, int, int *,
int pfr_del_addrs(struct pfr_table *, struct pfr_addr *, int, int *,
int);
int pfr_set_addrs(struct pfr_table *, struct pfr_addr *, int, int *,
- int *, int *, int *, int, u_int32_t);
+ int *, int *, int *, int);
int pfr_get_addrs(struct pfr_table *, struct pfr_addr *, int *, int);
int pfr_get_astats(struct pfr_table *, struct pfr_astats *, int *, int);
int pfr_clr_astats(struct pfr_table *, struct pfr_addr *, int, int *,
@@ -1567,44 +1648,49 @@ int pfr_ina_commit(struct pfr_table *, u_int32_t, int *, int *, int);
int pfr_ina_define(struct pfr_table *, struct pfr_addr *, int, int *,
int *, u_int32_t, int);
-extern struct pfi_statehead pfi_statehead;
-extern struct pfi_kif *pfi_all;
-
void pfi_initialize(void);
-struct pfi_kif *pfi_kif_get(const char *);
-void pfi_kif_ref(struct pfi_kif *, enum pfi_kif_refs);
-void pfi_kif_unref(struct pfi_kif *, enum pfi_kif_refs);
-int pfi_kif_match(struct pfi_kif *, struct pfi_kif *);
+#ifdef __FreeBSD__
+void pfi_cleanup(void);
+#endif
+void pfi_attach_clone(struct if_clone *);
void pfi_attach_ifnet(struct ifnet *);
void pfi_detach_ifnet(struct ifnet *);
-void pfi_attach_ifgroup(struct ifg_group *);
-void pfi_detach_ifgroup(struct ifg_group *);
-void pfi_group_change(const char *);
-int pfi_match_addr(struct pfi_dynaddr *, struct pf_addr *,
- sa_family_t);
+struct pfi_kif *pfi_lookup_create(const char *);
+struct pfi_kif *pfi_lookup_if(const char *);
+int pfi_maybe_destroy(struct pfi_kif *);
+struct pfi_kif *pfi_attach_rule(const char *);
+void pfi_detach_rule(struct pfi_kif *);
+void pfi_attach_state(struct pfi_kif *);
+void pfi_detach_state(struct pfi_kif *);
int pfi_dynaddr_setup(struct pf_addr_wrap *, sa_family_t);
-void pfi_dynaddr_remove(struct pf_addr_wrap *);
void pfi_dynaddr_copyout(struct pf_addr_wrap *);
+void pfi_dynaddr_remove(struct pf_addr_wrap *);
void pfi_fill_oldstatus(struct pf_status *);
-int pfi_clr_istats(const char *);
-int pfi_get_ifaces(const char *, struct pfi_kif *, int *);
+int pfi_clr_istats(const char *, int *, int);
+int pfi_get_ifaces(const char *, struct pfi_if *, int *, int);
int pfi_set_flags(const char *, int);
int pfi_clear_flags(const char *, int);
+int pfi_match_addr(struct pfi_dynaddr *, struct pf_addr *,
+ sa_family_t);
-u_int16_t pf_tagname2tag(char *);
-void pf_tag2tagname(u_int16_t, char *);
-void pf_tag_ref(u_int16_t);
-void pf_tag_unref(u_int16_t);
-int pf_tag_packet(struct mbuf *, struct pf_mtag *, int, int);
-u_int32_t pf_qname2qid(char *);
-void pf_qid2qname(u_int32_t, char *);
-void pf_qid_unref(u_int32_t);
-struct pf_mtag *pf_find_mtag(struct mbuf *);
-struct pf_mtag *pf_get_mtag(struct mbuf *);
+extern struct pfi_statehead pfi_statehead;
+
+u_int16_t pf_tagname2tag(char *);
+void pf_tag2tagname(u_int16_t, char *);
+void pf_tag_ref(u_int16_t);
+void pf_tag_unref(u_int16_t);
+int pf_tag_packet(struct mbuf *, struct pf_tag *, int);
+u_int32_t pf_qname2qid(char *);
+void pf_qid2qname(u_int32_t, char *);
+void pf_qid_unref(u_int32_t);
extern struct pf_status pf_status;
+
+#ifdef __FreeBSD__
+extern uma_zone_t pf_frent_pl, pf_frag_pl;
+#else
extern struct pool pf_frent_pl, pf_frag_pl;
-extern struct rwlock pf_consistency_lock;
+#endif
struct pf_pool_limit {
void *pp;
@@ -1612,30 +1698,37 @@ struct pf_pool_limit {
};
extern struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX];
-#endif /* _KERNEL */
+#ifdef __FreeBSD__
+struct pf_frent {
+ LIST_ENTRY(pf_frent) fr_next;
+ struct ip *fr_ip;
+ struct mbuf *fr_m;
+};
-extern struct pf_anchor_global pf_anchors;
-extern struct pf_anchor pf_main_anchor;
-#define pf_main_ruleset pf_main_anchor.ruleset
-
-/* these ruleset functions can be linked into userland programs (pfctl) */
-int pf_get_ruleset_number(u_int8_t);
-void pf_init_ruleset(struct pf_ruleset *);
-int pf_anchor_setup(struct pf_rule *,
- const struct pf_ruleset *, const char *);
-int pf_anchor_copyout(const struct pf_ruleset *,
- const struct pf_rule *, struct pfioc_rule *);
-void pf_anchor_remove(struct pf_rule *);
-void pf_remove_if_empty_ruleset(struct pf_ruleset *);
-struct pf_anchor *pf_find_anchor(const char *);
-struct pf_ruleset *pf_find_ruleset(const char *);
-struct pf_ruleset *pf_find_or_create_ruleset(const char *);
-void pf_rs_initialize(void);
+struct pf_frcache {
+ LIST_ENTRY(pf_frcache) fr_next;
+ uint16_t fr_off;
+ uint16_t fr_end;
+};
-#ifdef _KERNEL
-int pf_anchor_copyout(const struct pf_ruleset *,
- const struct pf_rule *, struct pfioc_rule *);
-void pf_anchor_remove(struct pf_rule *);
+struct pf_fragment {
+ RB_ENTRY(pf_fragment) fr_entry;
+ TAILQ_ENTRY(pf_fragment) frag_next;
+ struct in_addr fr_src;
+ struct in_addr fr_dst;
+ u_int8_t fr_p; /* protocol of this fragment */
+ u_int8_t fr_flags; /* status flags */
+ u_int16_t fr_id; /* fragment id for reassemble */
+ u_int16_t fr_max; /* fragment data max */
+ u_int32_t fr_timeout;
+#define fr_queue fr_u.fru_queue
+#define fr_cache fr_u.fru_cache
+ union {
+ LIST_HEAD(pf_fragq, pf_frent) fru_queue; /* buffering */
+ LIST_HEAD(pf_cacheq, pf_frcache) fru_cache; /* non-buf */
+ } fr_u;
+};
+#endif /* (__FreeBSD__) */
#endif /* _KERNEL */
@@ -1647,11 +1740,15 @@ struct pf_osfp_enlist *
const struct tcphdr *);
#endif /* _KERNEL */
struct pf_osfp_enlist *
- pf_osfp_fingerprint_hdr(const struct ip *, const struct ip6_hdr *,
- const struct tcphdr *);
+ pf_osfp_fingerprint_hdr(const struct ip *, const struct tcphdr *);
void pf_osfp_flush(void);
int pf_osfp_get(struct pf_osfp_ioctl *);
+#ifdef __FreeBSD__
+int pf_osfp_initialize(void);
+void pf_osfp_cleanup(void);
+#else
void pf_osfp_initialize(void);
+#endif
int pf_osfp_match(struct pf_osfp_enlist *, pf_osfp_t);
struct pf_os_fingerprint *
pf_osfp_validate(void);
diff --git a/sys/contrib/pf/netinet/in4_cksum.c b/sys/contrib/pf/netinet/in4_cksum.c
index 1c40f2e..24a04d0 100644
--- a/sys/contrib/pf/netinet/in4_cksum.c
+++ b/sys/contrib/pf/netinet/in4_cksum.c
@@ -1,3 +1,4 @@
+/* $FreeBSD$ */
/* $OpenBSD: in4_cksum.c,v 1.7 2003/06/02 23:28:13 millert Exp $ */
/* $KAME: in4_cksum.c,v 1.10 2001/11/30 10:06:15 itojun Exp $ */
/* $NetBSD: in_cksum.c,v 1.13 1996/10/13 02:03:03 christos Exp $ */
@@ -63,52 +64,37 @@
*/
#include <sys/param.h>
-#include <sys/mbuf.h>
#include <sys/systm.h>
-#include <sys/socket.h>
-#include <net/route.h>
+#include <sys/mbuf.h>
+
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
-/*
- * Checksum routine for Internet Protocol family headers (Portable Version).
- * This is only for IPv4 pseudo header checksum.
- * No need to clear non-pseudo-header fields in IPv4 header.
- * len is for actual payload size, and does not include IPv4 header and
- * skipped header chain (off + len should be equal to the whole packet).
- *
- * This routine is very heavily used in the network
- * code and should be modified for each CPU to be as fast as possible.
- */
+#include <machine/in_cksum.h>
#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
+int in4_cksum(struct mbuf *, u_int8_t, int, int);
+
int
-in4_cksum(m, nxt, off, len)
- struct mbuf *m;
- u_int8_t nxt;
- int off, len;
+in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len)
{
- u_int16_t *w;
- int sum = 0;
- int mlen = 0;
- int byte_swapped = 0;
union {
struct ipovly ipov;
u_int16_t w[10];
} u;
union {
- u_int8_t c[2];
- u_int16_t s;
- } s_util;
- union {
u_int16_t s[2];
u_int32_t l;
} l_util;
+ u_int16_t *w;
+ int psum;
+ int sum = 0;
+
if (nxt != 0) {
/* pseudo header */
if (off < sizeof(struct ipovly))
@@ -126,94 +112,9 @@ in4_cksum(m, nxt, off, len)
sum += w[5]; sum += w[6]; sum += w[7]; sum += w[8]; sum += w[9];
}
- /* skip unnecessary part */
- while (m && off > 0) {
- if (m->m_len > off)
- break;
- off -= m->m_len;
- m = m->m_next;
- }
-
- for (;m && len; m = m->m_next) {
- if (m->m_len == 0)
- continue;
- w = (u_int16_t *)(mtod(m, caddr_t) + off);
- if (mlen == -1) {
- /*
- * The first byte of this mbuf is the continuation
- * of a word spanning between this mbuf and the
- * last mbuf.
- *
- * s_util.c[0] is already saved when scanning previous
- * mbuf.
- */
- s_util.c[1] = *(u_int8_t *)w;
- sum += s_util.s;
- w = (u_int16_t *)((u_int8_t *)w + 1);
- mlen = m->m_len - off - 1;
- len--;
- } else
- mlen = m->m_len - off;
- off = 0;
- if (len < mlen)
- mlen = len;
- len -= mlen;
- /*
- * Force to even boundary.
- */
- if ((1 & (long) w) && (mlen > 0)) {
- REDUCE;
- sum <<= 8;
- s_util.c[0] = *(u_int8_t *)w;
- w = (u_int16_t *)((int8_t *)w + 1);
- mlen--;
- byte_swapped = 1;
- }
- /*
- * Unroll the loop to make overhead from
- * branches &c small.
- */
- while ((mlen -= 32) >= 0) {
- sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
- sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
- sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
- sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
- w += 16;
- }
- mlen += 32;
- while ((mlen -= 8) >= 0) {
- sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
- w += 4;
- }
- mlen += 8;
- if (mlen == 0 && byte_swapped == 0)
- continue;
- REDUCE;
- while ((mlen -= 2) >= 0) {
- sum += *w++;
- }
- if (byte_swapped) {
- REDUCE;
- sum <<= 8;
- byte_swapped = 0;
- if (mlen == -1) {
- s_util.c[1] = *(u_int8_t *)w;
- sum += s_util.s;
- mlen = 0;
- } else
- mlen = -1;
- } else if (mlen == -1)
- s_util.c[0] = *(u_int8_t *)w;
- }
- if (len)
- printf("cksum4: out of data\n");
- if (mlen == -1) {
- /* The last mbuf has odd # of bytes. Follow the
- standard (the odd byte may be shifted left by 8 bits
- or not as determined by endian-ness of the machine) */
- s_util.c[1] = 0;
- sum += s_util.s;
- }
+ psum = in_cksum_skip(m, len + off, off);
+ psum = ~psum & 0xffff;
+ sum += psum;
REDUCE;
return (~sum & 0xffff);
}
OpenPOWER on IntegriCloud