summaryrefslogtreecommitdiffstats
path: root/sys/netpfil/pf
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netpfil/pf')
-rw-r--r--sys/netpfil/pf/if_pflog.c6
-rw-r--r--sys/netpfil/pf/if_pfsync.c17
-rw-r--r--sys/netpfil/pf/pf.c907
-rw-r--r--sys/netpfil/pf/pf.h7
-rw-r--r--sys/netpfil/pf/pf_altq.h22
-rw-r--r--sys/netpfil/pf/pf_ioctl.c94
-rw-r--r--sys/netpfil/pf/pf_mtag.h2
-rw-r--r--sys/netpfil/pf/pf_ruleset.c1
8 files changed, 913 insertions, 143 deletions
diff --git a/sys/netpfil/pf/if_pflog.c b/sys/netpfil/pf/if_pflog.c
index 1efd5e2..5c22806 100644
--- a/sys/netpfil/pf/if_pflog.c
+++ b/sys/netpfil/pf/if_pflog.c
@@ -209,7 +209,7 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
return (0);
bzero(&hdr, sizeof(hdr));
- hdr.length = PFLOG_REAL_HDRLEN;
+ hdr.length = PFLOG_HDRLEN;
hdr.af = af;
hdr.action = rm->action;
hdr.reason = reason;
@@ -218,13 +218,16 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
if (am == NULL) {
hdr.rulenr = htonl(rm->nr);
hdr.subrulenr = 1;
+ hdr.ridentifier = rm->cuid;
} else {
hdr.rulenr = htonl(am->nr);
hdr.subrulenr = htonl(rm->nr);
+ hdr.ridentifier = rm->cuid;
if (ruleset != NULL && ruleset->anchor != NULL)
strlcpy(hdr.ruleset, ruleset->anchor->name,
sizeof(hdr.ruleset));
}
+#ifdef PF_USER_INFO
/*
* XXXGL: we avoid pf_socket_lookup() when we are holding
* state lock, since this leads to unsafe LOR.
@@ -239,6 +242,7 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
hdr.pid = NO_PID;
hdr.rule_uid = rm->cuid;
hdr.rule_pid = rm->cpid;
+#endif
hdr.dir = dir;
#ifdef INET
diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c
index 90e6f8f..7936c07 100644
--- a/sys/netpfil/pf/if_pfsync.c
+++ b/sys/netpfil/pf/if_pfsync.c
@@ -185,9 +185,6 @@ struct pfsync_softc {
struct ip_moptions sc_imo;
struct in_addr sc_sync_peer;
uint32_t sc_flags;
-#define PFSYNCF_OK 0x00000001
-#define PFSYNCF_DEFER 0x00000002
-#define PFSYNCF_PUSH 0x00000004
uint8_t sc_maxupdates;
struct ip sc_template;
struct callout sc_tmo;
@@ -365,7 +362,7 @@ pfsync_clone_destroy(struct ifnet *ifp)
callout_drain(&sc->sc_bulkfail_tmo);
callout_drain(&sc->sc_bulk_tmo);
- if (!(sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p)
+ if (!(sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p && V_pfsync_carp_adj > 0)
(*carp_demote_adj_p)(-V_pfsync_carp_adj, "pfsync destroy");
bpfdetach(ifp);
if_detach(ifp);
@@ -1150,7 +1147,7 @@ pfsync_in_bus(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
sc->sc_ureq_sent = 0;
sc->sc_bulk_tries = 0;
callout_stop(&sc->sc_bulkfail_tmo);
- if (!(sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p)
+ if (!(sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p && V_pfsync_carp_adj > 0)
(*carp_demote_adj_p)(-V_pfsync_carp_adj,
"pfsync bulk done");
sc->sc_flags |= PFSYNCF_OK;
@@ -1308,8 +1305,7 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
}
pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer;
pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates;
- pfsyncr.pfsyncr_defer = (PFSYNCF_DEFER ==
- (sc->sc_flags & PFSYNCF_DEFER));
+ pfsyncr.pfsyncr_defer = sc->sc_flags;
PFSYNC_UNLOCK(sc);
return (copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr)));
@@ -1401,7 +1397,7 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
ip->ip_dst.s_addr = sc->sc_sync_peer.s_addr;
/* Request a full state table update. */
- if ((sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p)
+ if ((sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p && V_pfsync_carp_adj > 0)
(*carp_demote_adj_p)(V_pfsync_carp_adj,
"pfsync bulk start");
sc->sc_flags &= ~PFSYNCF_OK;
@@ -1631,6 +1627,7 @@ pfsync_sendout(int schedswi)
sc->sc_ifp->if_obytes += m->m_pkthdr.len;
sc->sc_len = PFSYNC_MINPKT;
+ /* XXX: SHould not drop voluntarily update packets! */
if (!_IF_QFULL(&sc->sc_ifp->if_snd))
_IF_ENQUEUE(&sc->sc_ifp->if_snd, m);
else {
@@ -1776,7 +1773,7 @@ pfsync_undefer_state(struct pf_state *st, int drop)
}
}
- panic("%s: unable to find deferred state", __func__);
+ printf("%s: unable to find deferred state", __func__);
}
static void
@@ -2144,7 +2141,7 @@ pfsync_bulk_fail(void *arg)
sc->sc_ureq_sent = 0;
sc->sc_bulk_tries = 0;
PFSYNC_LOCK(sc);
- if (!(sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p)
+ if (!(sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p && V_pfsync_carp_adj > 0)
(*carp_demote_adj_p)(-V_pfsync_carp_adj,
"pfsync bulk fail");
sc->sc_flags |= PFSYNCF_OK;
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index b3268a2..4a809c8 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -62,6 +62,8 @@ __FBSDID("$FreeBSD$");
#include <net/if.h>
#include <net/if_types.h>
+#include <net/ethernet.h>
+#include <net/if_vlan_var.h>
#include <net/route.h>
#include <net/radix_mpath.h>
#include <net/vnet.h>
@@ -86,6 +88,9 @@ __FBSDID("$FreeBSD$");
#include <netinet/udp_var.h>
#include <netpfil/ipfw/ip_fw_private.h> /* XXX: only for DIR_IN/DIR_OUT */
+#include <netinet/ip_fw.h>
+#include <netinet/ip_dummynet.h>
+#include <netinet/ip_divert.h>
#ifdef INET6
#include <netinet/ip6.h>
@@ -226,6 +231,8 @@ static int pf_state_key_attach(struct pf_state_key *,
static void pf_state_key_detach(struct pf_state *, int);
static int pf_state_key_ctor(void *, int, void *, int);
static u_int32_t pf_tcp_iss(struct pf_pdesc *);
+void pf_rule_to_actions(struct pf_rule *,
+ struct pf_rule_actions *);
static int pf_test_rule(struct pf_rule **, struct pf_state **,
int, struct pfi_kif *, struct mbuf *, int,
struct pf_pdesc *, struct pf_rule **,
@@ -258,7 +265,8 @@ static int pf_test_state_icmp(struct pf_state **, int,
struct pfi_kif *, struct mbuf *, int,
void *, struct pf_pdesc *, u_short *);
static int pf_test_state_other(struct pf_state **, int,
- struct pfi_kif *, struct mbuf *, struct pf_pdesc *);
+ struct pfi_kif *, struct mbuf *, int,
+ struct pf_pdesc *);
static u_int8_t pf_get_wscale(struct mbuf *, int, u_int16_t,
sa_family_t);
static u_int16_t pf_get_mss(struct mbuf *, int, u_int16_t,
@@ -281,6 +289,10 @@ static u_int pf_purge_expired_states(u_int, int);
static void pf_purge_unlinked_rules(void);
static int pf_mtag_uminit(void *, int, int);
static void pf_mtag_free(struct m_tag *);
+static void pf_packet_redo_nat(struct mbuf *, struct pf_pdesc *,
+ int, struct pf_state *, int);
+static void pf_packet_undo_nat(struct mbuf *, struct pf_pdesc *,
+ int, struct pf_state *, int);
#ifdef INET
static void pf_route(struct mbuf **, struct pf_rule *, int,
struct ifnet *, struct pf_state *,
@@ -300,28 +312,36 @@ VNET_DECLARE(int, pf_end_threads);
VNET_DEFINE(struct pf_limit, pf_limits[PF_LIMIT_MAX]);
-#define PACKET_LOOPED(pd) ((pd)->pf_mtag && \
- (pd)->pf_mtag->flags & PF_PACKET_LOOPED)
+#define PACKET_LOOPED(mtag) ((mtag)->flags & PF_PACKET_LOOPED)
+
+#define PF_DIVERT_MAXPACKETS_REACHED() \
+do { \
+ if (r->spare2 && \
+ s->packets[dir == PF_OUT] > r->spare2) \
+ /* fake that divert already happened */ \
+ pd.pf_mtag->flags |= PF_PACKET_LOOPED; \
+} while(0)
#define STATE_LOOKUP(i, k, d, s, pd) \
do { \
(s) = pf_find_state((i), (k), (d)); \
if ((s) == NULL) \
return (PF_DROP); \
- if (PACKET_LOOPED(pd)) \
+ if (PACKET_LOOPED(pd->pf_mtag)) { \
+ if ((s)->key[PF_SK_WIRE] != (s)->key[PF_SK_STACK]) { \
+ pf_packet_redo_nat(m, pd, off, s, direction); \
+ } \
return (PF_PASS); \
+ } \
if ((d) == PF_OUT && \
(((s)->rule.ptr->rt == PF_ROUTETO && \
- (s)->rule.ptr->direction == PF_OUT) || \
- ((s)->rule.ptr->rt == PF_REPLYTO && \
- (s)->rule.ptr->direction == PF_IN)) && \
+ (s)->rule.ptr->direction == PF_OUT)) && \
(s)->rt_kif != NULL && \
(s)->rt_kif != (i)) \
return (PF_PASS); \
} while (0)
-#define BOUND_IFACE(r, k) \
- ((r)->rule_flag & PFRULE_IFBOUND) ? (k) : V_pfi_all
+#define BOUND_IFACE(r, k) k
#define STATE_INC_COUNTERS(s) \
do { \
@@ -407,6 +427,160 @@ pf_addr_cmp(struct pf_addr *a, struct pf_addr *b, sa_family_t af)
return (0);
}
+static void
+pf_packet_undo_nat(struct mbuf *m, struct pf_pdesc *pd, int off,
+ struct pf_state *state, int direction)
+{
+ struct pf_state_key *nk;
+
+ if (state == NULL || state->nat_rule.ptr == NULL)
+ return;
+
+ if (state->nat_rule.ptr->action == PF_RDR ||
+ state->nat_rule.ptr->action == PF_BINAT)
+ nk = (state)->key[PF_SK_WIRE];
+ else
+ nk = (state)->key[PF_SK_STACK];
+
+ switch (pd->proto) {
+ case IPPROTO_TCP: {
+ struct tcphdr *th = pd->hdr.tcp;
+
+ if (direction == PF_OUT) {
+ pf_change_ap(pd->src, &th->th_sport, pd->ip_sum,
+ &th->th_sum, &nk->addr[pd->sidx],
+ nk->port[pd->sidx], 0, pd->af);
+ } else {
+ pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum,
+ &th->th_sum, &nk->addr[pd->didx],
+ nk->port[pd->didx], 0, pd->af);
+ }
+ m_copyback(m, off, sizeof(*th), (caddr_t)th);
+ }
+ break;
+ case IPPROTO_UDP: {
+ struct udphdr *uh = pd->hdr.udp;
+
+ if (direction == PF_OUT) {
+ pf_change_ap(pd->src, &uh->uh_sport, pd->ip_sum,
+ &uh->uh_sum, &nk->addr[pd->sidx],
+ nk->port[pd->sidx], 1, pd->af);
+ } else {
+ pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum,
+ &uh->uh_sum, &nk->addr[pd->didx],
+ nk->port[pd->didx], 1, pd->af);
+ }
+ m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
+ }
+ break;
+ /* case IPPROTO_ICMP: */
+ /* XXX: If we want to do this for icmp is probably wrong!?! */
+ /* break; */
+ default:
+ if (direction == PF_OUT) {
+ switch (pd->af) {
+ case AF_INET:
+ pf_change_a(&pd->src->v4.s_addr,
+ pd->ip_sum, nk->addr[pd->sidx].v4.s_addr,
+ 0);
+ break;
+ case AF_INET6:
+ PF_ACPY(pd->src, &nk->addr[pd->sidx], pd->af);
+ break;
+ }
+ } else {
+ switch (pd->af) {
+ case AF_INET:
+ pf_change_a(&pd->dst->v4.s_addr,
+ pd->ip_sum, nk->addr[pd->didx].v4.s_addr,
+ 0);
+ break;
+ case AF_INET6:
+ PF_ACPY(pd->dst, &nk->addr[pd->didx], pd->af);
+ break;
+ }
+ }
+ break;
+ }
+}
+
+static void
+pf_packet_redo_nat(struct mbuf *m, struct pf_pdesc *pd, int off,
+ struct pf_state *state, int direction)
+{
+ struct pf_state_key *nk;
+
+ if (state == NULL || state->nat_rule.ptr == NULL)
+ return;
+
+ if (state->nat_rule.ptr->action == PF_RDR ||
+ state->nat_rule.ptr->action == PF_BINAT)
+ nk = (state)->key[PF_SK_STACK];
+ else
+ nk = (state)->key[PF_SK_WIRE];
+
+ switch (pd->proto) {
+ case IPPROTO_TCP: {
+ struct tcphdr *th = pd->hdr.tcp;
+
+ if (direction == PF_OUT) {
+ pf_change_ap(pd->src, &th->th_sport, pd->ip_sum,
+ &th->th_sum, &nk->addr[pd->sidx],
+ nk->port[pd->sidx], 0, pd->af);
+ } else {
+ pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum,
+ &th->th_sum, &nk->addr[pd->didx],
+ nk->port[pd->didx], 0, pd->af);
+ }
+ m_copyback(m, off, sizeof(*th), (caddr_t)th);
+ }
+ break;
+ case IPPROTO_UDP: {
+ struct udphdr *uh = pd->hdr.udp;
+
+ if (direction == PF_OUT) {
+ pf_change_ap(pd->src, &uh->uh_sport, pd->ip_sum,
+ &uh->uh_sum, &nk->addr[pd->sidx],
+ nk->port[pd->sidx], 1, pd->af);
+ } else {
+ pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum,
+ &uh->uh_sum, &nk->addr[pd->didx],
+ nk->port[pd->didx], 1, pd->af);
+ }
+ m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
+ }
+ break;
+ /* case IPPROTO_ICMP: */
+ /* XXX: If we want to do this for icmp is probably wrong!?! */
+ /* break; */
+ default:
+ if (direction == PF_OUT) {
+ switch (pd->af) {
+ case AF_INET:
+ pf_change_a(&pd->src->v4.s_addr,
+ pd->ip_sum, nk->addr[pd->sidx].v4.s_addr,
+ 0);
+ break;
+ case AF_INET6:
+ PF_ACPY(pd->src, &nk->addr[pd->sidx], pd->af);
+ break;
+ }
+ } else {
+ switch (pd->af) {
+ case AF_INET:
+ pf_change_a(&pd->dst->v4.s_addr,
+ pd->ip_sum, nk->addr[pd->didx].v4.s_addr,
+ 0);
+ break;
+ case AF_INET6:
+ PF_ACPY(pd->dst, &nk->addr[pd->didx], pd->af);
+ break;
+ }
+ }
+ break;
+ }
+}
+
static __inline uint32_t
pf_hashkey(struct pf_state_key *sk)
{
@@ -440,6 +614,21 @@ pf_hashsrc(struct pf_addr *addr, sa_family_t af)
return (h & pf_srchashmask);
}
+#ifdef ALTQ
+/* XXX: revisit this with ALTQ_WFQ/dummynet */
+static int
+pf_state_hash(struct pf_state *s)
+{
+ u_int32_t hv = (intptr_t)s / sizeof(*s);
+
+ hv ^= crc32(&s->src, sizeof(s->src));
+ hv ^= crc32(&s->dst, sizeof(s->dst));
+ if (hv == 0)
+ hv = 1;
+ return (hv);
+}
+#endif
+
#ifdef INET6
void
pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af)
@@ -1285,7 +1474,7 @@ pf_find_state(struct pfi_kif *kif, struct pf_state_key_cmp *key, u_int dir)
/* List is sorted, if-bound states before floating ones. */
TAILQ_FOREACH(s, &sk->states[idx], key_list[idx])
- if (s->kif == V_pfi_all || s->kif == kif) {
+ {
PF_STATE_LOCK(s);
PF_HASHROW_UNLOCK(kh);
if (s->timeout >= PFTM_MAX) {
@@ -2390,6 +2579,26 @@ pf_send_tcp(struct mbuf *replyto, const struct pf_rule *r, sa_family_t af,
pf_send(pfse);
}
+int
+pf_ieee8021q_setpcp(struct mbuf *m, struct pf_rule *r)
+{
+ struct m_tag *mtag;
+
+ KASSERT(r->ieee8021q_pcp.setpcp & SETPCP_VALID,
+ ("%s with invalid setpcp", __func__));
+
+ mtag = m_tag_locate(m, MTAG_8021Q, MTAG_8021Q_PCP_OUT, NULL);
+ if (mtag == NULL) {
+ mtag = m_tag_alloc(MTAG_8021Q, MTAG_8021Q_PCP_OUT,
+ sizeof(uint8_t), M_NOWAIT);
+ if (mtag == NULL)
+ return (ENOMEM);
+ m_tag_prepend(m, mtag);
+ }
+ *(uint8_t *)(mtag + 1) = (r->ieee8021q_pcp.setpcp & SETPCP_PCP_MASK);
+ return (0);
+}
+
static void
pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
struct pf_rule *r)
@@ -2563,6 +2772,37 @@ pf_match_port(u_int8_t op, u_int16_t a1, u_int16_t a2, u_int16_t p)
return (pf_match(op, a1, a2, p));
}
+int
+pf_match_ieee8021q_pcp(u_int8_t op, u_int8_t pcp1, u_int8_t pcp2,
+ struct mbuf *m)
+{
+ struct m_tag *mtag;
+ uint8_t mpcp;
+
+ /*
+ * Packets without 802.1q headers are treated as having a PCP of 0
+ * (best effort).
+ */
+ mtag = m_tag_locate(m, MTAG_8021Q, MTAG_8021Q_PCP_IN, NULL);
+ if (mtag != NULL)
+ mpcp = *(uint8_t *)(mtag + 1);
+ else
+ mpcp = IEEE8021Q_PCP_BE;
+
+ /*
+ * 802.1q uses a non-traditional ordering, in which 1 < 0, allowing
+ * default 0-tagged ("best effort") traffic to take precedence over
+ * 1-tagged ("background") traffic. Renumber both PCP arguments
+ * before making a comparison so that we can use boring arithmetic
+ * operators.
+ */
+ pcp1 = ((pcp1 == 0) ? 1 : ((pcp1 == 1) ? 0 : pcp1));
+ pcp2 = ((pcp2 == 0) ? 1 : ((pcp2 == 1) ? 0 : pcp2));
+ mpcp = ((mpcp == 0) ? 1 : ((mpcp == 1) ? 0 : mpcp));
+ return (pf_match(op, pcp1, pcp2, mpcp));
+}
+
+#ifdef PF_USER_INFO
static int
pf_match_uid(u_int8_t op, uid_t a1, uid_t a2, uid_t u)
{
@@ -2578,6 +2818,7 @@ pf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g)
return (0);
return (pf_match(op, a1, a2, g));
}
+#endif
int
pf_match_tag(struct mbuf *m, struct pf_rule *r, int *tag, int mtag)
@@ -2771,6 +3012,22 @@ pf_addr_inc(struct pf_addr *addr, sa_family_t af)
}
#endif /* INET6 */
+void
+pf_rule_to_actions(struct pf_rule *r, struct pf_rule_actions *a)
+{
+ if (r->qid)
+ a->qid = r->qid;
+ if (r->pqid)
+ a->pqid = r->pqid;
+ if (r->pdnpipe)
+ a->pdnpipe = r->pdnpipe;
+ if (r->dnpipe)
+ a->dnpipe = r->dnpipe;
+ if (r->free_flags & PFRULE_DN_IS_PIPE)
+ a->flags |= PFRULE_DN_IS_PIPE;
+}
+
+#ifdef PF_USER_INFO
int
pf_socket_lookup(int direction, struct pf_pdesc *pd, struct mbuf *m)
{
@@ -2850,6 +3107,7 @@ pf_socket_lookup(int direction, struct pf_pdesc *pd, struct mbuf *m)
return (1);
}
+#endif
static u_int8_t
pf_get_wscale(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
@@ -3041,12 +3299,14 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
PF_RULES_RASSERT();
+#ifdef PF_USER_INFO
if (inp != NULL) {
INP_LOCK_ASSERT(inp);
pd->lookup.uid = inp->inp_cred->cr_uid;
pd->lookup.gid = inp->inp_cred->cr_groups[0];
pd->lookup.done = 1;
}
+#endif
switch (pd->proto) {
case IPPROTO_TCP:
@@ -3257,7 +3517,11 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
/* icmp only. type always 0 in other cases */
else if (r->code && r->code != icmpcode + 1)
r = TAILQ_NEXT(r, entries);
- else if (r->tos && !(r->tos == pd->tos))
+ else if ((r->rule_flag & PFRULE_TOS) && r->tos &&
+ !(r->tos == pd->tos))
+ r = TAILQ_NEXT(r, entries);
+ else if ((r->rule_flag & PFRULE_DSCP) && r->tos &&
+ !(r->tos == (pd->tos & DSCP_MASK)))
r = TAILQ_NEXT(r, entries);
else if (r->rule_flag & PFRULE_FRAGMENT)
r = TAILQ_NEXT(r, entries);
@@ -3265,6 +3529,7 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
(r->flagset & th->th_flags) != r->flags)
r = TAILQ_NEXT(r, entries);
/* tcp/udp only. uid.op always 0 in other cases */
+#ifdef PF_USER_INFO
else if (r->uid.op && (pd->lookup.done || (pd->lookup.done =
pf_socket_lookup(direction, pd, m), 1)) &&
!pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
@@ -3276,6 +3541,11 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
!pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
pd->lookup.gid))
r = TAILQ_NEXT(r, entries);
+#endif
+ else if (r->ieee8021q_pcp.op &&
+ !pf_match_ieee8021q_pcp(r->ieee8021q_pcp.op,
+ r->ieee8021q_pcp.pcp[0], r->ieee8021q_pcp.pcp[1], m))
+ r = TAILQ_NEXT(r, entries);
else if (r->prob &&
r->prob <= arc4random())
r = TAILQ_NEXT(r, entries);
@@ -3293,10 +3563,20 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
if (r->rtableid >= 0)
rtableid = r->rtableid;
if (r->anchor == NULL) {
- match = 1;
- *rm = r;
- *am = a;
- *rsm = ruleset;
+ if (r->action == PF_MATCH) {
+ r->packets[direction == PF_OUT]++;
+ r->bytes[direction == PF_OUT] += pd->tot_len;
+ pf_rule_to_actions(r, &pd->act);
+ if (r->log)
+ PFLOG_PACKET(kif, m, af,
+ direction, PFRES_MATCH, r,
+ a, ruleset, pd, 1);
+ } else {
+ match = 1;
+ *rm = r;
+ *am = a;
+ *rsm = ruleset;
+ }
if ((*rm)->quick)
break;
r = TAILQ_NEXT(r, entries);
@@ -3315,6 +3595,9 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
REASON_SET(&reason, PFRES_MATCH);
+ /* apply actions for last matching pass/block rule */
+ pf_rule_to_actions(r, &pd->act);
+
if (r->log || (nr != NULL && nr->log)) {
if (rewrite)
m_copyback(m, off, hdrlen, pd->hdr.any);
@@ -3488,6 +3771,11 @@ pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a,
s->state_flags |= PFSTATE_SLOPPY;
s->log = r->log & PF_LOG_ALL;
s->sync_state = PFSYNC_S_NONE;
+ s->qid = pd->act.qid;
+ s->pqid = pd->act.pqid;
+ s->pdnpipe = pd->act.pdnpipe;
+ s->dnpipe = pd->act.dnpipe;
+ s->state_flags |= pd->act.flags;
if (nr != NULL)
s->log |= nr->log & PF_LOG_ALL;
switch (pd->proto) {
@@ -3726,6 +4014,9 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (r->tos && !(r->tos == pd->tos))
r = TAILQ_NEXT(r, entries);
+ else if ((r->rule_flag & PFRULE_DSCP) && r->tos &&
+ !(r->tos == (pd->tos & DSCP_MASK)))
+ r = TAILQ_NEXT(r, entries);
else if (r->os_fingerprint != PF_OSFP_ANY)
r = TAILQ_NEXT(r, entries);
else if (pd->proto == IPPROTO_UDP &&
@@ -3738,6 +4029,10 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
pd->proto == IPPROTO_ICMPV6) &&
(r->type || r->code))
r = TAILQ_NEXT(r, entries);
+ else if (r->ieee8021q_pcp.op &&
+ !pf_match_ieee8021q_pcp(r->ieee8021q_pcp.op,
+ r->ieee8021q_pcp.pcp[0], r->ieee8021q_pcp.pcp[1], m))
+ r = TAILQ_NEXT(r, entries);
else if (r->prob && r->prob <=
(arc4random() % (UINT_MAX - 1) + 1))
r = TAILQ_NEXT(r, entries);
@@ -3746,10 +4041,20 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
r = TAILQ_NEXT(r, entries);
else {
if (r->anchor == NULL) {
- match = 1;
- *rm = r;
- *am = a;
- *rsm = ruleset;
+ if (r->action == PF_MATCH) {
+ r->packets[direction == PF_OUT]++;
+ r->bytes[direction == PF_OUT] += pd->tot_len;
+ pf_rule_to_actions(r, &pd->act);
+ if (r->log)
+ PFLOG_PACKET(kif, m, af,
+ direction, PFRES_MATCH, r,
+ a, ruleset, pd, 1);
+ } else {
+ match = 1;
+ *rm = r;
+ *am = a;
+ *rsm = ruleset;
+ }
if ((*rm)->quick)
break;
r = TAILQ_NEXT(r, entries);
@@ -3768,6 +4073,9 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
REASON_SET(&reason, PFRES_MATCH);
+ /* apply actions for last matching pass/block rule */
+ pf_rule_to_actions(r, &pd->act);
+
if (r->log)
PFLOG_PACKET(kif, m, af, direction, reason, r, a, ruleset, pd,
1);
@@ -5011,7 +5319,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
static int
pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
- struct mbuf *m, struct pf_pdesc *pd)
+ struct mbuf *m, int off, struct pf_pdesc *pd)
{
struct pf_state_peer *src, *dst;
struct pf_state_key_cmp key;
@@ -5289,6 +5597,12 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
ip = mtod(m0, struct ip *);
+ if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
+ if (s)
+ PF_STATE_UNLOCK(s);
+ return;
+ }
+
bzero(&dst, sizeof(dst));
dst.sin_family = AF_INET;
dst.sin_len = sizeof(dst);
@@ -5336,7 +5650,71 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
if (ifp == NULL)
goto bad;
- if (oifp != ifp) {
+ else if (r->rt == PF_REPLYTO || (r->rt == PF_ROUTETO && ifp->if_type == IFT_ENC)) {
+ /* XXX: Copied from ifaof_ifpforaddr() since it mostly will not return NULL! */
+ struct sockaddr_in inaddr;
+ struct sockaddr *addr;
+ struct ifaddr *ifa;
+ char *cp, *cp2, *cp3;
+ char *cplim;
+
+ inaddr.sin_addr = ip->ip_dst;
+ inaddr.sin_family = AF_INET;
+ inaddr.sin_len = sizeof(inaddr);
+ inaddr.sin_port = 0;
+ addr = (struct sockaddr *)&inaddr;
+
+ IF_ADDR_RLOCK(ifp);
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ continue;
+ if (ifa->ifa_netmask == 0) {
+ if ((bcmp(addr, ifa->ifa_addr, addr->sa_len) == 0) ||
+ (ifa->ifa_dstaddr &&
+ (bcmp(addr, ifa->ifa_dstaddr, addr->sa_len) == 0))) {
+ IF_ADDR_RUNLOCK(ifp);
+ return;
+ }
+ continue;
+ }
+ if (ifp->if_flags & IFF_POINTOPOINT) {
+ if (bcmp(addr, ifa->ifa_dstaddr, addr->sa_len) == 0) {
+ IF_ADDR_RUNLOCK(ifp);
+ return;
+ }
+ } else {
+ cp = addr->sa_data;
+ cp2 = ifa->ifa_addr->sa_data;
+ cp3 = ifa->ifa_netmask->sa_data;
+ cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
+ for (; cp3 < cplim; cp3++)
+ if ((*cp++ ^ *cp2++) & *cp3)
+ break;
+ if (cp3 == cplim) {
+ IF_ADDR_RUNLOCK(ifp);
+ return;
+ }
+ }
+ }
+ IF_ADDR_RUNLOCK(ifp);
+ }
+ else if (r->rt == PF_ROUTETO && r->direction == dir && in_localip(ip->ip_dst))
+ return;
+
+ if (s != NULL && r->rt == PF_REPLYTO) {
+ /*
+ * Send it out since it came from state recorded ifp(rt_addr).
+ * Routing table lookup might have chosen not correct interface!
+ */
+ } else if (oifp != ifp) {
+ if (in_broadcast(ip->ip_dst, oifp)) /* XXX: LOCKING of address list?! */
+ return;
+
+ if (s && r->rt == PF_ROUTETO && pd->nat_rule != NULL &&
+ r->direction == PF_OUT && r->direction == dir && pd->pf_mtag->routed < 2) {
+ pf_packet_undo_nat(m0, pd, ntohs(ip->ip_off), s, dir);
+ }
+
if (pf_test(PF_OUT, ifp, &m0, NULL) != PF_PASS)
goto bad;
else if (m0 == NULL)
@@ -5390,6 +5768,9 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
error = EMSGSIZE;
KMOD_IPSTAT_INC(ips_cantfrag);
if (r->rt != PF_DUPTO) {
+ if (s && pd->nat_rule != NULL)
+ pf_packet_undo_nat(m0, pd, ntohs(ip->ip_off), s, dir);
+
icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
ifp->if_mtu);
goto done;
@@ -5469,6 +5850,12 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
ip6 = mtod(m0, struct ip6_hdr *);
+ if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src)) {
+ if (s)
+ PF_STATE_UNLOCK(s);
+ return;
+ }
+
bzero(&dst, sizeof(dst));
dst.sin6_family = AF_INET6;
dst.sin6_len = sizeof(dst);
@@ -5508,8 +5895,70 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
if (ifp == NULL)
goto bad;
+ else if (r->rt == PF_REPLYTO) {
+ /* XXX: Copied from ifaof_ifpforaddr() since it mostly will not return NULL! */
+ struct sockaddr_in6 inaddr6;
+ struct sockaddr *addr;
+ struct ifaddr *ifa;
+ char *cp, *cp2, *cp3;
+ char *cplim;
+
+ inaddr6.sin6_addr = ip6->ip6_dst;
+ inaddr6.sin6_family = AF_INET6;
+ inaddr6.sin6_len = sizeof(inaddr6);
+ inaddr6.sin6_port = 0;
+ inaddr6.sin6_flowinfo = 0;
+ addr = (struct sockaddr *)&inaddr6;
+
+ IF_ADDR_RLOCK(ifp);
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ if (ifa->ifa_netmask == 0) {
+ if ((bcmp(addr, ifa->ifa_addr, addr->sa_len) == 0) ||
+ (ifa->ifa_dstaddr &&
+ (bcmp(addr, ifa->ifa_dstaddr, addr->sa_len) == 0))) {
+ IF_ADDR_RUNLOCK(ifp);
+ return;
+ }
+ continue;
+ }
+ if (ifp->if_flags & IFF_POINTOPOINT) {
+ if (bcmp(addr, ifa->ifa_dstaddr, addr->sa_len) == 0) {
+ IF_ADDR_RUNLOCK(ifp);
+ return;
+ }
+ } else {
+ cp = addr->sa_data;
+ cp2 = ifa->ifa_addr->sa_data;
+ cp3 = ifa->ifa_netmask->sa_data;
+ cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
+ for (; cp3 < cplim; cp3++)
+ if ((*cp++ ^ *cp2++) & *cp3)
+ break;
+ if (cp3 == cplim) {
+ IF_ADDR_RUNLOCK(ifp);
+ return;
+ }
+ }
+ }
+ IF_ADDR_RUNLOCK(ifp);
+ } else if (r->rt == PF_ROUTETO && r->direction == dir && in6_localaddr(&ip6->ip6_dst))
+ return;
+
+ if (s != NULL && r->rt == PF_REPLYTO) {
+ /*
+ * Send it out since it came from state recorded ifp(rt_addr).
+ * Routing table lookup might have chosen not correct interface!
+ */
+ } else if (oifp != ifp) {
+
+ if (s && r->rt == PF_ROUTETO && pd->nat_rule != NULL &&
+ r->direction == PF_OUT && r->direction == dir && pd->pf_mtag->routed < 2) {
+ int ip_off = ((caddr_t)ip6 - m0->m_data) + sizeof(struct ip6_hdr);
+ pf_packet_undo_nat(m0, pd, ip_off, s, dir);
+ }
- if (oifp != ifp) {
if (pf_test6(PF_FWD, ifp, &m0, NULL) != PF_PASS)
goto bad;
else if (m0 == NULL)
@@ -5536,9 +5985,12 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
nd6_output(ifp, ifp, m0, &dst, NULL);
else {
in6_ifstat_inc(ifp, ifs6_in_toobig);
- if (r->rt != PF_DUPTO)
+ if (r->rt != PF_DUPTO) {
+ if (s && pd->nat_rule != NULL)
+ pf_packet_undo_nat(m0, pd, ((caddr_t)ip6 - m0->m_data) + sizeof(struct ip6_hdr), s, dir);
+
icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
- else
+ } else
goto bad;
}
@@ -5704,7 +6156,11 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
struct pf_state *s = NULL;
struct pf_ruleset *ruleset = NULL;
struct pf_pdesc pd;
- int off, dirndx, pqid = 0;
+ int off = 0, dirndx, pqid = 0;
+ int loopedfrom = 0;
+ u_int16_t divertcookie = 0;
+ u_int8_t divflags = 0;
+ struct ip_fw_args dnflow;
M_ASSERTPKTHDR(m);
@@ -5726,26 +6182,33 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
if (m->m_flags & M_SKIP_FIREWALL)
return (PF_PASS);
- pd.pf_mtag = pf_find_mtag(m);
+ pd.pf_mtag = pf_get_mtag(m);
+ if (pd.pf_mtag == NULL) {
+ REASON_SET(&reason, PFRES_MEMORY);
+ log = 1;
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: dropping packet due to failed memory allocation for tags\n"));
+ return PF_DROP;
+ }
PF_RULES_RLOCK();
- if (ip_divert_ptr != NULL &&
+ if ((ip_divert_ptr != NULL || ip_dn_io_ptr != NULL) &&
((ipfwtag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL)) != NULL)) {
struct ipfw_rule_ref *rr = (struct ipfw_rule_ref *)(ipfwtag+1);
- if (rr->info & IPFW_IS_DIVERT && rr->rulenum == 0) {
- if (pd.pf_mtag == NULL &&
- ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) {
- action = PF_DROP;
- goto done;
- }
- pd.pf_mtag->flags |= PF_PACKET_LOOPED;
- m_tag_delete(m, ipfwtag);
+ pd.pf_mtag->flags |= PF_PACKET_LOOPED;
+ if (rr->info & IPFW_IS_DUMMYNET)
+ loopedfrom = 1;
+ if (rr->info & IPFW_IS_DIVERT) {
+ divertcookie = rr->rulenum;
+ divflags = (u_int8_t)(divertcookie >> 8);
+ divertcookie &= ~PFSTATE_DIVERT_MASK;
}
if (pd.pf_mtag && pd.pf_mtag->flags & PF_FASTFWD_OURS_PRESENT) {
m->m_flags |= M_FASTFWD_OURS;
pd.pf_mtag->flags &= ~PF_FASTFWD_OURS_PRESENT;
}
+ m_tag_delete(m, ipfwtag);
} else if (pf_normalize_ip(m0, dir, kif, &reason, &pd) != PF_PASS) {
/* We do IP header normalization and packet reassembly here */
action = PF_DROP;
@@ -5788,6 +6251,10 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
struct tcphdr th;
pd.hdr.tcp = &th;
+ dnflow.f_id._flags = th.th_flags;
+ dnflow.f_id.dst_port = ntohs(th.th_dport);
+ dnflow.f_id.src_port = ntohs(th.th_sport);
+
if (!pf_pull_hdr(m, off, &th, sizeof(th),
&action, &reason, AF_INET)) {
log = action != PF_PASS;
@@ -5802,8 +6269,6 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd,
&reason);
if (action == PF_PASS) {
- if (pfsync_update_state_ptr != NULL)
- pfsync_update_state_ptr(s);
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
@@ -5817,6 +6282,9 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
struct udphdr uh;
pd.hdr.udp = &uh;
+ dnflow.f_id.dst_port = ntohs(uh.uh_dport);
+ dnflow.f_id.src_port = ntohs(uh.uh_sport);
+
if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
&action, &reason, AF_INET)) {
log = action != PF_PASS;
@@ -5831,8 +6299,6 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
}
action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
if (action == PF_PASS) {
- if (pfsync_update_state_ptr != NULL)
- pfsync_update_state_ptr(s);
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
@@ -5854,8 +6320,6 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd,
&reason);
if (action == PF_PASS) {
- if (pfsync_update_state_ptr != NULL)
- pfsync_update_state_ptr(s);
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
@@ -5875,10 +6339,8 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
#endif
default:
- action = pf_test_state_other(&s, dir, kif, m, &pd);
+ action = pf_test_state_other(&s, dir, kif, m, off, &pd);
if (action == PF_PASS) {
- if (pfsync_update_state_ptr != NULL)
- pfsync_update_state_ptr(s);
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
@@ -5899,6 +6361,17 @@ done:
("pf: dropping packet with ip options\n"));
}
+ if (s) {
+ PF_DIVERT_MAXPACKETS_REACHED();
+
+ if (divflags) {
+ s->divert_cookie = divertcookie;
+ s->local_flags |= divflags;
+ } else {
+ divertcookie = s->divert_cookie;
+ divflags = s->local_flags;
+ }
+ }
if (s && s->tag > 0 && pf_tag_packet(m, &pd, s->tag)) {
action = PF_DROP;
REASON_SET(&reason, PFRES_MEMORY);
@@ -5907,22 +6380,150 @@ done:
M_SETFIB(m, r->rtableid);
#ifdef ALTQ
- if (action == PF_PASS && r->qid) {
- if (pd.pf_mtag == NULL &&
- ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) {
- action = PF_DROP;
- REASON_SET(&reason, PFRES_MEMORY);
+ if (s && s->qid) {
+ pd.act.pqid = s->pqid;
+ pd.act.qid = s->qid;
+ } else if (r->qid) {
+ pd.act.pqid = r->pqid;
+ pd.act.qid = r->qid;
+ }
+ if (action == PF_PASS && pd.act.qid) {
+ if (s != NULL)
+ pd.pf_mtag->qid_hash = pf_state_hash(s);
+ if (pqid || (pd.tos & IPTOS_LOWDELAY))
+ pd.pf_mtag->qid = pd.act.pqid;
+ else
+ pd.pf_mtag->qid = pd.act.qid;
+ /* Add hints for ecn. */
+ pd.pf_mtag->hdr = h;
+ }
+#endif /* ALTQ */
+
+ if (divflags & PFSTATE_DIVERT_TAG)
+ pd.pf_mtag->tag = divertcookie;
+ else if (divflags & PFSTATE_DIVERT_ALTQ)
+ pd.pf_mtag->qid = divertcookie;
+ else if (divflags & PFSTATE_DIVERT_ACTION) {
+ struct pf_rule *dlr;
+ action = PF_DROP;
+ if (s)
+ pf_unlink_state(s, PF_ENTER_LOCKED);
+ REASON_SET(&reason, PFRES_DIVERT);
+ log = 1;
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: changing action to with overload from divert.\n"));
+ dlr = r;
+ PFLOG_PACKET(kif, m, AF_INET, dir, reason, dlr, a,
+ ruleset, &pd, (s == NULL));
+ m_freem(*m0);
+ *m0 = NULL;
+ /* NOTE: Fake this to avoid divert giving errors to the application. */
+ return (PF_PASS);
+ }
+
+ if (divflags & PFSTATE_DIVERT_DNCOOKIE) {
+ pd.act.dnpipe = divertcookie;
+ pd.act.pdnpipe = divertcookie;
+ pd.act.flags |= PFRULE_DN_IS_PIPE;
+ } else if (s && (s->dnpipe || s->pdnpipe)) {
+ pd.act.dnpipe = s->dnpipe;
+ pd.act.pdnpipe = s->pdnpipe;
+ pd.act.flags = s->state_flags;
+ } else if (r->dnpipe || r->pdnpipe) {
+ pd.act.dnpipe = r->dnpipe;
+ pd.act.dnpipe = r->pdnpipe;
+ pd.act.flags = r->free_flags;
+ }
+
+ if (pd.act.dnpipe && ip_dn_io_ptr != NULL && loopedfrom != 1) {
+ if (dir != r->direction && pd.act.pdnpipe) {
+ dnflow.rule.info = pd.act.pdnpipe;
+ } else if (dir == r->direction) {
+ dnflow.rule.info = pd.act.dnpipe;
+ } else
+ goto continueprocessing;
+
+ if (pd.act.flags & PFRULE_DN_IS_PIPE)
+ dnflow.rule.info |= IPFW_IS_PIPE;
+ dnflow.f_id.addr_type = 4; /* IPv4 type */
+ dnflow.f_id.proto = pd.proto;
+ if (dir == PF_OUT && s != NULL && s->nat_rule.ptr != NULL &&
+ s->nat_rule.ptr->action == PF_NAT)
+ dnflow.f_id.src_ip =
+ ntohl(s->key[(s->direction == PF_IN)]->
+ addr[(s->direction == PF_OUT)].v4.s_addr);
+ else
+ dnflow.f_id.src_ip = ntohl(h->ip_src.s_addr);
+ dnflow.f_id.dst_ip = ntohl(h->ip_dst.s_addr);
+ dnflow.f_id.extra = dnflow.rule.info;
+
+ if (m->m_flags & M_FASTFWD_OURS) {
+ pd.pf_mtag->flags |= PF_FASTFWD_OURS_PRESENT;
+ m->m_flags &= ~M_FASTFWD_OURS;
+ }
+
+ if (s != NULL && s->nat_rule.ptr)
+ pf_packet_undo_nat(m, &pd, off, s, dir);
+
+ ip_dn_io_ptr(m0,
+ (dir == PF_IN) ? DIR_IN : DIR_OUT,
+ &dnflow);
+ /* This is dummynet fast io processing */
+ if (*m0 != NULL) {
+ m_tag_delete(*m0, m_tag_first(*m0));
+ pd.pf_mtag->flags &= ~PF_PACKET_LOOPED;
+ if (s != NULL && s->nat_rule.ptr)
+ pf_packet_redo_nat(m, &pd, off, s, dir);
} else {
- 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->hdr = h;
+ *m0 = NULL;
+ if (s)
+ PF_STATE_UNLOCK(s);
+ return (action);
}
+ }
+continueprocessing:
+
+ if (action == PF_PASS && r->divert.port && ip_divert_ptr != NULL &&
+ !PACKET_LOOPED(&pd)) {
+ if (!r->spare2 ||
+ (s && s->packets[dir == PF_OUT] <= r->spare2)) {
+ ipfwtag = m_tag_alloc(MTAG_IPFW_RULE, 0,
+ sizeof(struct ipfw_rule_ref), M_NOWAIT | M_ZERO);
+ if (ipfwtag != NULL) {
+ ((struct ipfw_rule_ref *)(ipfwtag+1))->info =
+ ntohs(r->divert.port);
+ ((struct ipfw_rule_ref *)(ipfwtag+1))->rulenum = dir;
+
+ if (s)
+ PF_STATE_UNLOCK(s);
+
+ m_tag_prepend(m, ipfwtag);
+ if (m->m_flags & M_FASTFWD_OURS) {
+ if (pd.pf_mtag == NULL &&
+ ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) {
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_MEMORY);
+ log = 1;
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: failed to allocate tag\n"));
+ }
+ pd.pf_mtag->flags |= PF_FASTFWD_OURS_PRESENT;
+ m->m_flags &= ~M_FASTFWD_OURS;
+ }
+ ip_divert_ptr(*m0, dir == PF_IN ? DIR_IN : DIR_OUT);
+ *m0 = NULL;
+ return (action);
+ } else {
+ /* XXX: ipfw has the same behaviour! */
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_MEMORY);
+ log = 1;
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: failed to allocate divert tag\n"));
+ }
+ }
}
-#endif /* ALTQ */
/*
* connections redirected to loopback should not match sockets
@@ -5933,50 +6534,17 @@ 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)
+ (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
m->m_flags |= M_SKIP_FIREWALL;
- if (action == PF_PASS && r->divert.port && ip_divert_ptr != NULL &&
- !PACKET_LOOPED(&pd)) {
+ if (PACKET_LOOPED(pd.pf_mtag) && !loopedfrom)
+ m->m_flags |= M_FASTFWD_OURS;
+ }
- ipfwtag = m_tag_alloc(MTAG_IPFW_RULE, 0,
- sizeof(struct ipfw_rule_ref), M_NOWAIT | M_ZERO);
- if (ipfwtag != NULL) {
- ((struct ipfw_rule_ref *)(ipfwtag+1))->info =
- ntohs(r->divert.port);
- ((struct ipfw_rule_ref *)(ipfwtag+1))->rulenum = dir;
+ pd.pf_mtag->flags &= ~PF_PACKET_LOOPED;
- if (s)
- PF_STATE_UNLOCK(s);
-
- m_tag_prepend(m, ipfwtag);
- if (m->m_flags & M_FASTFWD_OURS) {
- if (pd.pf_mtag == NULL &&
- ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) {
- action = PF_DROP;
- REASON_SET(&reason, PFRES_MEMORY);
- log = 1;
- DPFPRINTF(PF_DEBUG_MISC,
- ("pf: failed to allocate tag\n"));
- } else {
- pd.pf_mtag->flags |=
- PF_FASTFWD_OURS_PRESENT;
- m->m_flags &= ~M_FASTFWD_OURS;
- }
- }
- ip_divert_ptr(*m0, dir == PF_IN ? DIR_IN : DIR_OUT);
- *m0 = NULL;
-
- return (action);
- } else {
- /* XXX: ipfw has the same behaviour! */
- action = PF_DROP;
- REASON_SET(&reason, PFRES_MEMORY);
- log = 1;
- DPFPRINTF(PF_DEBUG_MISC,
- ("pf: failed to allocate divert tag\n"));
- }
- }
+ if (action == PF_PASS && s != NULL && pfsync_update_state_ptr != NULL)
+ pfsync_update_state_ptr(s);
if (log) {
struct pf_rule *lr;
@@ -6077,7 +6645,10 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
struct pf_state *s = NULL;
struct pf_ruleset *ruleset = NULL;
struct pf_pdesc pd;
- int off, terminal = 0, dirndx, rh_cnt = 0;
+ int off = 0, terminal = 0, dirndx, rh_cnt = 0;
+ int loopedfrom = 0;
+ struct m_tag *dn_tag;
+ struct ip_fw_args dnflow;
int fwdir = dir;
M_ASSERTPKTHDR(m);
@@ -6099,7 +6670,14 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
return (PF_PASS);
memset(&pd, 0, sizeof(pd));
- pd.pf_mtag = pf_find_mtag(m);
+ pd.pf_mtag = pf_get_mtag(m);
+ if (pd.pf_mtag == NULL) {
+ REASON_SET(&reason, PFRES_MEMORY);
+ log = 1;
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: dropping packet due to failed memory allocation for tags\n"));
+ return PF_DROP;
+ }
if (pd.pf_mtag && pd.pf_mtag->flags & PF_TAG_GENERATED)
return (PF_PASS);
@@ -6118,8 +6696,20 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
PF_RULES_RLOCK();
+ if (((ip_dn_io_ptr != NULL) || (ip_divert_ptr != NULL)) &&
+ ((dn_tag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL)) != NULL)) {
+ struct ipfw_rule_ref *rr = (struct ipfw_rule_ref *)(dn_tag+1);
+ pd.pf_mtag->flags |= PF_PACKET_LOOPED;
+ if (rr->info & IPFW_IS_DUMMYNET)
+ loopedfrom = 1;
+ if (pd.pf_mtag->flags & PF_FASTFWD_OURS_PRESENT) {
+ m->m_flags |= M_FASTFWD_OURS;
+ pd.pf_mtag->flags &= ~PF_FASTFWD_OURS_PRESENT;
+ }
+ m_tag_delete(m, dn_tag);
+ }
/* We do IP header normalization and packet reassembly here */
- if (pf_normalize_ip6(m0, dir, kif, &reason, &pd) != PF_PASS) {
+ else if (pf_normalize_ip6(m0, dir, kif, &reason, &pd) != PF_PASS) {
action = PF_DROP;
goto done;
}
@@ -6228,6 +6818,10 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
struct tcphdr th;
pd.hdr.tcp = &th;
+ dnflow.f_id._flags = th.th_flags;
+ dnflow.f_id.dst_port = th.th_dport;
+ dnflow.f_id.src_port = th.th_sport;
+
if (!pf_pull_hdr(m, off, &th, sizeof(th),
&action, &reason, AF_INET6)) {
log = action != PF_PASS;
@@ -6240,8 +6834,6 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd,
&reason);
if (action == PF_PASS) {
- if (pfsync_update_state_ptr != NULL)
- pfsync_update_state_ptr(s);
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
@@ -6255,6 +6847,9 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
struct udphdr uh;
pd.hdr.udp = &uh;
+ dnflow.f_id.dst_port = uh.uh_dport;
+ dnflow.f_id.src_port = uh.uh_sport;
+
if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
&action, &reason, AF_INET6)) {
log = action != PF_PASS;
@@ -6269,8 +6864,6 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
}
action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
if (action == PF_PASS) {
- if (pfsync_update_state_ptr != NULL)
- pfsync_update_state_ptr(s);
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
@@ -6299,8 +6892,6 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
action = pf_test_state_icmp(&s, dir, kif,
m, off, h, &pd, &reason);
if (action == PF_PASS) {
- if (pfsync_update_state_ptr != NULL)
- pfsync_update_state_ptr(s);
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
@@ -6311,10 +6902,8 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
}
default:
- action = pf_test_state_other(&s, dir, kif, m, &pd);
+ action = pf_test_state_other(&s, dir, kif, m, off, &pd);
if (action == PF_PASS) {
- if (pfsync_update_state_ptr != NULL)
- pfsync_update_state_ptr(s);
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
@@ -6348,23 +6937,99 @@ done:
if (r->rtableid >= 0)
M_SETFIB(m, r->rtableid);
+ if ((r->ieee8021q_pcp.setpcp & SETPCP_VALID) &&
+ pf_ieee8021q_setpcp(m, r)) {
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_MEMORY);
+ log = 1;
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: failed to allocate 802.1q mtag\n"));
+ }
+
+ if ((r->ieee8021q_pcp.setpcp & SETPCP_VALID) &&
+ pf_ieee8021q_setpcp(m, r)) {
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_MEMORY);
+ log = 1;
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: failed to allocate 802.1q mtag\n"));
+ }
+
#ifdef ALTQ
- if (action == PF_PASS && r->qid) {
- if (pd.pf_mtag == NULL &&
- ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) {
- action = PF_DROP;
- REASON_SET(&reason, PFRES_MEMORY);
- } else {
- 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->hdr = h;
- }
+ if (s && s->qid) {
+ pd.act.pqid = s->pqid;
+ pd.act.qid = s->qid;
+ } else if (r->qid) {
+ pd.act.pqid = r->pqid;
+ pd.act.qid = r->qid;
+ }
+ if (action == PF_PASS && pd.act.qid) {
+ if (s != NULL)
+ pd.pf_mtag->qid_hash = pf_state_hash(s);
+ if (pd.tos & IPTOS_LOWDELAY)
+ pd.pf_mtag->qid = pd.act.pqid;
+ else
+ pd.pf_mtag->qid = pd.act.qid;
+ /* Add hints for ecn. */
+ pd.pf_mtag->hdr = h;
}
#endif /* ALTQ */
+ if (s && (s->dnpipe || s->pdnpipe)) {
+ pd.act.dnpipe = s->dnpipe;
+ pd.act.pdnpipe = s->pdnpipe;
+ pd.act.flags = s->state_flags;
+ } else if (r->dnpipe || r->pdnpipe) {
+ pd.act.dnpipe = r->dnpipe;
+ pd.act.dnpipe = r->pdnpipe;
+ pd.act.flags = r->free_flags;
+ }
+ if ((pd.act.dnpipe || pd.act.pdnpipe) && ip_dn_io_ptr != NULL && loopedfrom != 1) {
+ if (dir != r->direction && pd.act.pdnpipe) {
+ dnflow.rule.info = pd.act.pdnpipe;
+ } else if (dir == r->direction && pd.act.dnpipe) {
+ dnflow.rule.info = pd.act.dnpipe;
+ } else
+ goto continueprocessing6;
+
+ if (pd.act.flags & PFRULE_DN_IS_PIPE)
+ dnflow.rule.info |= IPFW_IS_PIPE;
+ dnflow.f_id.addr_type = 6; /* IPv4 type */
+ dnflow.f_id.proto = pd.proto;
+ dnflow.f_id.src_ip = 0;
+ dnflow.f_id.dst_ip = 0;
+ if (dir == PF_OUT && s != NULL && s->nat_rule.ptr != NULL &&
+ s->nat_rule.ptr->action == PF_NAT)
+ dnflow.f_id.src_ip6 = s->key[(s->direction == PF_IN)]->addr[0].v6;
+ else
+ dnflow.f_id.src_ip6 = h->ip6_src;
+ dnflow.f_id.dst_ip6 = h->ip6_dst;
+
+ if (s != NULL && s->nat_rule.ptr)
+ pf_packet_undo_nat(m, &pd, off, s, dir);
+
+ ip_dn_io_ptr(m0,
+ ((dir == PF_IN) ? DIR_IN : DIR_OUT) | PROTO_IPV6,
+ &dnflow);
+ /* This is dummynet fast io processing */
+ if (*m0 != NULL) {
+ m_tag_delete(*m0, m_tag_first(*m0));
+ pd.pf_mtag->flags &= ~PF_PACKET_LOOPED;
+ if (s != NULL && s->nat_rule.ptr)
+ pf_packet_redo_nat(m, &pd, off, s, dir);
+ } else {
+ *m0 = NULL;
+ if (s)
+ PF_STATE_UNLOCK(s);
+ return (action);
+ }
+ } else
+ pd.pf_mtag->flags &= ~PF_PACKET_LOOPED;
+continueprocessing6:
+
+ if (action == PF_PASS && s != NULL && pfsync_update_state_ptr != NULL)
+ pfsync_update_state_ptr(s);
+
if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
(s->nat_rule.ptr->action == PF_RDR ||
diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h
index 3a5d2aa..5351786 100644
--- a/sys/netpfil/pf/pf.h
+++ b/sys/netpfil/pf/pf.h
@@ -45,7 +45,8 @@
enum { PF_INOUT, PF_IN, PF_OUT, PF_FWD };
enum { PF_PASS, PF_DROP, PF_SCRUB, PF_NOSCRUB, PF_NAT, PF_NONAT,
- PF_BINAT, PF_NOBINAT, PF_RDR, PF_NORDR, PF_SYNPROXY_DROP, PF_DEFER };
+ PF_BINAT, PF_NOBINAT, PF_RDR, PF_NORDR, PF_SYNPROXY_DROP, PF_DEFER,
+ PF_MATCH };
enum { PF_RULESET_SCRUB, PF_RULESET_FILTER, PF_RULESET_NAT,
PF_RULESET_BINAT, PF_RULESET_RDR, PF_RULESET_MAX };
enum { PF_OP_NONE, PF_OP_IRG, PF_OP_EQ, PF_OP_NE, PF_OP_LT,
@@ -125,7 +126,8 @@ enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL,
#define PFRES_MAXSTATES 12 /* State limit */
#define PFRES_SRCLIMIT 13 /* Source node/conn limit */
#define PFRES_SYNPROXY 14 /* SYN proxy */
-#define PFRES_MAX 15 /* total+1 */
+#define PFRES_DIVERT 15 /* Divert override */
+#define PFRES_MAX 16 /* total+1 */
#define PFRES_NAMES { \
"match", \
@@ -143,6 +145,7 @@ enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL,
"state-limit", \
"src-limit", \
"synproxy", \
+ "divert", \
NULL \
}
diff --git a/sys/netpfil/pf/pf_altq.h b/sys/netpfil/pf/pf_altq.h
index eda0965..184e453 100644
--- a/sys/netpfil/pf/pf_altq.h
+++ b/sys/netpfil/pf/pf_altq.h
@@ -65,6 +65,26 @@ struct hfsc_opts {
int flags;
};
+/*
+ * XXX this needs some work
+ */
+struct fairq_opts {
+ u_int nbuckets;
+ u_int hogs_m1;
+ int flags;
+
+ /* link sharing service curve */
+ u_int lssc_m1;
+ u_int lssc_d;
+ u_int lssc_m2;
+};
+
+struct codel_opts {
+ u_int target;
+ u_int interval;
+ int ecn;
+};
+
struct pf_altq {
char ifname[IFNAMSIZ];
@@ -91,6 +111,8 @@ struct pf_altq {
struct cbq_opts cbq_opts;
struct priq_opts priq_opts;
struct hfsc_opts hfsc_opts;
+ struct fairq_opts fairq_opts;
+ struct codel_opts codel_opts;
} pq_u;
uint32_t qid; /* return value */
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index a3528f0..5990cf6 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -350,7 +350,9 @@ pf_empty_pool(struct pf_palist *poola)
pfi_dynaddr_remove(pa->addr.p.dyn);
break;
case PF_ADDR_TABLE:
- pfr_detach_table(pa->addr.p.tbl);
+ /* XXX: this could be unfinished pooladdr on pabuf */
+ if (pa->addr.p.tbl != NULL)
+ pfr_detach_table(pa->addr.p.tbl);
break;
}
if (pa->kif)
@@ -1002,6 +1004,8 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
case DIOCCLRRULECTRS:
case DIOCGETLIMIT:
case DIOCGETALTQS:
+ case DIOCGETNAMEDALTQ:
+ case DIOCGETNAMEDTAG:
case DIOCGETALTQ:
case DIOCGETQSTATS:
case DIOCGETRULESETS:
@@ -1048,6 +1052,8 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
case DIOCGETTIMEOUT:
case DIOCGETLIMIT:
case DIOCGETALTQS:
+ case DIOCGETNAMEDALTQ:
+ case DIOCGETNAMEDTAG:
case DIOCGETALTQ:
case DIOCGETQSTATS:
case DIOCGETRULESETS:
@@ -1162,7 +1168,9 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
rule->states_cur = counter_u64_alloc(M_WAITOK);
rule->states_tot = counter_u64_alloc(M_WAITOK);
rule->src_nodes = counter_u64_alloc(M_WAITOK);
+#ifdef PF_USER_INFO
rule->cuid = td->td_ucred->cr_ruid;
+#endif
rule->cpid = td->td_proc ? td->td_proc->p_pid : 0;
TAILQ_INIT(&rule->rpool.list);
@@ -1188,7 +1196,6 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
V_ticket_pabuf));
ERROUT(EBUSY);
}
-
tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
pf_rulequeue);
if (tail)
@@ -1267,8 +1274,29 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
}
rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
+#ifndef PF_USER_INFO
+ if (rule->cuid) {
+ tail = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
+ while ((tail != NULL) && (tail->cuid != rule->cuid))
+ tail = TAILQ_NEXT(tail, entries);
+ if (tail != NULL) {
+ rule->evaluations = tail->evaluations;
+ rule->packets[0] = tail->packets[0];
+ rule->packets[1] = tail->packets[1];
+ rule->bytes[0] = tail->bytes[0];
+ rule->bytes[1] = tail->bytes[1];
+ } else {
+ rule->evaluations = rule->packets[0] = rule->packets[1] =
+ rule->bytes[0] = rule->bytes[1] = 0;
+ }
+ } else {
+ rule->evaluations = rule->packets[0] = rule->packets[1] =
+ rule->bytes[0] = rule->bytes[1] = 0;
+ }
+#else
rule->evaluations = rule->packets[0] = rule->packets[1] =
rule->bytes[0] = rule->bytes[1] = 0;
+#endif
TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
rule, entries);
ruleset->rules[rs_num].inactive.rcount++;
@@ -1418,7 +1446,9 @@ DIOCADDRULE_error:
newrule->states_cur = counter_u64_alloc(M_WAITOK);
newrule->states_tot = counter_u64_alloc(M_WAITOK);
newrule->src_nodes = counter_u64_alloc(M_WAITOK);
+#ifdef PF_USER_INFO
newrule->cuid = td->td_ucred->cr_ruid;
+#endif
newrule->cpid = td->td_proc ? td->td_proc->p_pid : 0;
TAILQ_INIT(&newrule->rpool.list);
}
@@ -1705,6 +1735,30 @@ relock_DIOCKILLSTATES:
break;
}
+ case DIOCKILLSCHEDULE: {
+ struct pf_state *state;
+ struct pfioc_schedule_kill *psk = (struct pfioc_schedule_kill *)addr;
+ int killed = 0;
+ u_int i;
+
+ for (i = 0; i <= pf_hashmask; i++) {
+ struct pf_idhash *ih = &V_pf_idhash[i];
+
+relock_DIOCKILLSCHEDULE:
+ PF_HASHROW_LOCK(ih);
+ LIST_FOREACH(state, &ih->states, entry) {
+ if (!strcmp(psk->schedule, state->rule.ptr->schedule)) {
+ pf_unlink_state(state, PF_ENTER_LOCKED);
+ killed++;
+ goto relock_DIOCKILLSCHEDULE;
+ }
+ }
+ PF_HASHROW_UNLOCK(ih);
+ }
+ psk->numberkilled = killed;
+ break;
+ }
+
case DIOCADDSTATE: {
struct pfioc_state *ps = (struct pfioc_state *)addr;
struct pfsync_state *sp = &ps->state;
@@ -2095,6 +2149,16 @@ DIOCGETSTATES_full:
break;
}
+ case DIOCGETNAMEDALTQ: {
+ struct pfioc_ruleset *pa = (struct pfioc_ruleset *)addr;
+
+ if (pa->name[0]) {
+ pa->nr = pf_qname2qid(pa->name);
+ pf_qid_unref(pa->nr);
+ }
+ break;
+ }
+
case DIOCGETALTQS: {
struct pfioc_altq *pa = (struct pfioc_altq *)addr;
struct pf_altq *altq;
@@ -2180,6 +2244,16 @@ DIOCGETSTATES_full:
}
#endif /* ALTQ */
+ case DIOCGETNAMEDTAG: {
+ /* Little abuse. */
+ struct pfioc_ruleset *pa = (struct pfioc_ruleset *)addr;
+
+ if (pa->name[0])
+ pa->nr = pf_tagname2tag(pa->name);
+
+ break;
+ }
+
case DIOCBEGINADDRS: {
struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
@@ -3561,9 +3635,9 @@ pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
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.csum_flags & CSUM_DELAY_DATA_IPV6) {
+ in6_delayed_cksum(*m, (*m)->m_pkthdr.len - sizeof(struct ip6_hdr), sizeof(struct ip6_hdr));
+ (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6;
}
chk = pf_test(PF_OUT, ifp, m, inp);
@@ -3639,8 +3713,8 @@ hook_pf(void)
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);
+ pfil_add_named_hook(pf_check_in, NULL, "pf", PFIL_IN | PFIL_WAITOK, pfh_inet);
+ pfil_add_named_hook(pf_check_out, NULL, "pf", PFIL_OUT | PFIL_WAITOK, pfh_inet);
#endif
#ifdef INET6
pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
@@ -3653,8 +3727,10 @@ hook_pf(void)
#endif
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);
+ pfil_add_named_hook(pf_check6_in, NULL, "pf", PFIL_IN | PFIL_WAITOK,
+ pfh_inet6);
+ pfil_add_named_hook(pf_check6_out, NULL, "pf", PFIL_OUT | PFIL_WAITOK,
+ pfh_inet6);
#endif
V_pf_pfil_hooked = 1;
diff --git a/sys/netpfil/pf/pf_mtag.h b/sys/netpfil/pf/pf_mtag.h
index 3aacb2e..3ec08a2 100644
--- a/sys/netpfil/pf/pf_mtag.h
+++ b/sys/netpfil/pf/pf_mtag.h
@@ -44,9 +44,11 @@
struct pf_mtag {
void *hdr; /* saved hdr pos in mbuf, for ECN */
u_int32_t qid; /* queue id */
+ u_int32_t qid_hash; /* queue hashid used by WFQ like algos */
u_int16_t tag; /* tag id */
u_int8_t flags;
u_int8_t routed;
+ u_int8_t af; /* for ECN */
};
static __inline struct pf_mtag *
diff --git a/sys/netpfil/pf/pf_ruleset.c b/sys/netpfil/pf/pf_ruleset.c
index 384e42b..2274359 100644
--- a/sys/netpfil/pf/pf_ruleset.c
+++ b/sys/netpfil/pf/pf_ruleset.c
@@ -120,6 +120,7 @@ pf_get_ruleset_number(u_int8_t action)
return (PF_RULESET_SCRUB);
break;
case PF_PASS:
+ case PF_MATCH:
case PF_DROP:
return (PF_RULESET_FILTER);
break;
OpenPOWER on IntegriCloud