summaryrefslogtreecommitdiffstats
path: root/sys/contrib/pf/net/pf.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/pf/net/pf.c')
-rw-r--r--sys/contrib/pf/net/pf.c1215
1 files changed, 849 insertions, 366 deletions
diff --git a/sys/contrib/pf/net/pf.c b/sys/contrib/pf/net/pf.c
index a2db3d4..dc263d1 100644
--- a/sys/contrib/pf/net/pf.c
+++ b/sys/contrib/pf/net/pf.c
@@ -1,5 +1,4 @@
-/* $OpenBSD: pf.c,v 1.433.2.2 2004/07/17 03:22:34 brad Exp $ */
-/* add $OpenBSD: pf.c,v 1.448 2004/05/11 07:34:11 dhartmei Exp $ */
+/* $OpenBSD: pf.c,v 1.483 2005/03/15 17:38:43 dhartmei Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -69,6 +68,7 @@
#include <netinet/tcp_var.h>
#include <netinet/udp_var.h>
#include <netinet/icmp_var.h>
+#include <netinet/if_ether.h>
#include <dev/rndvar.h>
#include <net/pfvar.h>
@@ -92,7 +92,7 @@
* Global variables
*/
-struct pf_anchorqueue pf_anchors;
+struct pf_anchor_global pf_anchors;
struct pf_ruleset pf_main_ruleset;
struct pf_altqqueue pf_altqs[2];
struct pf_palist pf_pabuf;
@@ -107,12 +107,22 @@ u_int32_t ticket_pabuf;
struct timeout pf_expire_to; /* expire timeout */
+struct pf_anchor_stackframe {
+ struct pf_ruleset *rs;
+ struct pf_rule *r;
+ struct pf_anchor_node *parent;
+ struct pf_anchor *child;
+} pf_anchor_stack[64];
+
struct pool pf_src_tree_pl, pf_rule_pl;
struct pool pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
void pf_print_host(struct pf_addr *, u_int16_t, u_int8_t);
-void pf_print_state(struct pf_state *);
-void pf_print_flags(u_int8_t);
+
+void pf_init_threshold(struct pf_threshold *, u_int32_t,
+ u_int32_t);
+void pf_add_threshold(struct pf_threshold *);
+int pf_check_threshold(struct pf_threshold *);
void pf_change_ap(struct pf_addr *, u_int16_t *,
u_int16_t *, u_int16_t *, struct pf_addr *,
@@ -128,7 +138,8 @@ void pf_change_icmp(struct pf_addr *, u_int16_t *,
void pf_send_tcp(const struct pf_rule *, sa_family_t,
const struct pf_addr *, const struct pf_addr *,
u_int16_t, u_int16_t, u_int32_t, u_int32_t,
- u_int8_t, u_int16_t, u_int16_t, u_int8_t);
+ u_int8_t, u_int16_t, u_int16_t, u_int8_t, int,
+ struct ether_header *, struct ifnet *);
void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t,
sa_family_t, struct pf_rule *);
struct pf_rule *pf_match_translation(struct pf_pdesc *, struct mbuf *,
@@ -143,19 +154,19 @@ struct pf_rule *pf_get_translation(struct pf_pdesc *, struct mbuf *,
int pf_test_tcp(struct pf_rule **, struct pf_state **,
int, struct pfi_kif *, struct mbuf *, int,
void *, struct pf_pdesc *, struct pf_rule **,
- struct pf_ruleset **);
+ struct pf_ruleset **, struct ifqueue *);
int pf_test_udp(struct pf_rule **, struct pf_state **,
int, struct pfi_kif *, struct mbuf *, int,
void *, struct pf_pdesc *, struct pf_rule **,
- struct pf_ruleset **);
+ struct pf_ruleset **, struct ifqueue *);
int pf_test_icmp(struct pf_rule **, struct pf_state **,
int, struct pfi_kif *, struct mbuf *, int,
void *, struct pf_pdesc *, struct pf_rule **,
- struct pf_ruleset **);
+ struct pf_ruleset **, struct ifqueue *);
int pf_test_other(struct pf_rule **, struct pf_state **,
int, struct pfi_kif *, struct mbuf *, int, void *,
struct pf_pdesc *, struct pf_rule **,
- struct pf_ruleset **);
+ struct pf_ruleset **, struct ifqueue *);
int pf_test_fragment(struct pf_rule **, int,
struct pfi_kif *, struct mbuf *, void *,
struct pf_pdesc *, struct pf_rule **,
@@ -168,12 +179,12 @@ int pf_test_state_udp(struct pf_state **, int,
void *, struct pf_pdesc *);
int pf_test_state_icmp(struct pf_state **, int,
struct pfi_kif *, struct mbuf *, int,
- void *, struct pf_pdesc *);
+ void *, struct pf_pdesc *, u_short *);
int pf_test_state_other(struct pf_state **, int,
struct pfi_kif *, struct pf_pdesc *);
struct pf_tag *pf_get_tag(struct mbuf *);
int pf_match_tag(struct mbuf *, struct pf_rule *,
- struct pf_rule *, struct pf_tag *, int *);
+ struct pf_tag **, int *);
void pf_hash(struct pf_addr *, struct pf_addr *,
struct pf_poolhashkey *, sa_family_t);
int pf_map_addr(u_int8_t, struct pf_rule *,
@@ -204,6 +215,8 @@ int pf_addr_wrap_neq(struct pf_addr_wrap *,
static int pf_add_mbuf_tag(struct mbuf *, u_int);
struct pf_state *pf_find_state_recurse(struct pfi_kif *,
struct pf_state *, u_int8_t);
+int pf_src_connlimit(struct pf_state **);
+int pf_check_congestion(struct ifqueue *);
struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
{ &pf_state_pl, PFSTATE_HIWAT },
@@ -214,12 +227,12 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
#define STATE_LOOKUP() \
do { \
if (direction == PF_IN) \
- *state = pf_find_state_recurse( \
+ *state = pf_find_state_recurse( \
kif, &key, PF_EXT_GWY); \
else \
- *state = pf_find_state_recurse( \
+ *state = pf_find_state_recurse( \
kif, &key, PF_LAN_EXT); \
- if (*state == NULL) \
+ if (*state == NULL || (*state)->timeout == PFTM_PURGE) \
return (PF_DROP); \
if (direction == PF_OUT && \
(((*state)->rule.ptr->rt == PF_ROUTETO && \
@@ -243,6 +256,24 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
((r)->rule_flag & PFRULE_GRBOUND) ? (k)->pfik_parent : \
(k)->pfik_parent->pfik_parent)
+#define STATE_INC_COUNTERS(s) \
+ do { \
+ s->rule.ptr->states++; \
+ if (s->anchor.ptr != NULL) \
+ s->anchor.ptr->states++; \
+ if (s->nat_rule.ptr != NULL) \
+ s->nat_rule.ptr->states++; \
+ } while (0)
+
+#define STATE_DEC_COUNTERS(s) \
+ do { \
+ if (s->nat_rule.ptr != NULL) \
+ s->nat_rule.ptr->states--; \
+ if (s->anchor.ptr != NULL) \
+ s->anchor.ptr->states--; \
+ s->rule.ptr->states--; \
+ } while (0)
+
static __inline int pf_src_compare(struct pf_src_node *, struct pf_src_node *);
static __inline int pf_state_compare_lan_ext(struct pf_state *,
struct pf_state *);
@@ -250,6 +281,7 @@ static __inline int pf_state_compare_ext_gwy(struct pf_state *,
struct pf_state *);
static __inline int pf_state_compare_id(struct pf_state *,
struct pf_state *);
+static __inline int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
struct pf_src_tree tree_src_tracking;
@@ -263,6 +295,8 @@ RB_GENERATE(pf_state_tree_ext_gwy, pf_state,
u.s.entry_ext_gwy, pf_state_compare_ext_gwy);
RB_GENERATE(pf_state_tree_id, pf_state,
u.s.entry_id, pf_state_compare_id);
+RB_GENERATE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare);
+RB_GENERATE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare);
static __inline int
pf_src_compare(struct pf_src_node *a, struct pf_src_node *b)
@@ -459,6 +493,14 @@ pf_state_compare_id(struct pf_state *a, struct pf_state *b)
return (0);
}
+static __inline int
+pf_anchor_compare(struct pf_anchor *a, struct pf_anchor *b)
+{
+ int c = strcmp(a->path, b->path);
+
+ return (c ? (c < 0 ? -1 : 1) : 0);
+}
+
#ifdef INET6
void
pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af)
@@ -477,7 +519,7 @@ pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af)
break;
}
}
-#endif
+#endif /* INET6 */
struct pf_state *
pf_find_state_byid(struct pf_state *key)
@@ -553,6 +595,131 @@ pf_find_state_all(struct pf_state *key, u_int8_t tree, int *more)
}
}
+void
+pf_init_threshold(struct pf_threshold *threshold,
+ u_int32_t limit, u_int32_t seconds)
+{
+ threshold->limit = limit * PF_THRESHOLD_MULT;
+ threshold->seconds = seconds;
+ threshold->count = 0;
+ threshold->last = time_second;
+}
+
+void
+pf_add_threshold(struct pf_threshold *threshold)
+{
+ u_int32_t t = time_second, diff = t - threshold->last;
+
+ if (diff >= threshold->seconds)
+ threshold->count = 0;
+ else
+ threshold->count -= threshold->count * diff /
+ threshold->seconds;
+ threshold->count += PF_THRESHOLD_MULT;
+ threshold->last = t;
+}
+
+int
+pf_check_threshold(struct pf_threshold *threshold)
+{
+ return (threshold->count > threshold->limit);
+}
+
+int
+pf_src_connlimit(struct pf_state **state)
+{
+ struct pf_state *s;
+ int bad = 0;
+
+ (*state)->src_node->conn++;
+ pf_add_threshold(&(*state)->src_node->conn_rate);
+
+ if ((*state)->rule.ptr->max_src_conn &&
+ (*state)->rule.ptr->max_src_conn <
+ (*state)->src_node->conn) {
+ pf_status.lcounters[LCNT_SRCCONN]++;
+ bad++;
+ }
+
+ if ((*state)->rule.ptr->max_src_conn_rate.limit &&
+ pf_check_threshold(&(*state)->src_node->conn_rate)) {
+ pf_status.lcounters[LCNT_SRCCONNRATE]++;
+ bad++;
+ }
+
+ if (!bad)
+ return (0);
+
+ if ((*state)->rule.ptr->overload_tbl) {
+ struct pfr_addr p;
+ u_int32_t killed = 0;
+
+ pf_status.lcounters[LCNT_OVERLOAD_TABLE]++;
+ if (pf_status.debug >= PF_DEBUG_MISC) {
+ printf("pf_src_connlimit: blocking address ");
+ pf_print_host(&(*state)->src_node->addr, 0,
+ (*state)->af);
+ }
+
+ bzero(&p, sizeof(p));
+ p.pfra_af = (*state)->af;
+ switch ((*state)->af) {
+#ifdef INET
+ case AF_INET:
+ p.pfra_net = 32;
+ p.pfra_ip4addr = (*state)->src_node->addr.v4;
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ p.pfra_net = 128;
+ p.pfra_ip6addr = (*state)->src_node->addr.v6;
+ break;
+#endif /* INET6 */
+ }
+
+ pfr_insert_kentry((*state)->rule.ptr->overload_tbl,
+ &p, time_second);
+
+ /* kill existing states if that's required. */
+ if ((*state)->rule.ptr->flush) {
+ pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++;
+
+ RB_FOREACH(s, pf_state_tree_id, &tree_id) {
+ /*
+ * Kill states from this source. (Only those
+ * from the same rule if PF_FLUSH_GLOBAL is not
+ * set)
+ */
+ if (s->af == (*state)->af &&
+ (((*state)->direction == PF_OUT &&
+ PF_AEQ(&(*state)->src_node->addr,
+ &s->lan.addr, s->af)) ||
+ ((*state)->direction == PF_IN &&
+ PF_AEQ(&(*state)->src_node->addr,
+ &s->ext.addr, s->af))) &&
+ ((*state)->rule.ptr->flush &
+ PF_FLUSH_GLOBAL ||
+ (*state)->rule.ptr == s->rule.ptr)) {
+ s->timeout = PFTM_PURGE;
+ s->src.state = s->dst.state =
+ TCPS_CLOSED;
+ killed++;
+ }
+ }
+ if (pf_status.debug >= PF_DEBUG_MISC)
+ printf(", %u states killed", killed);
+ }
+ if (pf_status.debug >= PF_DEBUG_MISC)
+ printf("\n");
+ }
+
+ /* kill this state */
+ (*state)->timeout = PFTM_PURGE;
+ (*state)->src.state = (*state)->dst.state = TCPS_CLOSED;
+ return (1);
+}
+
int
pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
struct pf_addr *src, sa_family_t af)
@@ -574,9 +741,16 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
if (!rule->max_src_nodes ||
rule->src_nodes < rule->max_src_nodes)
(*sn) = pool_get(&pf_src_tree_pl, PR_NOWAIT);
+ else
+ pf_status.lcounters[LCNT_SRCNODES]++;
if ((*sn) == NULL)
return (-1);
bzero(*sn, sizeof(struct pf_src_node));
+
+ pf_init_threshold(&(*sn)->conn_rate,
+ rule->max_src_conn_rate.limit,
+ rule->max_src_conn_rate.seconds);
+
(*sn)->af = af;
if (rule->rule_flag & PFRULE_RULESRCTRACK ||
rule->rpool.opts & PF_POOL_STICKYADDR)
@@ -594,7 +768,7 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
pool_put(&pf_src_tree_pl, *sn);
return (-1);
}
- (*sn)->creation = time.tv_sec;
+ (*sn)->creation = time_second;
(*sn)->ruletype = rule->action;
if ((*sn)->rule.ptr != NULL)
(*sn)->rule.ptr->src_nodes++;
@@ -602,8 +776,10 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
pf_status.src_nodes++;
} else {
if (rule->max_src_states &&
- (*sn)->states >= rule->max_src_states)
+ (*sn)->states >= rule->max_src_states) {
+ pf_status.lcounters[LCNT_SRCSTATES]++;
return (-1);
+ }
}
return (0);
}
@@ -705,7 +881,7 @@ pf_state_expires(const struct pf_state *state)
/* handle all PFTM_* > PFTM_MAX here */
if (state->timeout == PFTM_PURGE)
- return (time.tv_sec);
+ return (time_second);
if (state->timeout == PFTM_UNTIL_PACKET)
return (0);
KASSERT(state->timeout < PFTM_MAX);
@@ -726,7 +902,7 @@ pf_state_expires(const struct pf_state *state)
return (state->expire + timeout * (end - states) /
(end - start));
else
- return (time.tv_sec);
+ return (time_second);
}
return (state->expire + timeout);
}
@@ -739,7 +915,7 @@ pf_purge_expired_src_nodes(void)
for (cur = RB_MIN(pf_src_tree, &tree_src_tracking); cur; cur = next) {
next = RB_NEXT(pf_src_tree, &tree_src_tracking, cur);
- if (cur->states <= 0 && cur->expire <= time.tv_sec) {
+ if (cur->states <= 0 && cur->expire <= time_second) {
if (cur->rule.ptr != NULL) {
cur->rule.ptr->src_nodes--;
if (cur->rule.ptr->states <= 0 &&
@@ -760,12 +936,17 @@ pf_src_tree_remove_state(struct pf_state *s)
u_int32_t timeout;
if (s->src_node != NULL) {
+ if (s->proto == IPPROTO_TCP) {
+ if (s->src.state == PF_TCPS_PROXY_DST ||
+ s->timeout >= PFTM_TCP_ESTABLISHED)
+ --s->src_node->conn;
+ }
if (--s->src_node->states <= 0) {
timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
if (!timeout)
timeout =
pf_default_rule.timeout[PFTM_SRC_NODE];
- s->src_node->expire = time.tv_sec + timeout;
+ s->src_node->expire = time_second + timeout;
}
}
if (s->nat_src_node != s->src_node && s->nat_src_node != NULL) {
@@ -774,13 +955,51 @@ pf_src_tree_remove_state(struct pf_state *s)
if (!timeout)
timeout =
pf_default_rule.timeout[PFTM_SRC_NODE];
- s->nat_src_node->expire = time.tv_sec + timeout;
+ s->nat_src_node->expire = time_second + timeout;
}
}
s->src_node = s->nat_src_node = NULL;
}
void
+pf_purge_expired_state(struct pf_state *cur)
+{
+ if (cur->src.state == PF_TCPS_PROXY_DST)
+ pf_send_tcp(cur->rule.ptr, cur->af,
+ &cur->ext.addr, &cur->lan.addr,
+ cur->ext.port, cur->lan.port,
+ cur->src.seqhi, cur->src.seqlo + 1,
+ TH_RST|TH_ACK, 0, 0, 0, 1, NULL, NULL);
+ RB_REMOVE(pf_state_tree_ext_gwy,
+ &cur->u.s.kif->pfik_ext_gwy, cur);
+ RB_REMOVE(pf_state_tree_lan_ext,
+ &cur->u.s.kif->pfik_lan_ext, cur);
+ RB_REMOVE(pf_state_tree_id, &tree_id, cur);
+#if NPFSYNC
+ pfsync_delete_state(cur);
+#endif
+ pf_src_tree_remove_state(cur);
+ if (--cur->rule.ptr->states <= 0 &&
+ cur->rule.ptr->src_nodes <= 0)
+ pf_rm_rule(NULL, cur->rule.ptr);
+ if (cur->nat_rule.ptr != NULL)
+ if (--cur->nat_rule.ptr->states <= 0 &&
+ cur->nat_rule.ptr->src_nodes <= 0)
+ pf_rm_rule(NULL, cur->nat_rule.ptr);
+ if (cur->anchor.ptr != NULL)
+ if (--cur->anchor.ptr->states <= 0)
+ pf_rm_rule(NULL, cur->anchor.ptr);
+ pf_normalize_tcp_cleanup(cur);
+ pfi_detach_state(cur->u.s.kif);
+ TAILQ_REMOVE(&state_updates, cur, u.s.entry_updates);
+ if (cur->tag)
+ pf_tag_unref(cur->tag);
+ pool_put(&pf_state_pl, cur);
+ pf_status.fcounters[FCNT_STATE_REMOVALS]++;
+ pf_status.states--;
+}
+
+void
pf_purge_expired_states(void)
{
struct pf_state *cur, *next;
@@ -788,40 +1007,8 @@ pf_purge_expired_states(void)
for (cur = RB_MIN(pf_state_tree_id, &tree_id);
cur; cur = next) {
next = RB_NEXT(pf_state_tree_id, &tree_id, cur);
-
- if (pf_state_expires(cur) <= time.tv_sec) {
- if (cur->src.state == PF_TCPS_PROXY_DST)
- pf_send_tcp(cur->rule.ptr, cur->af,
- &cur->ext.addr, &cur->lan.addr,
- cur->ext.port, cur->lan.port,
- cur->src.seqhi, cur->src.seqlo + 1, 0,
- TH_RST|TH_ACK, 0, 0);
- RB_REMOVE(pf_state_tree_ext_gwy,
- &cur->u.s.kif->pfik_ext_gwy, cur);
- RB_REMOVE(pf_state_tree_lan_ext,
- &cur->u.s.kif->pfik_lan_ext, cur);
- RB_REMOVE(pf_state_tree_id, &tree_id, cur);
-#if NPFSYNC
- pfsync_delete_state(cur);
-#endif
- pf_src_tree_remove_state(cur);
- if (--cur->rule.ptr->states <= 0 &&
- cur->rule.ptr->src_nodes <= 0)
- pf_rm_rule(NULL, cur->rule.ptr);
- if (cur->nat_rule.ptr != NULL)
- if (--cur->nat_rule.ptr->states <= 0 &&
- cur->nat_rule.ptr->src_nodes <= 0)
- pf_rm_rule(NULL, cur->nat_rule.ptr);
- if (cur->anchor.ptr != NULL)
- if (--cur->anchor.ptr->states <= 0)
- pf_rm_rule(NULL, cur->anchor.ptr);
- pf_normalize_tcp_cleanup(cur);
- pfi_detach_state(cur->u.s.kif);
- TAILQ_REMOVE(&state_updates, cur, u.s.entry_updates);
- pool_put(&pf_state_pl, cur);
- pf_status.fcounters[FCNT_STATE_REMOVALS]++;
- pf_status.states--;
- }
+ if (pf_state_expires(cur) <= time_second)
+ pf_purge_expired_state(cur);
}
}
@@ -1011,14 +1198,14 @@ pf_calc_skip_steps(struct pf_rulequeue *rules)
PF_SET_SKIP_STEPS(PF_SKIP_AF);
if (cur->proto != prev->proto)
PF_SET_SKIP_STEPS(PF_SKIP_PROTO);
- if (cur->src.not != prev->src.not ||
+ if (cur->src.neg != prev->src.neg ||
pf_addr_wrap_neq(&cur->src.addr, &prev->src.addr))
PF_SET_SKIP_STEPS(PF_SKIP_SRC_ADDR);
if (cur->src.port[0] != prev->src.port[0] ||
cur->src.port[1] != prev->src.port[1] ||
cur->src.port_op != prev->src.port_op)
PF_SET_SKIP_STEPS(PF_SKIP_SRC_PORT);
- if (cur->dst.not != prev->dst.not ||
+ if (cur->dst.neg != prev->dst.neg ||
pf_addr_wrap_neq(&cur->dst.addr, &prev->dst.addr))
PF_SET_SKIP_STEPS(PF_SKIP_DST_ADDR);
if (cur->dst.port[0] != prev->dst.port[0] ||
@@ -1057,21 +1244,6 @@ pf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2)
}
}
-void
-pf_update_anchor_rules()
-{
- struct pf_rule *rule;
- int i;
-
- for (i = 0; i < PF_RULESET_MAX; ++i)
- TAILQ_FOREACH(rule, pf_main_ruleset.rules[i].active.ptr,
- entries)
- if (rule->anchorname[0])
- rule->anchor = pf_find_anchor(rule->anchorname);
- else
- rule->anchor = NULL;
-}
-
u_int16_t
pf_cksum_fixup(u_int16_t cksum, u_int16_t old, u_int16_t new, u_int8_t udp)
{
@@ -1256,10 +1428,10 @@ void
pf_send_tcp(const struct pf_rule *r, sa_family_t af,
const struct pf_addr *saddr, const struct pf_addr *daddr,
u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack,
- u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl)
+ u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, int tag,
+ struct ether_header *eh, struct ifnet *ifp)
{
struct mbuf *m;
- struct m_tag *mtag;
int len, tlen;
#ifdef INET
struct ip *h;
@@ -1289,17 +1461,22 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af,
}
/* create outgoing mbuf */
- mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
- if (mtag == NULL)
- return;
m = m_gethdr(M_DONTWAIT, MT_HEADER);
- if (m == NULL) {
- m_tag_free(mtag);
+ if (m == NULL)
return;
+ if (tag) {
+ struct m_tag *mtag;
+
+ mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
+ if (mtag == NULL) {
+ m_freem(m);
+ return;
+ }
+ m_tag_prepend(m, mtag);
}
- m_tag_prepend(m, mtag);
#ifdef ALTQ
if (r != NULL && r->qid) {
+ struct m_tag *mtag;
struct altq_tag *atag;
mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
@@ -1312,7 +1489,7 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af,
m_tag_prepend(m, mtag);
}
}
-#endif
+#endif /* ALTQ */
m->m_data += max_linkhdr;
m->m_pkthdr.len = m->m_len = len;
m->m_pkthdr.rcvif = NULL;
@@ -1377,8 +1554,28 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af,
h->ip_off = htons(ip_mtudisc ? IP_DF : 0);
h->ip_ttl = ttl ? ttl : ip_defttl;
h->ip_sum = 0;
- ip_output(m, (void *)NULL, (void *)NULL, 0, (void *)NULL,
- (void *)NULL);
+ if (eh == NULL) {
+ ip_output(m, (void *)NULL, (void *)NULL, 0,
+ (void *)NULL, (void *)NULL);
+ } else {
+ struct route ro;
+ struct rtentry rt;
+ struct ether_header *e = (void *)ro.ro_dst.sa_data;
+
+ if (ifp == NULL) {
+ m_freem(m);
+ return;
+ }
+ rt.rt_ifp = ifp;
+ ro.ro_rt = &rt;
+ ro.ro_dst.sa_len = sizeof(ro.ro_dst);
+ ro.ro_dst.sa_family = pseudo_AF_HDRCMPLT;
+ bcopy(eh->ether_dhost, e->ether_shost, ETHER_ADDR_LEN);
+ bcopy(eh->ether_shost, e->ether_dhost, ETHER_ADDR_LEN);
+ e->ether_type = eh->ether_type;
+ ip_output(m, (void *)NULL, &ro, IP_ROUTETOETHER,
+ (void *)NULL, (void *)NULL);
+ }
break;
#endif /* INET */
#ifdef INET6
@@ -1427,7 +1624,7 @@ pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
m_tag_prepend(m0, mtag);
}
}
-#endif
+#endif /* ALTQ */
switch (af) {
#ifdef INET
@@ -1552,17 +1749,14 @@ pf_get_tag(struct mbuf *m)
}
int
-pf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_rule *nat_rule,
- struct pf_tag *pftag, int *tag)
+pf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_tag **pftag, int *tag)
{
if (*tag == -1) { /* find mbuf tag */
- pftag = pf_get_tag(m);
- if (pftag != NULL)
- *tag = pftag->tag;
+ *pftag = pf_get_tag(m);
+ if (*pftag != NULL)
+ *tag = (*pftag)->tag;
else
*tag = 0;
- if (nat_rule != NULL && nat_rule->tag)
- *tag = nat_rule->tag;
}
return ((!r->match_tag_not && r->match_tag == *tag) ||
@@ -1589,36 +1783,66 @@ pf_tag_packet(struct mbuf *m, struct pf_tag *pftag, int tag)
return (0);
}
-#define PF_STEP_INTO_ANCHOR(r, a, s, n) \
- do { \
- if ((r) == NULL || (r)->anchor == NULL || \
- (s) != NULL || (a) != NULL) \
- panic("PF_STEP_INTO_ANCHOR"); \
- (a) = (r); \
- (s) = TAILQ_FIRST(&(r)->anchor->rulesets); \
- (r) = NULL; \
- while ((s) != NULL && ((r) = \
- TAILQ_FIRST((s)->rules[n].active.ptr)) == NULL) \
- (s) = TAILQ_NEXT((s), entries); \
- if ((r) == NULL) { \
- (r) = TAILQ_NEXT((a), entries); \
- (a) = NULL; \
- } \
- } while (0)
+static void
+pf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n,
+ struct pf_rule **r, struct pf_rule **a)
+{
+ struct pf_anchor_stackframe *f;
-#define PF_STEP_OUT_OF_ANCHOR(r, a, s, n) \
- do { \
- if ((r) != NULL || (a) == NULL || (s) == NULL) \
- panic("PF_STEP_OUT_OF_ANCHOR"); \
- (s) = TAILQ_NEXT((s), entries); \
- while ((s) != NULL && ((r) = \
- TAILQ_FIRST((s)->rules[n].active.ptr)) == NULL) \
- (s) = TAILQ_NEXT((s), entries); \
- if ((r) == NULL) { \
- (r) = TAILQ_NEXT((a), entries); \
- (a) = NULL; \
- } \
- } while (0)
+ if (*depth >= sizeof(pf_anchor_stack) /
+ sizeof(pf_anchor_stack[0])) {
+ printf("pf_step_into_anchor: stack overflow\n");
+ *r = TAILQ_NEXT(*r, entries);
+ return;
+ } else if (*depth == 0 && a != NULL)
+ *a = *r;
+ f = pf_anchor_stack + (*depth)++;
+ f->rs = *rs;
+ f->r = *r;
+ if ((*r)->anchor_wildcard) {
+ f->parent = &(*r)->anchor->children;
+ if ((f->child = RB_MIN(pf_anchor_node, f->parent)) ==
+ NULL) {
+ *r = NULL;
+ return;
+ }
+ *rs = &f->child->ruleset;
+ } else {
+ f->parent = NULL;
+ f->child = NULL;
+ *rs = &(*r)->anchor->ruleset;
+ }
+ *r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
+}
+
+static void
+pf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n,
+ struct pf_rule **r, struct pf_rule **a)
+{
+ struct pf_anchor_stackframe *f;
+
+ do {
+ if (*depth <= 0)
+ break;
+ f = pf_anchor_stack + *depth - 1;
+ if (f->parent != NULL && f->child != NULL) {
+ f->child = RB_NEXT(pf_anchor_node, f->parent, f->child);
+ if (f->child != NULL) {
+ *rs = &f->child->ruleset;
+ *r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
+ if (*r == NULL)
+ continue;
+ else
+ break;
+ }
+ }
+ (*depth)--;
+ if (*depth == 0 && a != NULL)
+ *a = NULL;
+ *rs = f->rs;
+ *r = TAILQ_NEXT(f->r, entries);
+ } while (*r == NULL);
+}
#ifdef INET6
void
@@ -1772,20 +1996,27 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
if (rpool->cur->addr.type == PF_ADDR_NOROUTE)
return (1);
if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
- if (af == AF_INET) {
+ switch (af) {
+#ifdef INET
+ case AF_INET:
if (rpool->cur->addr.p.dyn->pfid_acnt4 < 1 &&
(rpool->opts & PF_POOL_TYPEMASK) !=
PF_POOL_ROUNDROBIN)
return (1);
raddr = &rpool->cur->addr.p.dyn->pfid_addr4;
rmask = &rpool->cur->addr.p.dyn->pfid_mask4;
- } else {
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
if (rpool->cur->addr.p.dyn->pfid_acnt6 < 1 &&
(rpool->opts & PF_POOL_TYPEMASK) !=
PF_POOL_ROUNDROBIN)
return (1);
raddr = &rpool->cur->addr.p.dyn->pfid_addr6;
rmask = &rpool->cur->addr.p.dyn->pfid_mask6;
+ break;
+#endif /* INET6 */
}
} else if (rpool->cur->addr.type == PF_ADDR_TABLE) {
if ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN)
@@ -1807,25 +2038,29 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
switch (af) {
#ifdef INET
case AF_INET:
- rpool->counter.addr32[0] = arc4random();
+ rpool->counter.addr32[0] = htonl(arc4random());
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
if (rmask->addr32[3] != 0xffffffff)
- rpool->counter.addr32[3] = arc4random();
+ rpool->counter.addr32[3] =
+ htonl(arc4random());
else
break;
if (rmask->addr32[2] != 0xffffffff)
- rpool->counter.addr32[2] = arc4random();
+ rpool->counter.addr32[2] =
+ htonl(arc4random());
else
break;
if (rmask->addr32[1] != 0xffffffff)
- rpool->counter.addr32[1] = arc4random();
+ rpool->counter.addr32[1] =
+ htonl(arc4random());
else
break;
if (rmask->addr32[0] != 0xffffffff)
- rpool->counter.addr32[0] = arc4random();
+ rpool->counter.addr32[0] =
+ htonl(arc4random());
break;
#endif /* INET6 */
}
@@ -1886,6 +2121,8 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
get_addr:
PF_ACPY(naddr, &rpool->counter, af);
+ if (init_addr != NULL && PF_AZERO(init_addr, af))
+ PF_ACPY(init_addr, naddr, af);
PF_AINC(&rpool->counter, af);
break;
}
@@ -1928,7 +2165,7 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
* similar 2 portloop in in_pcbbind
*/
if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP)) {
- key.gwy.port = 0;
+ key.gwy.port = dport;
if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL)
return (0);
} else if (low == 0 && high == 0) {
@@ -1950,7 +2187,7 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
high = tmp;
}
/* low < high */
- cut = arc4random() % (1 + high - low) + low;
+ cut = htonl(arc4random()) % (1 + high - low) + low;
/* low <= cut <= high */
for (tmp = cut; tmp <= high; ++(tmp)) {
key.gwy.port = htons(tmp);
@@ -1992,8 +2229,11 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
int direction, struct pfi_kif *kif, struct pf_addr *saddr, u_int16_t sport,
struct pf_addr *daddr, u_int16_t dport, int rs_num)
{
- struct pf_rule *r, *rm = NULL, *anchorrule = NULL;
+ struct pf_rule *r, *rm = NULL;
struct pf_ruleset *ruleset = NULL;
+ struct pf_tag *pftag = NULL;
+ int tag = -1;
+ int asd = 0;
r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr);
while (r && rm == NULL) {
@@ -2019,7 +2259,7 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
r = r->skip[PF_SKIP_AF].ptr;
else if (r->proto && r->proto != pd->proto)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&src->addr, saddr, pd->af, src->not))
+ else if (PF_MISMATCHAW(&src->addr, saddr, pd->af, src->neg))
r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR :
PF_SKIP_DST_ADDR].ptr;
else if (src->port_op && !pf_match_port(src->port_op,
@@ -2027,7 +2267,7 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT :
PF_SKIP_DST_PORT].ptr;
else if (dst != NULL &&
- PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->not))
+ PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af, 0))
r = TAILQ_NEXT(r, entries);
@@ -2035,20 +2275,25 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
!pf_match_port(dst->port_op, dst->port[0],
dst->port[1], dport))
r = r->skip[PF_SKIP_DST_PORT].ptr;
+ else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
+ r = TAILQ_NEXT(r, entries);
else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto !=
IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m,
off, pd->hdr.tcp), r->os_fingerprint)))
r = TAILQ_NEXT(r, entries);
- else if (r->anchorname[0] && r->anchor == NULL)
- r = TAILQ_NEXT(r, entries);
- else if (r->anchor == NULL)
+ else {
+ if (r->tag)
+ tag = r->tag;
+ if (r->anchor == NULL) {
rm = r;
- else
- PF_STEP_INTO_ANCHOR(r, anchorrule, ruleset, rs_num);
- if (r == NULL && anchorrule != NULL)
- PF_STEP_OUT_OF_ANCHOR(r, anchorrule, ruleset,
- rs_num);
+ } else
+ pf_step_into_anchor(&asd, &ruleset, rs_num, &r, NULL);
+ }
+ if (r == NULL)
+ pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r, NULL);
}
+ if (pf_tag_packet(m, pftag, tag))
+ return (NULL);
if (rm != NULL && (rm->action == PF_NONAT ||
rm->action == PF_NORDR || rm->action == PF_NOBINAT))
return (NULL);
@@ -2100,7 +2345,9 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
switch (direction) {
case PF_OUT:
if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){
- if (pd->af == AF_INET) {
+ switch (pd->af) {
+#ifdef INET
+ case AF_INET:
if (r->rpool.cur->addr.p.dyn->
pfid_acnt4 < 1)
return (NULL);
@@ -2110,7 +2357,10 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
&r->rpool.cur->addr.p.dyn->
pfid_mask4,
saddr, AF_INET);
- } else {
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
if (r->rpool.cur->addr.p.dyn->
pfid_acnt6 < 1)
return (NULL);
@@ -2120,6 +2370,8 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
&r->rpool.cur->addr.p.dyn->
pfid_mask6,
saddr, AF_INET6);
+ break;
+#endif /* INET6 */
}
} else
PF_POOLMASK(naddr,
@@ -2128,8 +2380,10 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
saddr, pd->af);
break;
case PF_IN:
- if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){
- if (pd->af == AF_INET) {
+ if (r->src.addr.type == PF_ADDR_DYNIFTL) {
+ switch (pd->af) {
+#ifdef INET
+ case AF_INET:
if (r->src.addr.p.dyn->
pfid_acnt4 < 1)
return (NULL);
@@ -2139,7 +2393,10 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
&r->src.addr.p.dyn->
pfid_mask4,
daddr, AF_INET);
- } else {
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
if (r->src.addr.p.dyn->
pfid_acnt6 < 1)
return (NULL);
@@ -2149,6 +2406,8 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
&r->src.addr.p.dyn->
pfid_mask6,
daddr, AF_INET6);
+ break;
+#endif /* INET6 */
}
} else
PF_POOLMASK(naddr,
@@ -2159,7 +2418,7 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
}
break;
case PF_RDR: {
- if (pf_map_addr(r->af, r, saddr, naddr, NULL, sn))
+ if (pf_map_addr(pd->af, r, saddr, naddr, NULL, sn))
return (NULL);
if (r->rpool.proxy_port[1]) {
@@ -2224,6 +2483,7 @@ pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd)
daddr = pd->src;
}
switch (pd->af) {
+#ifdef INET
case AF_INET:
inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport);
if (inp == NULL) {
@@ -2232,6 +2492,7 @@ pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd)
return (0);
}
break;
+#endif /* INET */
#ifdef INET6
case AF_INET6:
inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6,
@@ -2316,6 +2577,7 @@ pf_get_mss(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
break;
case TCPOPT_MAXSEG:
bcopy((caddr_t)(opt + 2), (caddr_t)&mss, 2);
+ NTOHS(mss);
/* FALLTHROUGH */
default:
optlen = opt[1];
@@ -2410,7 +2672,8 @@ pf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr)
int
pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
struct pfi_kif *kif, struct mbuf *m, int off, void *h,
- struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm)
+ struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
+ struct ifqueue *ifq)
{
struct pf_rule *nr = NULL;
struct pf_addr *saddr = pd->src, *daddr = pd->dst;
@@ -2428,6 +2691,12 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
struct pf_tag *pftag = NULL;
int tag = -1;
u_int16_t mss = tcp_mssdflt;
+ int asd = 0;
+
+ if (pf_check_congestion(ifq)) {
+ REASON_SET(&reason, PFRES_CONGEST);
+ return (PF_DROP);
+ }
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
@@ -2472,12 +2741,12 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
r = r->skip[PF_SKIP_AF].ptr;
else if (r->proto && r->proto != IPPROTO_TCP)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.not))
+ else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
else if (r->src.port_op && !pf_match_port(r->src.port_op,
r->src.port[0], r->src.port[1], th->th_sport))
r = r->skip[PF_SKIP_SRC_PORT].ptr;
- else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.not))
+ else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
r->dst.port[0], r->dst.port[1], th->th_dport))
@@ -2498,9 +2767,9 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
!pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
gid))
r = TAILQ_NEXT(r, entries);
- else if (r->match_tag && !pf_match_tag(m, r, nr, pftag, &tag))
+ else if (r->prob && r->prob <= arc4random())
r = TAILQ_NEXT(r, entries);
- else if (r->anchorname[0] && r->anchor == NULL)
+ else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
r = TAILQ_NEXT(r, entries);
else if (r->os_fingerprint != PF_OSFP_ANY && !pf_osfp_match(
pf_osfp_fingerprint(pd, m, off, th), r->os_fingerprint))
@@ -2516,12 +2785,12 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
break;
r = TAILQ_NEXT(r, entries);
} else
- PF_STEP_INTO_ANCHOR(r, a, ruleset,
- PF_RULESET_FILTER);
+ pf_step_into_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
- if (r == NULL && a != NULL)
- PF_STEP_OUT_OF_ANCHOR(r, a, ruleset,
- PF_RULESET_FILTER);
+ if (r == NULL)
+ pf_step_out_of_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
r = *rm;
a = *am;
@@ -2563,7 +2832,7 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
pf_send_tcp(r, af, pd->dst,
pd->src, th->th_dport, th->th_sport,
ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0,
- r->return_ttl);
+ r->return_ttl, 1, pd->eh, kif->pfik_ifp);
} else if ((af == AF_INET) && r->return_icmp)
pf_send_icmp(m, r->return_icmp >> 8,
r->return_icmp & 255, af, r);
@@ -2590,21 +2859,29 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
len = pd->tot_len - off - (th->th_off << 2);
/* check maximums */
- if (r->max_states && (r->states >= r->max_states))
+ if (r->max_states && (r->states >= r->max_states)) {
+ pf_status.lcounters[LCNT_STATES]++;
+ REASON_SET(&reason, PFRES_MAXSTATES);
goto cleanup;
+ }
/* src node for flter rule */
if ((r->rule_flag & PFRULE_SRCTRACK ||
r->rpool.opts & PF_POOL_STICKYADDR) &&
- pf_insert_src_node(&sn, r, saddr, af) != 0)
+ pf_insert_src_node(&sn, r, saddr, af) != 0) {
+ REASON_SET(&reason, PFRES_SRCLIMIT);
goto cleanup;
+ }
/* src node for translation rule */
if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
((direction == PF_OUT &&
pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
- (pf_insert_src_node(&nsn, nr, saddr, af) != 0)))
+ (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
+ REASON_SET(&reason, PFRES_SRCLIMIT);
goto cleanup;
+ }
s = pool_get(&pf_state_pl, PR_NOWAIT);
if (s == NULL) {
+ REASON_SET(&reason, PFRES_MEMORY);
cleanup:
if (sn != NULL && sn->states == 0 && sn->expire == 0) {
RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
@@ -2619,18 +2896,13 @@ cleanup:
pf_status.src_nodes--;
pool_put(&pf_src_tree_pl, nsn);
}
- REASON_SET(&reason, PFRES_MEMORY);
return (PF_DROP);
}
bzero(s, sizeof(*s));
- r->states++;
- if (a != NULL)
- a->states++;
s->rule.ptr = r;
s->nat_rule.ptr = nr;
- if (s->nat_rule.ptr != NULL)
- s->nat_rule.ptr->states++;
s->anchor.ptr = a;
+ STATE_INC_COUNTERS(s);
s->allow_opts = r->allow_opts;
s->log = r->log & 2;
s->proto = IPPROTO_TCP;
@@ -2667,7 +2939,7 @@ cleanup:
if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
r->keep_state == PF_STATE_MODULATE) {
/* Generate sequence number modulator */
- while ((s->src.seqdiff = arc4random()) == 0)
+ while ((s->src.seqdiff = htonl(arc4random())) == 0)
;
pf_change_a(&th->th_seq, &th->th_sum,
htonl(s->src.seqlo + s->src.seqdiff), 0);
@@ -2692,8 +2964,8 @@ cleanup:
s->dst.max_win = 1;
s->src.state = TCPS_SYN_SENT;
s->dst.state = TCPS_CLOSED;
- s->creation = time.tv_sec;
- s->expire = time.tv_sec;
+ s->creation = time_second;
+ s->expire = time_second;
s->timeout = PFTM_TCP_FIRST_PACKET;
pf_set_rt_ifp(s, saddr);
if (sn != NULL) {
@@ -2709,25 +2981,35 @@ cleanup:
off, pd, th, &s->src, &s->dst)) {
REASON_SET(&reason, PFRES_MEMORY);
pf_src_tree_remove_state(s);
+ STATE_DEC_COUNTERS(s);
pool_put(&pf_state_pl, s);
return (PF_DROP);
}
if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub &&
- pf_normalize_tcp_stateful(m, off, pd, &reason, th, &s->src,
- &s->dst, &rewrite)) {
+ pf_normalize_tcp_stateful(m, off, pd, &reason, th, s,
+ &s->src, &s->dst, &rewrite)) {
+ /* This really shouldn't happen!!! */
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_normalize_tcp_stateful failed on first pkt"));
pf_normalize_tcp_cleanup(s);
pf_src_tree_remove_state(s);
+ STATE_DEC_COUNTERS(s);
pool_put(&pf_state_pl, s);
return (PF_DROP);
}
if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
pf_normalize_tcp_cleanup(s);
- REASON_SET(&reason, PFRES_MEMORY);
+ REASON_SET(&reason, PFRES_STATEINS);
pf_src_tree_remove_state(s);
+ STATE_DEC_COUNTERS(s);
pool_put(&pf_state_pl, s);
return (PF_DROP);
} else
*sm = s;
+ if (tag > 0) {
+ pf_tag_ref(tag);
+ s->tag = tag;
+ }
if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
r->keep_state == PF_STATE_SYNPROXY) {
s->src.state = PF_TCPS_PROXY_SRC;
@@ -2742,7 +3024,7 @@ cleanup:
bport, 0, af);
}
}
- s->src.seqhi = arc4random();
+ s->src.seqhi = htonl(arc4random());
/* Find mss option */
mss = pf_get_mss(m, off, th->th_off, af);
mss = pf_calc_mss(saddr, af, mss);
@@ -2750,7 +3032,8 @@ cleanup:
s->src.mss = mss;
pf_send_tcp(r, af, daddr, saddr, th->th_dport,
th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1,
- TH_SYN|TH_ACK, 0, s->src.mss, 0);
+ TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, NULL, NULL);
+ REASON_SET(&reason, PFRES_SYNPROXY);
return (PF_SYNPROXY_DROP);
}
}
@@ -2765,7 +3048,8 @@ cleanup:
int
pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
struct pfi_kif *kif, struct mbuf *m, int off, void *h,
- struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm)
+ struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
+ struct ifqueue *ifq)
{
struct pf_rule *nr = NULL;
struct pf_addr *saddr = pd->src, *daddr = pd->dst;
@@ -2782,6 +3066,12 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
int rewrite = 0;
struct pf_tag *pftag = NULL;
int tag = -1;
+ int asd = 0;
+
+ if (pf_check_congestion(ifq)) {
+ REASON_SET(&reason, PFRES_CONGEST);
+ return (PF_DROP);
+ }
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
@@ -2826,12 +3116,12 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
r = r->skip[PF_SKIP_AF].ptr;
else if (r->proto && r->proto != IPPROTO_UDP)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.not))
+ else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
else if (r->src.port_op && !pf_match_port(r->src.port_op,
r->src.port[0], r->src.port[1], uh->uh_sport))
r = r->skip[PF_SKIP_SRC_PORT].ptr;
- else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.not))
+ else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
r->dst.port[0], r->dst.port[1], uh->uh_dport))
@@ -2850,9 +3140,9 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
!pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
gid))
r = TAILQ_NEXT(r, entries);
- else if (r->match_tag && !pf_match_tag(m, r, nr, pftag, &tag))
+ else if (r->prob && r->prob <= arc4random())
r = TAILQ_NEXT(r, entries);
- else if (r->anchorname[0] && r->anchor == NULL)
+ else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
r = TAILQ_NEXT(r, entries);
else if (r->os_fingerprint != PF_OSFP_ANY)
r = TAILQ_NEXT(r, entries);
@@ -2867,12 +3157,12 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
break;
r = TAILQ_NEXT(r, entries);
} else
- PF_STEP_INTO_ANCHOR(r, a, ruleset,
- PF_RULESET_FILTER);
+ pf_step_into_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
- if (r == NULL && a != NULL)
- PF_STEP_OUT_OF_ANCHOR(r, a, ruleset,
- PF_RULESET_FILTER);
+ if (r == NULL)
+ pf_step_out_of_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
r = *rm;
a = *am;
@@ -2923,21 +3213,29 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
struct pf_src_node *sn = NULL;
/* check maximums */
- if (r->max_states && (r->states >= r->max_states))
+ if (r->max_states && (r->states >= r->max_states)) {
+ pf_status.lcounters[LCNT_STATES]++;
+ REASON_SET(&reason, PFRES_MAXSTATES);
goto cleanup;
+ }
/* src node for flter rule */
if ((r->rule_flag & PFRULE_SRCTRACK ||
r->rpool.opts & PF_POOL_STICKYADDR) &&
- pf_insert_src_node(&sn, r, saddr, af) != 0)
+ pf_insert_src_node(&sn, r, saddr, af) != 0) {
+ REASON_SET(&reason, PFRES_SRCLIMIT);
goto cleanup;
+ }
/* src node for translation rule */
if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
((direction == PF_OUT &&
pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
- (pf_insert_src_node(&nsn, nr, saddr, af) != 0)))
+ (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
+ REASON_SET(&reason, PFRES_SRCLIMIT);
goto cleanup;
+ }
s = pool_get(&pf_state_pl, PR_NOWAIT);
if (s == NULL) {
+ REASON_SET(&reason, PFRES_MEMORY);
cleanup:
if (sn != NULL && sn->states == 0 && sn->expire == 0) {
RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
@@ -2952,18 +3250,13 @@ cleanup:
pf_status.src_nodes--;
pool_put(&pf_src_tree_pl, nsn);
}
- REASON_SET(&reason, PFRES_MEMORY);
return (PF_DROP);
}
bzero(s, sizeof(*s));
- r->states++;
- if (a != NULL)
- a->states++;
s->rule.ptr = r;
s->nat_rule.ptr = nr;
- if (s->nat_rule.ptr != NULL)
- s->nat_rule.ptr->states++;
s->anchor.ptr = a;
+ STATE_INC_COUNTERS(s);
s->allow_opts = r->allow_opts;
s->log = r->log & 2;
s->proto = IPPROTO_UDP;
@@ -2996,8 +3289,8 @@ cleanup:
}
s->src.state = PFUDPS_SINGLE;
s->dst.state = PFUDPS_NO_TRAFFIC;
- s->creation = time.tv_sec;
- s->expire = time.tv_sec;
+ s->creation = time_second;
+ s->expire = time_second;
s->timeout = PFTM_UDP_FIRST_PACKET;
pf_set_rt_ifp(s, saddr);
if (sn != NULL) {
@@ -3010,12 +3303,17 @@ cleanup:
s->nat_src_node->states++;
}
if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
- REASON_SET(&reason, PFRES_MEMORY);
+ REASON_SET(&reason, PFRES_STATEINS);
pf_src_tree_remove_state(s);
+ STATE_DEC_COUNTERS(s);
pool_put(&pf_state_pl, s);
return (PF_DROP);
} else
*sm = s;
+ if (tag > 0) {
+ pf_tag_ref(tag);
+ s->tag = tag;
+ }
}
/* copy back packet headers if we performed NAT operations */
@@ -3028,7 +3326,8 @@ cleanup:
int
pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
struct pfi_kif *kif, struct mbuf *m, int off, void *h,
- struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm)
+ struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
+ struct ifqueue *ifq)
{
struct pf_rule *nr = NULL;
struct pf_addr *saddr = pd->src, *daddr = pd->dst;
@@ -3045,6 +3344,12 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
#ifdef INET6
int rewrite = 0;
#endif /* INET6 */
+ int asd = 0;
+
+ if (pf_check_congestion(ifq)) {
+ REASON_SET(&reason, PFRES_CONGEST);
+ return (PF_DROP);
+ }
switch (pd->proto) {
#ifdef INET
@@ -3081,7 +3386,7 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
if (direction == PF_OUT) {
/* check outgoing packet for BINAT/NAT */
if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
- saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) {
+ saddr, icmpid, daddr, icmpid, &pd->naddr, NULL)) != NULL) {
PF_ACPY(&pd->baddr, saddr, af);
switch (af) {
#ifdef INET
@@ -3105,7 +3410,7 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
} else {
/* check incoming packet for BINAT/RDR */
if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
- saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) {
+ saddr, icmpid, daddr, icmpid, &pd->naddr, NULL)) != NULL) {
PF_ACPY(&pd->baddr, daddr, af);
switch (af) {
#ifdef INET
@@ -3139,9 +3444,9 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
r = r->skip[PF_SKIP_AF].ptr;
else if (r->proto && r->proto != pd->proto)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.not))
+ else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
- else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.not))
+ else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (r->type && r->type != icmptype + 1)
r = TAILQ_NEXT(r, entries);
@@ -3151,9 +3456,9 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
r = TAILQ_NEXT(r, entries);
else if (r->rule_flag & PFRULE_FRAGMENT)
r = TAILQ_NEXT(r, entries);
- else if (r->match_tag && !pf_match_tag(m, r, nr, pftag, &tag))
+ else if (r->prob && r->prob <= arc4random())
r = TAILQ_NEXT(r, entries);
- else if (r->anchorname[0] && r->anchor == NULL)
+ else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
r = TAILQ_NEXT(r, entries);
else if (r->os_fingerprint != PF_OSFP_ANY)
r = TAILQ_NEXT(r, entries);
@@ -3168,12 +3473,12 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
break;
r = TAILQ_NEXT(r, entries);
} else
- PF_STEP_INTO_ANCHOR(r, a, ruleset,
- PF_RULESET_FILTER);
+ pf_step_into_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
- if (r == NULL && a != NULL)
- PF_STEP_OUT_OF_ANCHOR(r, a, ruleset,
- PF_RULESET_FILTER);
+ if (r == NULL)
+ pf_step_out_of_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
r = *rm;
a = *am;
@@ -3204,21 +3509,29 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
struct pf_src_node *sn = NULL;
/* check maximums */
- if (r->max_states && (r->states >= r->max_states))
+ if (r->max_states && (r->states >= r->max_states)) {
+ pf_status.lcounters[LCNT_STATES]++;
+ REASON_SET(&reason, PFRES_MAXSTATES);
goto cleanup;
+ }
/* src node for flter rule */
if ((r->rule_flag & PFRULE_SRCTRACK ||
r->rpool.opts & PF_POOL_STICKYADDR) &&
- pf_insert_src_node(&sn, r, saddr, af) != 0)
+ pf_insert_src_node(&sn, r, saddr, af) != 0) {
+ REASON_SET(&reason, PFRES_SRCLIMIT);
goto cleanup;
+ }
/* src node for translation rule */
if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
((direction == PF_OUT &&
pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
- (pf_insert_src_node(&nsn, nr, saddr, af) != 0)))
+ (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
+ REASON_SET(&reason, PFRES_SRCLIMIT);
goto cleanup;
+ }
s = pool_get(&pf_state_pl, PR_NOWAIT);
if (s == NULL) {
+ REASON_SET(&reason, PFRES_MEMORY);
cleanup:
if (sn != NULL && sn->states == 0 && sn->expire == 0) {
RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
@@ -3233,18 +3546,13 @@ cleanup:
pf_status.src_nodes--;
pool_put(&pf_src_tree_pl, nsn);
}
- REASON_SET(&reason, PFRES_MEMORY);
return (PF_DROP);
}
bzero(s, sizeof(*s));
- r->states++;
- if (a != NULL)
- a->states++;
s->rule.ptr = r;
s->nat_rule.ptr = nr;
- if (s->nat_rule.ptr != NULL)
- s->nat_rule.ptr->states++;
s->anchor.ptr = a;
+ STATE_INC_COUNTERS(s);
s->allow_opts = r->allow_opts;
s->log = r->log & 2;
s->proto = pd->proto;
@@ -3271,8 +3579,8 @@ cleanup:
PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
s->gwy.port = icmpid;
}
- s->creation = time.tv_sec;
- s->expire = time.tv_sec;
+ s->creation = time_second;
+ s->expire = time_second;
s->timeout = PFTM_ICMP_FIRST_PACKET;
pf_set_rt_ifp(s, saddr);
if (sn != NULL) {
@@ -3285,12 +3593,17 @@ cleanup:
s->nat_src_node->states++;
}
if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
- REASON_SET(&reason, PFRES_MEMORY);
+ REASON_SET(&reason, PFRES_STATEINS);
pf_src_tree_remove_state(s);
+ STATE_DEC_COUNTERS(s);
pool_put(&pf_state_pl, s);
return (PF_DROP);
} else
*sm = s;
+ if (tag > 0) {
+ pf_tag_ref(tag);
+ s->tag = tag;
+ }
}
#ifdef INET6
@@ -3306,7 +3619,7 @@ cleanup:
int
pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
- struct pf_rule **am, struct pf_ruleset **rsm)
+ struct pf_rule **am, struct pf_ruleset **rsm, struct ifqueue *ifq)
{
struct pf_rule *nr = NULL;
struct pf_rule *r, *a = NULL;
@@ -3317,6 +3630,12 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
u_short reason;
struct pf_tag *pftag = NULL;
int tag = -1;
+ int asd = 0;
+
+ if (pf_check_congestion(ifq)) {
+ REASON_SET(&reason, PFRES_CONGEST);
+ return (PF_DROP);
+ }
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
@@ -3377,17 +3696,17 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
r = r->skip[PF_SKIP_AF].ptr;
else if (r->proto && r->proto != pd->proto)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.not))
+ else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
- else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.not))
+ else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (r->tos && !(r->tos & pd->tos))
r = TAILQ_NEXT(r, entries);
else if (r->rule_flag & PFRULE_FRAGMENT)
r = TAILQ_NEXT(r, entries);
- else if (r->match_tag && !pf_match_tag(m, r, nr, pftag, &tag))
+ else if (r->prob && r->prob <= arc4random())
r = TAILQ_NEXT(r, entries);
- else if (r->anchorname[0] && r->anchor == NULL)
+ else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
r = TAILQ_NEXT(r, entries);
else if (r->os_fingerprint != PF_OSFP_ANY)
r = TAILQ_NEXT(r, entries);
@@ -3402,12 +3721,12 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
break;
r = TAILQ_NEXT(r, entries);
} else
- PF_STEP_INTO_ANCHOR(r, a, ruleset,
- PF_RULESET_FILTER);
+ pf_step_into_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
- if (r == NULL && a != NULL)
- PF_STEP_OUT_OF_ANCHOR(r, a, ruleset,
- PF_RULESET_FILTER);
+ if (r == NULL)
+ pf_step_out_of_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
r = *rm;
a = *am;
@@ -3466,21 +3785,29 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
struct pf_src_node *sn = NULL;
/* check maximums */
- if (r->max_states && (r->states >= r->max_states))
+ if (r->max_states && (r->states >= r->max_states)) {
+ pf_status.lcounters[LCNT_STATES]++;
+ REASON_SET(&reason, PFRES_MAXSTATES);
goto cleanup;
+ }
/* src node for flter rule */
if ((r->rule_flag & PFRULE_SRCTRACK ||
r->rpool.opts & PF_POOL_STICKYADDR) &&
- pf_insert_src_node(&sn, r, saddr, af) != 0)
+ pf_insert_src_node(&sn, r, saddr, af) != 0) {
+ REASON_SET(&reason, PFRES_SRCLIMIT);
goto cleanup;
+ }
/* src node for translation rule */
if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
((direction == PF_OUT &&
pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
- (pf_insert_src_node(&nsn, nr, saddr, af) != 0)))
+ (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
+ REASON_SET(&reason, PFRES_SRCLIMIT);
goto cleanup;
+ }
s = pool_get(&pf_state_pl, PR_NOWAIT);
if (s == NULL) {
+ REASON_SET(&reason, PFRES_MEMORY);
cleanup:
if (sn != NULL && sn->states == 0 && sn->expire == 0) {
RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
@@ -3495,18 +3822,13 @@ cleanup:
pf_status.src_nodes--;
pool_put(&pf_src_tree_pl, nsn);
}
- REASON_SET(&reason, PFRES_MEMORY);
return (PF_DROP);
}
bzero(s, sizeof(*s));
- r->states++;
- if (a != NULL)
- a->states++;
s->rule.ptr = r;
s->nat_rule.ptr = nr;
- if (s->nat_rule.ptr != NULL)
- s->nat_rule.ptr->states++;
s->anchor.ptr = a;
+ STATE_INC_COUNTERS(s);
s->allow_opts = r->allow_opts;
s->log = r->log & 2;
s->proto = pd->proto;
@@ -3529,8 +3851,8 @@ cleanup:
}
s->src.state = PFOTHERS_SINGLE;
s->dst.state = PFOTHERS_NO_TRAFFIC;
- s->creation = time.tv_sec;
- s->expire = time.tv_sec;
+ s->creation = time_second;
+ s->expire = time_second;
s->timeout = PFTM_OTHER_FIRST_PACKET;
pf_set_rt_ifp(s, saddr);
if (sn != NULL) {
@@ -3543,12 +3865,17 @@ cleanup:
s->nat_src_node->states++;
}
if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
- REASON_SET(&reason, PFRES_MEMORY);
+ REASON_SET(&reason, PFRES_STATEINS);
pf_src_tree_remove_state(s);
+ STATE_DEC_COUNTERS(s);
pool_put(&pf_state_pl, s);
return (PF_DROP);
} else
*sm = s;
+ if (tag > 0) {
+ pf_tag_ref(tag);
+ s->tag = tag;
+ }
}
return (PF_PASS);
@@ -3565,6 +3892,7 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
u_short reason;
struct pf_tag *pftag = NULL;
int tag = -1;
+ int asd = 0;
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
while (r != NULL) {
@@ -3578,9 +3906,9 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
r = r->skip[PF_SKIP_AF].ptr;
else if (r->proto && r->proto != pd->proto)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.not))
+ else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
- else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.not))
+ else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (r->tos && !(r->tos & pd->tos))
r = TAILQ_NEXT(r, entries);
@@ -3588,9 +3916,9 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
r->flagset || r->type || r->code ||
r->os_fingerprint != PF_OSFP_ANY)
r = TAILQ_NEXT(r, entries);
- else if (r->match_tag && !pf_match_tag(m, r, NULL, pftag, &tag))
+ else if (r->prob && r->prob <= arc4random())
r = TAILQ_NEXT(r, entries);
- else if (r->anchorname[0] && r->anchor == NULL)
+ else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
r = TAILQ_NEXT(r, entries);
else {
if (r->anchor == NULL) {
@@ -3601,12 +3929,12 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
break;
r = TAILQ_NEXT(r, entries);
} else
- PF_STEP_INTO_ANCHOR(r, a, ruleset,
- PF_RULESET_FILTER);
+ pf_step_into_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
- if (r == NULL && a != NULL)
- PF_STEP_OUT_OF_ANCHOR(r, a, ruleset,
- PF_RULESET_FILTER);
+ if (r == NULL)
+ pf_step_out_of_anchor(&asd, &ruleset,
+ PF_RULESET_FILTER, &r, &a);
}
r = *rm;
a = *am;
@@ -3636,7 +3964,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
struct pf_state key;
struct tcphdr *th = pd->hdr.tcp;
u_int16_t win = ntohs(th->th_win);
- u_int32_t ack, end, seq;
+ u_int32_t ack, end, seq, orig_seq;
u_int8_t sws, dws;
int ackskew;
int copyback = 0;
@@ -3667,21 +3995,32 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
}
if ((*state)->src.state == PF_TCPS_PROXY_SRC) {
- if (direction != (*state)->direction)
+ if (direction != (*state)->direction) {
+ REASON_SET(reason, PFRES_SYNPROXY);
return (PF_SYNPROXY_DROP);
+ }
if (th->th_flags & TH_SYN) {
- if (ntohl(th->th_seq) != (*state)->src.seqlo)
+ if (ntohl(th->th_seq) != (*state)->src.seqlo) {
+ REASON_SET(reason, PFRES_SYNPROXY);
return (PF_DROP);
+ }
pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
pd->src, th->th_dport, th->th_sport,
(*state)->src.seqhi, ntohl(th->th_seq) + 1,
- TH_SYN|TH_ACK, 0, (*state)->src.mss, 0);
+ TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1,
+ NULL, NULL);
+ REASON_SET(reason, PFRES_SYNPROXY);
return (PF_SYNPROXY_DROP);
} else if (!(th->th_flags & TH_ACK) ||
(ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
- (ntohl(th->th_seq) != (*state)->src.seqlo + 1))
+ (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
+ REASON_SET(reason, PFRES_SYNPROXY);
return (PF_DROP);
- else
+ } else if ((*state)->src_node != NULL &&
+ pf_src_connlimit(state)) {
+ REASON_SET(reason, PFRES_SRCLIMIT);
+ return (PF_DROP);
+ } else
(*state)->src.state = PF_TCPS_PROXY_DST;
}
if ((*state)->src.state == PF_TCPS_PROXY_DST) {
@@ -3697,31 +4036,37 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
if (direction == (*state)->direction) {
if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) ||
(ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
- (ntohl(th->th_seq) != (*state)->src.seqlo + 1))
+ (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
+ REASON_SET(reason, PFRES_SYNPROXY);
return (PF_DROP);
+ }
(*state)->src.max_win = MAX(ntohs(th->th_win), 1);
if ((*state)->dst.seqhi == 1)
- (*state)->dst.seqhi = arc4random();
+ (*state)->dst.seqhi = htonl(arc4random());
pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
&dst->addr, src->port, dst->port,
(*state)->dst.seqhi, 0, TH_SYN, 0,
- (*state)->src.mss, 0);
+ (*state)->src.mss, 0, 0, NULL, NULL);
+ REASON_SET(reason, PFRES_SYNPROXY);
return (PF_SYNPROXY_DROP);
} else if (((th->th_flags & (TH_SYN|TH_ACK)) !=
(TH_SYN|TH_ACK)) ||
- (ntohl(th->th_ack) != (*state)->dst.seqhi + 1))
+ (ntohl(th->th_ack) != (*state)->dst.seqhi + 1)) {
+ REASON_SET(reason, PFRES_SYNPROXY);
return (PF_DROP);
- else {
+ } else {
(*state)->dst.max_win = MAX(ntohs(th->th_win), 1);
(*state)->dst.seqlo = ntohl(th->th_seq);
pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
pd->src, th->th_dport, th->th_sport,
ntohl(th->th_ack), ntohl(th->th_seq) + 1,
- TH_ACK, (*state)->src.max_win, 0, 0);
+ TH_ACK, (*state)->src.max_win, 0, 0, 0,
+ NULL, NULL);
pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
&dst->addr, src->port, dst->port,
(*state)->src.seqhi + 1, (*state)->src.seqlo + 1,
- TH_ACK, (*state)->dst.max_win, 0, 0);
+ TH_ACK, (*state)->dst.max_win, 0, 0, 1,
+ NULL, NULL);
(*state)->src.seqdiff = (*state)->dst.seqhi -
(*state)->src.seqlo;
(*state)->dst.seqdiff = (*state)->src.seqhi -
@@ -3733,6 +4078,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
(*state)->src.wscale = (*state)->dst.wscale = 0;
(*state)->src.state = (*state)->dst.state =
TCPS_ESTABLISHED;
+ REASON_SET(reason, PFRES_SYNPROXY);
return (PF_SYNPROXY_DROP);
}
}
@@ -3749,7 +4095,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
* tcp_filtering.ps
*/
- seq = ntohl(th->th_seq);
+ orig_seq = seq = ntohl(th->th_seq);
if (src->seqlo == 0) {
/* First packet from this end. Set its state */
@@ -3763,7 +4109,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
/* Deferred generation of sequence number modulator */
if (dst->seqdiff && !src->seqdiff) {
- while ((src->seqdiff = arc4random()) == 0)
+ while ((src->seqdiff = htonl(arc4random())) == 0)
;
ack = ntohl(th->th_ack) - dst->seqdiff;
pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
@@ -3859,8 +4205,17 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
/* Retrans: not more than one window back */
(ackskew >= -MAXACKWINDOW) &&
/* Acking not more than one reassembled fragment backwards */
- (ackskew <= (MAXACKWINDOW << sws))) {
+ (ackskew <= (MAXACKWINDOW << sws)) &&
/* Acking not more than one window forward */
+ ((th->th_flags & TH_RST) == 0 || orig_seq == src->seqlo ||
+ (pd->flags & PFDESC_IP_REAS) == 0)) {
+ /* Require an exact sequence match on resets when possible */
+
+ if (dst->scrub || src->scrub) {
+ if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
+ *state, src, dst, &copyback))
+ return (PF_DROP);
+ }
/* update max window */
if (src->max_win < win)
@@ -3881,16 +4236,22 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
if (src->state < TCPS_CLOSING)
src->state = TCPS_CLOSING;
if (th->th_flags & TH_ACK) {
- if (dst->state == TCPS_SYN_SENT)
+ if (dst->state == TCPS_SYN_SENT) {
dst->state = TCPS_ESTABLISHED;
- else if (dst->state == TCPS_CLOSING)
+ if (src->state == TCPS_ESTABLISHED &&
+ (*state)->src_node != NULL &&
+ pf_src_connlimit(state)) {
+ REASON_SET(reason, PFRES_SRCLIMIT);
+ return (PF_DROP);
+ }
+ } else if (dst->state == TCPS_CLOSING)
dst->state = TCPS_FIN_WAIT_2;
}
if (th->th_flags & TH_RST)
src->state = dst->state = TCPS_TIME_WAIT;
/* update expire time */
- (*state)->expire = time.tv_sec;
+ (*state)->expire = time_second;
if (src->state >= TCPS_FIN_WAIT_2 &&
dst->state >= TCPS_FIN_WAIT_2)
(*state)->timeout = PFTM_TCP_CLOSED;
@@ -3946,6 +4307,12 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
(*state)->packets[0], (*state)->packets[1]);
}
+ if (dst->scrub || src->scrub) {
+ if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
+ *state, src, dst, &copyback))
+ return (PF_DROP);
+ }
+
/* update max window */
if (src->max_win < win)
src->max_win = win;
@@ -3973,19 +4340,13 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
if ((*state)->dst.state == TCPS_SYN_SENT &&
(*state)->src.state == TCPS_SYN_SENT) {
/* Send RST for state mismatches during handshake */
- if (!(th->th_flags & TH_RST)) {
- u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
-
- if (th->th_flags & TH_SYN)
- ack++;
- if (th->th_flags & TH_FIN)
- ack++;
+ if (!(th->th_flags & TH_RST))
pf_send_tcp((*state)->rule.ptr, pd->af,
pd->dst, pd->src, th->th_dport,
- th->th_sport, ntohl(th->th_ack), ack,
- TH_RST|TH_ACK, 0, 0,
- (*state)->rule.ptr->return_ttl);
- }
+ th->th_sport, ntohl(th->th_ack), 0,
+ TH_RST, 0, 0,
+ (*state)->rule.ptr->return_ttl, 1,
+ pd->eh, kif->pfik_ifp);
src->seqlo = 0;
src->seqhi = 1;
src->max_win = 1;
@@ -4007,15 +4368,10 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) ?' ' :'5',
SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW) ?' ' :'6');
}
+ REASON_SET(reason, PFRES_BADSTATE);
return (PF_DROP);
}
- if (dst->scrub || src->scrub) {
- if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
- src, dst, &copyback))
- return (PF_DROP);
- }
-
/* Any packets which have gotten here are to be passed */
/* translate source/destination address, if necessary */
@@ -4076,7 +4432,7 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
dst->state = PFUDPS_MULTIPLE;
/* update expire time */
- (*state)->expire = time.tv_sec;
+ (*state)->expire = time_second;
if (src->state == PFUDPS_MULTIPLE && dst->state == PFUDPS_MULTIPLE)
(*state)->timeout = PFTM_UDP_MULTIPLE;
else
@@ -4100,7 +4456,7 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
int
pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
- struct mbuf *m, int off, void *h, struct pf_pdesc *pd)
+ struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason)
{
struct pf_addr *saddr = pd->src, *daddr = pd->dst;
u_int16_t icmpid, *icmpsum;
@@ -4161,7 +4517,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
STATE_LOOKUP();
- (*state)->expire = time.tv_sec;
+ (*state)->expire = time_second;
(*state)->timeout = PFTM_ICMP_ERROR_REPLY;
/* translate source/destination address, if necessary */
@@ -4236,7 +4592,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
ipoff2 = off + ICMP_MINLEN;
if (!pf_pull_hdr(m, ipoff2, &h2, sizeof(h2),
- NULL, NULL, pd2.af)) {
+ NULL, reason, pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: ICMP error message too short "
"(ip)\n"));
@@ -4246,8 +4602,10 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
* ICMP error messages don't refer to non-first
* fragments
*/
- if (h2.ip_off & htons(IP_OFFMASK))
+ if (h2.ip_off & htons(IP_OFFMASK)) {
+ REASON_SET(reason, PFRES_FRAG);
return (PF_DROP);
+ }
/* offset of protocol header that follows h2 */
off2 = ipoff2 + (h2.ip_hl << 2);
@@ -4263,7 +4621,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
ipoff2 = off + sizeof(struct icmp6_hdr);
if (!pf_pull_hdr(m, ipoff2, &h2_6, sizeof(h2_6),
- NULL, NULL, pd2.af)) {
+ NULL, reason, pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: ICMP error message too short "
"(ip6)\n"));
@@ -4281,6 +4639,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
* ICMPv6 error messages for
* non-first fragments
*/
+ REASON_SET(reason, PFRES_FRAG);
return (PF_DROP);
case IPPROTO_AH:
case IPPROTO_HOPOPTS:
@@ -4290,7 +4649,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
struct ip6_ext opt6;
if (!pf_pull_hdr(m, off2, &opt6,
- sizeof(opt6), NULL, NULL, pd2.af)) {
+ sizeof(opt6), NULL, reason,
+ pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: ICMPv6 short opt\n"));
return (PF_DROP);
@@ -4326,7 +4686,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
* expected. Don't access any TCP header fields after
* th_seq, an ackskew test is not possible.
*/
- if (!pf_pull_hdr(m, off2, &th, 8, NULL, NULL, pd2.af)) {
+ if (!pf_pull_hdr(m, off2, &th, 8, NULL, reason,
+ pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: ICMP error message too short "
"(tcp)\n"));
@@ -4383,6 +4744,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
pf_print_state(*state);
printf(" seq=%u\n", seq);
}
+ REASON_SET(reason, PFRES_BADSTATE);
return (PF_DROP);
}
@@ -4434,7 +4796,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
struct pf_state key;
if (!pf_pull_hdr(m, off2, &uh, sizeof(uh),
- NULL, NULL, pd2.af)) {
+ NULL, reason, pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: ICMP error message too short "
"(udp)\n"));
@@ -4501,7 +4863,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
struct pf_state key;
if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN,
- NULL, NULL, pd2.af)) {
+ NULL, reason, pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: ICMP error message too short i"
"(icmp)\n"));
@@ -4553,7 +4915,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
struct pf_state key;
if (!pf_pull_hdr(m, off2, &iih,
- sizeof(struct icmp6_hdr), NULL, NULL, pd2.af)) {
+ sizeof(struct icmp6_hdr), NULL, reason, pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: ICMP error message too short "
"(icmp6)\n"));
@@ -4699,7 +5061,7 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
dst->state = PFOTHERS_MULTIPLE;
/* update expire time */
- (*state)->expire = time.tv_sec;
+ (*state)->expire = time_second;
if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE)
(*state)->timeout = PFTM_OTHER_MULTIPLE;
else
@@ -4797,18 +5159,80 @@ int
pf_routable(struct pf_addr *addr, sa_family_t af)
{
struct sockaddr_in *dst;
+#ifdef INET6
+ struct sockaddr_in6 *dst6;
+ struct route_in6 ro;
+#else
struct route ro;
+#endif
+
+ bzero(&ro, sizeof(ro));
+ switch (af) {
+ case AF_INET:
+ dst = satosin(&ro.ro_dst);
+ dst->sin_family = AF_INET;
+ dst->sin_len = sizeof(*dst);
+ dst->sin_addr = addr->v4;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
+ dst6->sin6_family = AF_INET6;
+ dst6->sin6_len = sizeof(*dst6);
+ dst6->sin6_addr = addr->v6;
+ break;
+#endif /* INET6 */
+ default:
+ return (0);
+ }
+
+ rtalloc_noclone((struct route *)&ro, NO_CLONING);
+
+ if (ro.ro_rt != NULL) {
+ RTFREE(ro.ro_rt);
+ return (1);
+ }
+
+ return (0);
+}
+
+int
+pf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw)
+{
+ struct sockaddr_in *dst;
+#ifdef INET6
+ struct sockaddr_in6 *dst6;
+ struct route_in6 ro;
+#else
+ struct route ro;
+#endif
int ret = 0;
bzero(&ro, sizeof(ro));
- dst = satosin(&ro.ro_dst);
- dst->sin_family = af;
- dst->sin_len = sizeof(*dst);
- dst->sin_addr = addr->v4;
- rtalloc_noclone(&ro, NO_CLONING);
+ switch (af) {
+ case AF_INET:
+ dst = satosin(&ro.ro_dst);
+ dst->sin_family = AF_INET;
+ dst->sin_len = sizeof(*dst);
+ dst->sin_addr = addr->v4;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
+ dst6->sin6_family = AF_INET6;
+ dst6->sin6_len = sizeof(*dst6);
+ dst6->sin6_addr = addr->v6;
+ break;
+#endif /* INET6 */
+ default:
+ return (0);
+ }
+
+ rtalloc_noclone((struct route *)&ro, NO_CLONING);
if (ro.ro_rt != NULL) {
- ret = 1;
+ if (ro.ro_rt->rt_labelid == aw->v.rtlabel)
+ ret = 1;
RTFREE(ro.ro_rt);
}
@@ -4856,17 +5280,18 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
if (r->rt == PF_DUPTO) {
if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
return;
- if ((mtag = m_tag_copy(mtag)) == NULL)
- goto bad;
- m_tag_prepend(m0, mtag);
} else {
if ((r->rt == PF_REPLYTO) == (r->direction == dir))
return;
m0 = *m;
}
- if (m0->m_len < sizeof(struct ip))
- panic("pf_route: m0->m_len < sizeof(struct ip)");
+ if (m0->m_len < sizeof(struct ip)) {
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_route: m0->m_len < sizeof(struct ip)\n"));
+ goto bad;
+ }
+
ip = mtod(m0, struct ip *);
ro = &iproute;
@@ -4889,8 +5314,11 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
if (ro->ro_rt->rt_flags & RTF_GATEWAY)
dst = satosin(ro->ro_rt->rt_gateway);
} else {
- if (TAILQ_EMPTY(&r->rpool.list))
- panic("pf_route: TAILQ_EMPTY(&r->rpool.list)");
+ if (TAILQ_EMPTY(&r->rpool.list)) {
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_route: TAILQ_EMPTY(&r->rpool.list)\n"));
+ goto bad;
+ }
if (s == NULL) {
pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src,
&naddr, NULL, &sn);
@@ -4909,12 +5337,15 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
goto bad;
if (oifp != ifp) {
- if (pf_test(PF_OUT, ifp, &m0) != PF_PASS)
+ if (pf_test(PF_OUT, ifp, &m0, NULL) != PF_PASS)
goto bad;
else if (m0 == NULL)
goto done;
- if (m0->m_len < sizeof(struct ip))
- panic("pf_route: m0->m_len < sizeof(struct ip)");
+ if (m0->m_len < sizeof(struct ip)) {
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_route: m0->m_len < sizeof(struct ip)\n"));
+ goto bad;
+ }
ip = mtod(m0, struct ip *);
}
@@ -5053,17 +5484,17 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
if (r->rt == PF_DUPTO) {
if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
return;
- if ((mtag = m_tag_copy(mtag)) == NULL)
- goto bad;
- m_tag_prepend(m0, mtag);
} else {
if ((r->rt == PF_REPLYTO) == (r->direction == dir))
return;
m0 = *m;
}
- if (m0->m_len < sizeof(struct ip6_hdr))
- panic("pf_route6: m0->m_len < sizeof(struct ip6_hdr)");
+ if (m0->m_len < sizeof(struct ip6_hdr)) {
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
+ goto bad;
+ }
ip6 = mtod(m0, struct ip6_hdr *);
ro = &ip6route;
@@ -5083,8 +5514,11 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
return;
}
- if (TAILQ_EMPTY(&r->rpool.list))
- panic("pf_route6: TAILQ_EMPTY(&r->rpool.list)");
+ if (TAILQ_EMPTY(&r->rpool.list)) {
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_route6: TAILQ_EMPTY(&r->rpool.list)\n"));
+ goto bad;
+ }
if (s == NULL) {
pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src,
&naddr, NULL, &sn);
@@ -5102,12 +5536,15 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
goto bad;
if (oifp != ifp) {
- if (pf_test6(PF_OUT, ifp, &m0) != PF_PASS)
+ if (pf_test6(PF_OUT, ifp, &m0, NULL) != PF_PASS)
goto bad;
else if (m0 == NULL)
goto done;
- if (m0->m_len < sizeof(struct ip6_hdr))
- panic("pf_route6: m0->m_len < sizeof(struct ip6_hdr)");
+ if (m0->m_len < sizeof(struct ip6_hdr)) {
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
+ goto bad;
+ }
ip6 = mtod(m0, struct ip6_hdr *);
}
@@ -5178,7 +5615,8 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p,
return (1);
if (m->m_pkthdr.len < off + len)
return (1);
- switch (af) {
+ switch (af) {
+#ifdef INET
case AF_INET:
if (p == IPPROTO_ICMP) {
if (m->m_len < off)
@@ -5194,6 +5632,7 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p,
sum = in4_cksum(m, p, off, len);
}
break;
+#endif /* INET */
#ifdef INET6
case AF_INET6:
if (m->m_len < sizeof(struct ip6_hdr))
@@ -5244,7 +5683,8 @@ pf_add_mbuf_tag(struct mbuf *m, u_int tag)
#ifdef INET
int
-pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
+pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
+ struct ether_header *eh)
{
struct pfi_kif *kif;
u_short action, reason = 0, log = 0;
@@ -5260,14 +5700,22 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
(m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL))
return (PF_PASS);
+ if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
+ ifp = ifp->if_carpdev;
+
kif = pfi_index2kif[ifp->if_index];
- if (kif == NULL)
+ if (kif == NULL) {
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_test: kif == NULL, if_xname %s\n", ifp->if_xname));
return (PF_DROP);
+ }
+ if (kif->pfik_flags & PFI_IFLAG_SKIP)
+ return (PF_PASS);
#ifdef DIAGNOSTIC
if ((m->m_flags & M_PKTHDR) == 0)
panic("non-M_PKTHDR is passed to pf_test");
-#endif
+#endif /* DIAGNOSTIC */
memset(&pd, 0, sizeof(pd));
if (m->m_pkthdr.len < (int)sizeof(*h)) {
@@ -5278,7 +5726,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
}
/* We do IP header normalization and packet reassembly here */
- if (pf_normalize_ip(m0, dir, kif, &reason) != PF_PASS) {
+ if (pf_normalize_ip(m0, dir, kif, &reason, &pd) != PF_PASS) {
action = PF_DROP;
goto done;
}
@@ -5301,6 +5749,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
pd.af = AF_INET;
pd.tos = h->ip_tos;
pd.tot_len = ntohs(h->ip_len);
+ pd.eh = eh;
/* handle fragments that didn't get reassembled by normalization */
if (h->ip_off & htons(IP_MF | IP_OFFMASK)) {
@@ -5336,13 +5785,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
if (action == PF_PASS) {
#if NPFSYNC
pfsync_update_state(s);
-#endif
+#endif /* NPFSYNC */
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
action = pf_test_tcp(&r, &s, dir, kif,
- m, off, h, &pd, &a, &ruleset);
+ m, off, h, &pd, &a, &ruleset, &ipintrq);
break;
}
@@ -5370,13 +5819,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
if (action == PF_PASS) {
#if NPFSYNC
pfsync_update_state(s);
-#endif
+#endif /* NPFSYNC */
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
action = pf_test_udp(&r, &s, dir, kif,
- m, off, h, &pd, &a, &ruleset);
+ m, off, h, &pd, &a, &ruleset, &ipintrq);
break;
}
@@ -5394,17 +5843,18 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
action = PF_DROP;
goto done;
}
- action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd);
+ action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd,
+ &reason);
if (action == PF_PASS) {
#if NPFSYNC
pfsync_update_state(s);
-#endif
+#endif /* NPFSYNC */
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
action = pf_test_icmp(&r, &s, dir, kif,
- m, off, h, &pd, &a, &ruleset);
+ m, off, h, &pd, &a, &ruleset, &ipintrq);
break;
}
@@ -5413,13 +5863,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
if (action == PF_PASS) {
#if NPFSYNC
pfsync_update_state(s);
-#endif
+#endif /* NPFSYNC */
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
action = pf_test_other(&r, &s, dir, kif, m, off, h,
- &pd, &a, &ruleset);
+ &pd, &a, &ruleset, &ipintrq);
break;
}
@@ -5427,12 +5877,15 @@ done:
if (action == PF_PASS && h->ip_hl > 5 &&
!((s && s->allow_opts) || r->allow_opts)) {
action = PF_DROP;
- REASON_SET(&reason, PFRES_SHORT);
+ REASON_SET(&reason, PFRES_IPOPTIONS);
log = 1;
DPFPRINTF(PF_DEBUG_MISC,
("pf: dropping packet with ip options\n"));
}
+ if (s && s->tag)
+ pf_tag_packet(m, pf_get_tag(m), s->tag);
+
#ifdef ALTQ
if (action == PF_PASS && r->qid) {
struct m_tag *mtag;
@@ -5451,7 +5904,7 @@ done:
m_tag_prepend(m, mtag);
}
}
-#endif
+#endif /* ALTQ */
/*
* connections redirected to loopback should not match sockets
@@ -5526,12 +5979,12 @@ done:
pfr_update_stats(tr->src.addr.p.tbl, (s == NULL ||
s->direction == dir) ? pd.src : pd.dst, pd.af,
pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
- tr->src.not);
+ tr->src.neg);
if (tr->dst.addr.type == PF_ADDR_TABLE)
pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL ||
s->direction == dir) ? pd.dst : pd.src, pd.af,
pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
- tr->dst.not);
+ tr->dst.neg);
}
@@ -5549,7 +6002,8 @@ done:
#ifdef INET6
int
-pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
+pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
+ struct ether_header *eh)
{
struct pfi_kif *kif;
u_short action, reason = 0, log = 0;
@@ -5565,14 +6019,22 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
(m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL))
return (PF_PASS);
+ if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
+ ifp = ifp->if_carpdev;
+
kif = pfi_index2kif[ifp->if_index];
- if (kif == NULL)
+ if (kif == NULL) {
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_test6: kif == NULL, if_xname %s\n", ifp->if_xname));
return (PF_DROP);
+ }
+ if (kif->pfik_flags & PFI_IFLAG_SKIP)
+ return (PF_PASS);
#ifdef DIAGNOSTIC
if ((m->m_flags & M_PKTHDR) == 0)
- panic("non-M_PKTHDR is passed to pf_test");
-#endif
+ panic("non-M_PKTHDR is passed to pf_test6");
+#endif /* DIAGNOSTIC */
memset(&pd, 0, sizeof(pd));
if (m->m_pkthdr.len < (int)sizeof(*h)) {
@@ -5583,7 +6045,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
}
/* We do IP header normalization and packet reassembly here */
- if (pf_normalize_ip6(m0, dir, kif, &reason) != PF_PASS) {
+ if (pf_normalize_ip6(m0, dir, kif, &reason, &pd) != PF_PASS) {
action = PF_DROP;
goto done;
}
@@ -5597,6 +6059,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
pd.af = AF_INET6;
pd.tos = 0;
pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr);
+ pd.eh = eh;
off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr);
pd.proto = h->ip6_nxt;
@@ -5616,11 +6079,10 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
struct ip6_ext opt6;
if (!pf_pull_hdr(m, off, &opt6, sizeof(opt6),
- NULL, NULL, pd.af)) {
+ NULL, &reason, pd.af)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: IPv6 short opt\n"));
action = PF_DROP;
- REASON_SET(&reason, PFRES_SHORT);
log = 1;
goto done;
}
@@ -5650,8 +6112,10 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
goto done;
}
if (dir == PF_IN && pf_check_proto_cksum(m, off,
- ntohs(h->ip6_plen), IPPROTO_TCP, AF_INET6)) {
+ ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
+ IPPROTO_TCP, AF_INET6)) {
action = PF_DROP;
+ REASON_SET(&reason, PFRES_PROTCKSUM);
goto done;
}
pd.p_len = pd.tot_len - off - (th.th_off << 2);
@@ -5663,13 +6127,13 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
if (action == PF_PASS) {
#if NPFSYNC
pfsync_update_state(s);
-#endif
+#endif /* NPFSYNC */
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
action = pf_test_tcp(&r, &s, dir, kif,
- m, off, h, &pd, &a, &ruleset);
+ m, off, h, &pd, &a, &ruleset, &ip6intrq);
break;
}
@@ -5683,8 +6147,10 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
goto done;
}
if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
- off, ntohs(h->ip6_plen), IPPROTO_UDP, AF_INET6)) {
+ off, ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
+ IPPROTO_UDP, AF_INET6)) {
action = PF_DROP;
+ REASON_SET(&reason, PFRES_PROTCKSUM);
goto done;
}
if (uh.uh_dport == 0 ||
@@ -5697,13 +6163,13 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
if (action == PF_PASS) {
#if NPFSYNC
pfsync_update_state(s);
-#endif
+#endif /* NPFSYNC */
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
action = pf_test_udp(&r, &s, dir, kif,
- m, off, h, &pd, &a, &ruleset);
+ m, off, h, &pd, &a, &ruleset, &ip6intrq);
break;
}
@@ -5717,40 +6183,48 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
goto done;
}
if (dir == PF_IN && pf_check_proto_cksum(m, off,
- ntohs(h->ip6_plen), IPPROTO_ICMPV6, AF_INET6)) {
+ ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
+ IPPROTO_ICMPV6, AF_INET6)) {
action = PF_DROP;
+ REASON_SET(&reason, PFRES_PROTCKSUM);
goto done;
}
action = pf_test_state_icmp(&s, dir, kif,
- m, off, h, &pd);
+ m, off, h, &pd, &reason);
if (action == PF_PASS) {
#if NPFSYNC
pfsync_update_state(s);
-#endif
+#endif /* NPFSYNC */
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
action = pf_test_icmp(&r, &s, dir, kif,
- m, off, h, &pd, &a, &ruleset);
+ m, off, h, &pd, &a, &ruleset, &ip6intrq);
break;
}
default:
action = pf_test_state_other(&s, dir, kif, &pd);
if (action == PF_PASS) {
+#if NPFSYNC
+ pfsync_update_state(s);
+#endif /* NPFSYNC */
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
action = pf_test_other(&r, &s, dir, kif, m, off, h,
- &pd, &a, &ruleset);
+ &pd, &a, &ruleset, &ip6intrq);
break;
}
done:
/* XXX handle IPv6 options, if not allowed. not implemented. */
+ if (s && s->tag)
+ pf_tag_packet(m, pf_get_tag(m), s->tag);
+
#ifdef ALTQ
if (action == PF_PASS && r->qid) {
struct m_tag *mtag;
@@ -5769,7 +6243,7 @@ done:
m_tag_prepend(m, mtag);
}
}
-#endif
+#endif /* ALTQ */
if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
@@ -5839,12 +6313,12 @@ done:
pfr_update_stats(tr->src.addr.p.tbl, (s == NULL ||
s->direction == dir) ? pd.src : pd.dst, pd.af,
pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
- tr->src.not);
+ tr->src.neg);
if (tr->dst.addr.type == PF_ADDR_TABLE)
pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL ||
s->direction == dir) ? pd.dst : pd.src, pd.af,
pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
- tr->dst.not);
+ tr->dst.neg);
}
@@ -5859,3 +6333,12 @@ done:
return (action);
}
#endif /* INET6 */
+
+int
+pf_check_congestion(struct ifqueue *ifq)
+{
+ if (ifq->ifq_congestion)
+ return (1);
+ else
+ return (0);
+}
OpenPOWER on IntegriCloud