summaryrefslogtreecommitdiff
path: root/net/pf.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/pf.c')
-rw-r--r--net/pf.c2218
1 files changed, 784 insertions, 1434 deletions
diff --git a/net/pf.c b/net/pf.c
index 097334e28101..f4b242a74747 100644
--- a/net/pf.c
+++ b/net/pf.c
@@ -1,5 +1,4 @@
-/* $OpenBSD: pf.c,v 1.527 2007/02/22 15:23:23 pyr Exp $ */
-/* add: $OpenBSD: pf.c,v 1.559 2007/09/18 18:45:59 markus Exp $ */
+/* $OpenBSD: pf.c,v 1.552 2007/08/21 15:57:27 dhartmei Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -96,6 +95,10 @@
* Global variables
*/
+/* state tables */
+struct pf_state_tree_lan_ext pf_statetbl_lan_ext;
+struct pf_state_tree_ext_gwy pf_statetbl_ext_gwy;
+
struct pf_altqqueue pf_altqs[2];
struct pf_palist pf_pabuf;
struct pf_altqqueue *pf_altqs_active;
@@ -114,8 +117,9 @@ struct pf_anchor_stackframe {
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;
+struct pool pf_src_tree_pl, pf_rule_pl, pf_pooladdr_pl;
+struct pool pf_state_pl, pf_state_key_pl;
+struct pool pf_altq_pl;
void pf_print_host(struct pf_addr *, u_int16_t, u_int8_t);
@@ -153,22 +157,13 @@ struct pf_rule *pf_get_translation(struct pf_pdesc *, struct mbuf *,
struct pf_addr *, u_int16_t,
struct pf_addr *, u_int16_t,
struct pf_addr *, u_int16_t *);
-int pf_test_tcp(struct pf_rule **, struct pf_state **,
+void pf_attach_state(struct pf_state_key *,
+ struct pf_state *, int);
+void pf_detach_state(struct pf_state *, int);
+int pf_test_rule(struct pf_rule **, struct pf_state **,
int, struct pfi_kif *, struct mbuf *, int,
void *, struct pf_pdesc *, struct pf_rule **,
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 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 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 ifqueue *);
int pf_test_fragment(struct pf_rule **, int,
struct pfi_kif *, struct mbuf *, void *,
struct pf_pdesc *, struct pf_rule **,
@@ -184,8 +179,9 @@ int pf_test_state_icmp(struct pf_state **, int,
void *, struct pf_pdesc *, u_short *);
int pf_test_state_other(struct pf_state **, int,
struct pfi_kif *, struct pf_pdesc *);
-int pf_match_tag(struct mbuf *, struct pf_rule *,
- struct pf_mtag *, int *);
+int pf_match_tag(struct mbuf *, struct pf_rule *, int *);
+void pf_step_into_anchor(int *, struct pf_ruleset **, int,
+ struct pf_rule **, struct pf_rule **, int *);
int pf_step_out_of_anchor(int *, struct pf_ruleset **,
int, struct pf_rule **, struct pf_rule **,
int *);
@@ -217,9 +213,11 @@ int pf_check_proto_cksum(struct mbuf *, int, int,
u_int8_t, sa_family_t);
int pf_addr_wrap_neq(struct pf_addr_wrap *,
struct pf_addr_wrap *);
-struct pf_state *pf_find_state_recurse(struct pfi_kif *,
- struct pf_state_cmp *, u_int8_t);
+struct pf_state *pf_find_state(struct pfi_kif *,
+ struct pf_state_key_cmp *, u_int8_t);
int pf_src_connlimit(struct pf_state **);
+void pf_stateins_err(const char *, struct pf_state *,
+ struct pfi_kif *);
int pf_check_congestion(struct ifqueue *);
extern struct pool pfr_ktable_pl;
@@ -236,11 +234,9 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
#define STATE_LOOKUP() \
do { \
if (direction == PF_IN) \
- *state = pf_find_state_recurse( \
- kif, &key, PF_EXT_GWY); \
+ *state = pf_find_state(kif, &key, PF_EXT_GWY); \
else \
- *state = pf_find_state_recurse( \
- kif, &key, PF_LAN_EXT); \
+ *state = pf_find_state(kif, &key, PF_LAN_EXT); \
if (*state == NULL || (*state)->timeout == PFTM_PURGE) \
return (PF_DROP); \
if (direction == PF_OUT && \
@@ -253,13 +249,13 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
return (PF_PASS); \
} while (0)
-#define STATE_TRANSLATE(s) \
- (s)->lan.addr.addr32[0] != (s)->gwy.addr.addr32[0] || \
- ((s)->af == AF_INET6 && \
- ((s)->lan.addr.addr32[1] != (s)->gwy.addr.addr32[1] || \
- (s)->lan.addr.addr32[2] != (s)->gwy.addr.addr32[2] || \
- (s)->lan.addr.addr32[3] != (s)->gwy.addr.addr32[3])) || \
- (s)->lan.port != (s)->gwy.port
+#define STATE_TRANSLATE(sk) \
+ (sk)->lan.addr.addr32[0] != (sk)->gwy.addr.addr32[0] || \
+ ((sk)->af == AF_INET6 && \
+ ((sk)->lan.addr.addr32[1] != (sk)->gwy.addr.addr32[1] || \
+ (sk)->lan.addr.addr32[2] != (sk)->gwy.addr.addr32[2] || \
+ (sk)->lan.addr.addr32[3] != (sk)->gwy.addr.addr32[3])) || \
+ (sk)->lan.port != (sk)->gwy.port
#define BOUND_IFACE(r, k) \
((r)->rule_flag & PFRULE_IFBOUND) ? (k) : pfi_all
@@ -283,10 +279,10 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
} 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 *);
-static __inline int pf_state_compare_ext_gwy(struct pf_state *,
- struct pf_state *);
+static __inline int pf_state_compare_lan_ext(struct pf_state_key *,
+ struct pf_state_key *);
+static __inline int pf_state_compare_ext_gwy(struct pf_state_key *,
+ struct pf_state_key *);
static __inline int pf_state_compare_id(struct pf_state *,
struct pf_state *);
@@ -296,12 +292,15 @@ struct pf_state_tree_id tree_id;
struct pf_state_queue state_list;
RB_GENERATE(pf_src_tree, pf_src_node, entry, pf_src_compare);
-RB_GENERATE(pf_state_tree_lan_ext, pf_state,
- u.s.entry_lan_ext, pf_state_compare_lan_ext);
-RB_GENERATE(pf_state_tree_ext_gwy, pf_state,
- u.s.entry_ext_gwy, pf_state_compare_ext_gwy);
+RB_GENERATE(pf_state_tree_lan_ext, pf_state_key,
+ entry_lan_ext, pf_state_compare_lan_ext);
+RB_GENERATE(pf_state_tree_ext_gwy, pf_state_key,
+ entry_ext_gwy, pf_state_compare_ext_gwy);
RB_GENERATE(pf_state_tree_id, pf_state,
- u.s.entry_id, pf_state_compare_id);
+ entry_id, pf_state_compare_id);
+
+#define PF_DT_SKIP_LANEXT 0x01
+#define PF_DT_SKIP_EXTGWY 0x02
static __inline int
pf_src_compare(struct pf_src_node *a, struct pf_src_node *b)
@@ -348,7 +347,7 @@ pf_src_compare(struct pf_src_node *a, struct pf_src_node *b)
}
static __inline int
-pf_state_compare_lan_ext(struct pf_state *a, struct pf_state *b)
+pf_state_compare_lan_ext(struct pf_state_key *a, struct pf_state_key *b)
{
int diff;
@@ -416,7 +415,7 @@ pf_state_compare_lan_ext(struct pf_state *a, struct pf_state *b)
}
static __inline int
-pf_state_compare_ext_gwy(struct pf_state *a, struct pf_state *b)
+pf_state_compare_ext_gwy(struct pf_state_key *a, struct pf_state_key *b)
{
int diff;
@@ -522,74 +521,71 @@ struct pf_state *
pf_find_state_byid(struct pf_state_cmp *key)
{
pf_status.fcounters[FCNT_STATE_SEARCH]++;
+
return (RB_FIND(pf_state_tree_id, &tree_id, (struct pf_state *)key));
}
struct pf_state *
-pf_find_state_recurse(struct pfi_kif *kif, struct pf_state_cmp *key, u_int8_t tree)
+pf_find_state(struct pfi_kif *kif, struct pf_state_key_cmp *key, u_int8_t tree)
{
- struct pf_state *s;
+ struct pf_state_key *sk;
+ struct pf_state *s;
pf_status.fcounters[FCNT_STATE_SEARCH]++;
switch (tree) {
case PF_LAN_EXT:
- if ((s = RB_FIND(pf_state_tree_lan_ext, &kif->pfik_lan_ext,
- (struct pf_state *)key)) != NULL)
- return (s);
- if ((s = RB_FIND(pf_state_tree_lan_ext, &pfi_all->pfik_lan_ext,
- (struct pf_state *)key)) != NULL)
- return (s);
- return (NULL);
+ sk = RB_FIND(pf_state_tree_lan_ext, &pf_statetbl_lan_ext,
+ (struct pf_state_key *)key);
+ break;
case PF_EXT_GWY:
- if ((s = RB_FIND(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy,
- (struct pf_state *)key)) != NULL)
- return (s);
- if ((s = RB_FIND(pf_state_tree_ext_gwy, &pfi_all->pfik_ext_gwy,
- (struct pf_state *)key)) != NULL)
- return (s);
- return (NULL);
+ sk = RB_FIND(pf_state_tree_ext_gwy, &pf_statetbl_ext_gwy,
+ (struct pf_state_key *)key);
+ break;
default:
- panic("pf_find_state_recurse");
+ panic("pf_find_state");
}
+
+ /* list is sorted, if-bound states before floating ones */
+ if (sk != NULL)
+ TAILQ_FOREACH(s, &sk->states, next)
+ if (s->kif == pfi_all || s->kif == kif)
+ return (s);
+
+ return (NULL);
}
struct pf_state *
-pf_find_state_all(struct pf_state_cmp *key, u_int8_t tree, int *more)
+pf_find_state_all(struct pf_state_key_cmp *key, u_int8_t tree, int *more)
{
- struct pf_state *s, *ss = NULL;
- struct pfi_kif *kif;
+ struct pf_state_key *sk;
+ struct pf_state *s, *ret = NULL;
pf_status.fcounters[FCNT_STATE_SEARCH]++;
switch (tree) {
case PF_LAN_EXT:
- TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) {
- s = RB_FIND(pf_state_tree_lan_ext,
- &kif->pfik_lan_ext, (struct pf_state *)key);
- if (s == NULL)
- continue;
- if (more == NULL)
- return (s);
- ss = s;
- (*more)++;
- }
- return (ss);
+ sk = RB_FIND(pf_state_tree_lan_ext,
+ &pf_statetbl_lan_ext, (struct pf_state_key *)key);
+ break;
case PF_EXT_GWY:
- TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) {
- s = RB_FIND(pf_state_tree_ext_gwy,
- &kif->pfik_ext_gwy, (struct pf_state *)key);
- if (s == NULL)
- continue;
- if (more == NULL)
- return (s);
- ss = s;
- (*more)++;
- }
- return (ss);
+ sk = RB_FIND(pf_state_tree_ext_gwy,
+ &pf_statetbl_ext_gwy, (struct pf_state_key *)key);
+ break;
default:
panic("pf_find_state_all");
}
+
+ if (sk != NULL) {
+ ret = TAILQ_FIRST(&sk->states);
+ if (more == NULL)
+ return (ret);
+
+ TAILQ_FOREACH(s, &sk->states, next)
+ (*more)++;
+ }
+
+ return (ret);
}
void
@@ -625,7 +621,6 @@ pf_check_threshold(struct pf_threshold *threshold)
int
pf_src_connlimit(struct pf_state **state)
{
- struct pf_state *s;
int bad = 0;
(*state)->src_node->conn++;
@@ -656,12 +651,12 @@ pf_src_connlimit(struct pf_state **state)
if (pf_status.debug >= PF_DEBUG_MISC) {
printf("pf_src_connlimit: blocking address ");
pf_print_host(&(*state)->src_node->addr, 0,
- (*state)->af);
+ (*state)->state_key->af);
}
bzero(&p, sizeof(p));
- p.pfra_af = (*state)->af;
- switch ((*state)->af) {
+ p.pfra_af = (*state)->state_key->af;
+ switch ((*state)->state_key->af) {
#ifdef INET
case AF_INET:
p.pfra_net = 32;
@@ -681,26 +676,31 @@ pf_src_connlimit(struct pf_state **state)
/* kill existing states if that's required. */
if ((*state)->rule.ptr->flush) {
- pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++;
+ struct pf_state_key *sk;
+ struct pf_state *st;
- RB_FOREACH(s, pf_state_tree_id, &tree_id) {
+ pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++;
+ RB_FOREACH(st, pf_state_tree_id, &tree_id) {
+ sk = st->state_key;
/*
* 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 &&
+ if (sk->af ==
+ (*state)->state_key->af &&
+ (((*state)->state_key->direction ==
+ PF_OUT &&
PF_AEQ(&(*state)->src_node->addr,
- &s->lan.addr, s->af)) ||
- ((*state)->direction == PF_IN &&
+ &sk->lan.addr, sk->af)) ||
+ ((*state)->state_key->direction == PF_IN &&
PF_AEQ(&(*state)->src_node->addr,
- &s->ext.addr, s->af))) &&
+ &sk->ext.addr, sk->af))) &&
((*state)->rule.ptr->flush &
PF_FLUSH_GLOBAL ||
- (*state)->rule.ptr == s->rule.ptr)) {
- s->timeout = PFTM_PURGE;
- s->src.state = s->dst.state =
+ (*state)->rule.ptr == st->rule.ptr)) {
+ st->timeout = PFTM_PURGE;
+ st->src.state = st->dst.state =
TCPS_CLOSED;
killed++;
}
@@ -782,73 +782,80 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
return (0);
}
+void
+pf_stateins_err(const char *tree, struct pf_state *s, struct pfi_kif *kif)
+{
+ struct pf_state_key *sk = s->state_key;
+
+ if (pf_status.debug >= PF_DEBUG_MISC) {
+ printf("pf: state insert failed: %s %s", tree, kif->pfik_name);
+ printf(" lan: ");
+ pf_print_host(&sk->lan.addr, sk->lan.port,
+ sk->af);
+ printf(" gwy: ");
+ pf_print_host(&sk->gwy.addr, sk->gwy.port,
+ sk->af);
+ printf(" ext: ");
+ pf_print_host(&sk->ext.addr, sk->ext.port,
+ sk->af);
+ if (s->sync_flags & PFSTATE_FROMSYNC)
+ printf(" (from sync)");
+ printf("\n");
+ }
+}
+
int
-pf_insert_state(struct pfi_kif *kif, struct pf_state *state)
+pf_insert_state(struct pfi_kif *kif, struct pf_state *s)
{
- /* Thou MUST NOT insert multiple duplicate keys */
- state->u.s.kif = kif;
- if (RB_INSERT(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state)) {
- if (pf_status.debug >= PF_DEBUG_MISC) {
- printf("pf: state insert failed: tree_lan_ext");
- printf(" lan: ");
- pf_print_host(&state->lan.addr, state->lan.port,
- state->af);
- printf(" gwy: ");
- pf_print_host(&state->gwy.addr, state->gwy.port,
- state->af);
- printf(" ext: ");
- pf_print_host(&state->ext.addr, state->ext.port,
- state->af);
- if (state->sync_flags & PFSTATE_FROMSYNC)
- printf(" (from sync)");
- printf("\n");
- }
- return (-1);
+ struct pf_state_key *cur;
+ struct pf_state *sp;
+
+ KASSERT(s->state_key != NULL);
+ s->kif = kif;
+
+ if ((cur = RB_INSERT(pf_state_tree_lan_ext, &pf_statetbl_lan_ext,
+ s->state_key)) != NULL) {
+ /* key exists. check for same kif, if none, add to key */
+ TAILQ_FOREACH(sp, &cur->states, next)
+ if (sp->kif == kif) { /* collision! */
+ pf_stateins_err("tree_lan_ext", s, kif);
+ return (-1);
+ }
+ pf_detach_state(s, PF_DT_SKIP_LANEXT|PF_DT_SKIP_EXTGWY);
+ pf_attach_state(cur, s, kif == pfi_all ? 1 : 0);
}
- if (RB_INSERT(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state)) {
- if (pf_status.debug >= PF_DEBUG_MISC) {
- printf("pf: state insert failed: tree_ext_gwy");
- printf(" lan: ");
- pf_print_host(&state->lan.addr, state->lan.port,
- state->af);
- printf(" gwy: ");
- pf_print_host(&state->gwy.addr, state->gwy.port,
- state->af);
- printf(" ext: ");
- pf_print_host(&state->ext.addr, state->ext.port,
- state->af);
- if (state->sync_flags & PFSTATE_FROMSYNC)
- printf(" (from sync)");
- printf("\n");
- }
- RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state);
+ /* if cur != NULL, we already found a state key and attached to it */
+ if (cur == NULL && (cur = RB_INSERT(pf_state_tree_ext_gwy,
+ &pf_statetbl_ext_gwy, s->state_key)) != NULL) {
+ /* must not happen. we must have found the sk above! */
+ pf_stateins_err("tree_ext_gwy", s, kif);
+ pf_detach_state(s, PF_DT_SKIP_EXTGWY);
return (-1);
}
- if (state->id == 0 && state->creatorid == 0) {
- state->id = htobe64(pf_status.stateid++);
- state->creatorid = pf_status.hostid;
+ if (s->id == 0 && s->creatorid == 0) {
+ s->id = htobe64(pf_status.stateid++);
+ s->creatorid = pf_status.hostid;
}
- if (RB_INSERT(pf_state_tree_id, &tree_id, state) != NULL) {
+ if (RB_INSERT(pf_state_tree_id, &tree_id, s) != NULL) {
if (pf_status.debug >= PF_DEBUG_MISC) {
printf("pf: state insert failed: "
"id: %016llx creatorid: %08x",
- betoh64(state->id), ntohl(state->creatorid));
- if (state->sync_flags & PFSTATE_FROMSYNC)
+ betoh64(s->id), ntohl(s->creatorid));
+ if (s->sync_flags & PFSTATE_FROMSYNC)
printf(" (from sync)");
printf("\n");
}
- RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state);
- RB_REMOVE(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state);
+ pf_detach_state(s, 0);
return (-1);
}
- TAILQ_INSERT_TAIL(&state_list, state, u.s.entry_list);
+ TAILQ_INSERT_TAIL(&state_list, s, entry_list);
pf_status.fcounters[FCNT_STATE_INSERT]++;
pf_status.states++;
pfi_kif_ref(kif, PFI_KIF_REF_STATE);
#if NPFSYNC
- pfsync_insert_state(state);
+ pfsync_insert_state(s);
#endif
return (0);
}
@@ -954,7 +961,7 @@ 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->state_key->proto == IPPROTO_TCP) {
if (s->src.tcp_est)
--s->src_node->conn;
}
@@ -983,16 +990,12 @@ void
pf_unlink_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,
+ pf_send_tcp(cur->rule.ptr, cur->state_key->af,
+ &cur->state_key->ext.addr, &cur->state_key->lan.addr,
+ cur->state_key->ext.port, cur->state_key->lan.port,
cur->src.seqhi, cur->src.seqlo + 1,
TH_RST|TH_ACK, 0, 0, 0, 1, cur->tag, NULL, NULL);
}
- RB_REMOVE(pf_state_tree_ext_gwy,
- &cur->u.s.kif->pfik_ext_gwy, cur);
- RB_REMOVE(pf_state_tree_lan_ext,
- &cur->u.s.kif->pfik_lan_ext, cur);
RB_REMOVE(pf_state_tree_id, &tree_id, cur);
#if NPFSYNC
if (cur->creatorid == pf_status.hostid)
@@ -1000,6 +1003,7 @@ pf_unlink_state(struct pf_state *cur)
#endif
cur->timeout = PFTM_UNLINKED;
pf_src_tree_remove_state(cur);
+ pf_detach_state(cur, 0);
}
/* callers should be at splsoftnet and hold the
@@ -1025,8 +1029,8 @@ pf_free_state(struct pf_state *cur)
if (--cur->anchor.ptr->states <= 0)
pf_rm_rule(NULL, cur->anchor.ptr);
pf_normalize_tcp_cleanup(cur);
- pfi_kif_unref(cur->u.s.kif, PFI_KIF_REF_STATE);
- TAILQ_REMOVE(&state_list, cur, u.s.entry_list);
+ pfi_kif_unref(cur->kif, PFI_KIF_REF_STATE);
+ TAILQ_REMOVE(&state_list, cur, entry_list);
if (cur->tag)
pf_tag_unref(cur->tag);
pool_put(&pf_state_pl, cur);
@@ -1050,7 +1054,7 @@ pf_purge_expired_states(u_int32_t maxcheck)
}
/* get next state, as cur may get deleted */
- next = TAILQ_NEXT(cur, u.s.entry_list);
+ next = TAILQ_NEXT(cur, entry_list);
if (cur->timeout == PFTM_UNLINKED) {
/* free unlinked state */
@@ -1175,7 +1179,8 @@ pf_print_host(struct pf_addr *addr, u_int16_t p, sa_family_t af)
void
pf_print_state(struct pf_state *s)
{
- switch (s->proto) {
+ struct pf_state_key *sk = s->state_key;
+ switch (sk->proto) {
case IPPROTO_TCP:
printf("TCP ");
break;
@@ -1189,14 +1194,14 @@ pf_print_state(struct pf_state *s)
printf("ICMPV6 ");
break;
default:
- printf("%u ", s->proto);
+ printf("%u ", sk->proto);
break;
}
- pf_print_host(&s->lan.addr, s->lan.port, s->af);
+ pf_print_host(&sk->lan.addr, sk->lan.port, sk->af);
printf(" ");
- pf_print_host(&s->gwy.addr, s->gwy.port, s->af);
+ pf_print_host(&sk->gwy.addr, sk->gwy.port, sk->af);
printf(" ");
- pf_print_host(&s->ext.addr, s->ext.port, s->af);
+ pf_print_host(&sk->ext.addr, sk->ext.port, sk->af);
printf(" [lo=%u high=%u win=%u modulator=%u", s->src.seqlo,
s->src.seqhi, s->src.max_win, s->src.seqdiff);
if (s->src.wscale && s->dst.wscale)
@@ -1565,7 +1570,6 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af,
#endif /* INET6 */
struct tcphdr *th;
char *opt;
- struct pf_mtag *pf_mtag;
/* maximum segment size tcp option */
tlen = sizeof(struct tcphdr);
@@ -1589,24 +1593,18 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af,
m = m_gethdr(M_DONTWAIT, MT_HEADER);
if (m == NULL)
return;
- if ((pf_mtag = pf_get_mtag(m)) == NULL) {
- m_freem(m);
- return;
- }
if (tag)
- pf_mtag->flags |= PF_TAG_GENERATED;
-
- pf_mtag->tag = rtag;
+ m->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
+ m->m_pkthdr.pf.tag = rtag;
if (r != NULL && r->rtableid >= 0)
- pf_mtag->rtableid = r->rtableid;
+ m->m_pkthdr.pf.rtableid = m->m_pkthdr.pf.rtableid;
#ifdef ALTQ
if (r != NULL && r->qid) {
- pf_mtag->qid = r->qid;
+ m->m_pkthdr.pf.qid = r->qid;
/* add hints for ecn */
- pf_mtag->af = af;
- pf_mtag->hdr = mtod(m, struct ip *);
+ m->m_pkthdr.pf.hdr = mtod(m, struct ip *);
}
#endif /* ALTQ */
m->m_data += max_linkhdr;
@@ -1706,7 +1704,7 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af,
h6->ip6_vfc |= IPV6_VERSION;
h6->ip6_hlim = IPV6_DEFHLIM;
- ip6_output(m, NULL, NULL, 0, NULL, NULL);
+ ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
break;
#endif /* INET6 */
}
@@ -1716,24 +1714,19 @@ void
pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
struct pf_rule *r)
{
- struct pf_mtag *pf_mtag;
struct mbuf *m0;
m0 = m_copy(m, 0, M_COPYALL);
-
- if ((pf_mtag = pf_get_mtag(m0)) == NULL)
- return;
- pf_mtag->flags |= PF_TAG_GENERATED;
+ m0->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
if (r->rtableid >= 0)
- pf_mtag->rtableid = r->rtableid;
+ m0->m_pkthdr.pf.rtableid = r->rtableid;
#ifdef ALTQ
if (r->qid) {
- pf_mtag->qid = r->qid;
+ m0->m_pkthdr.pf.qid = r->qid;
/* add hints for ecn */
- pf_mtag->af = af;
- pf_mtag->hdr = mtod(m0, struct ip *);
+ m0->m_pkthdr.pf.hdr = mtod(m0, struct ip *);
}
#endif /* ALTQ */
@@ -1848,63 +1841,31 @@ pf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g)
return (pf_match(op, a1, a2, g));
}
-struct pf_mtag *
-pf_find_mtag(struct mbuf *m)
-{
- struct m_tag *mtag;
-
- if ((mtag = m_tag_find(m, PACKET_TAG_PF, NULL)) == NULL)
- return (NULL);
-
- return ((struct pf_mtag *)(mtag + 1));
-}
-
-struct pf_mtag *
-pf_get_mtag(struct mbuf *m)
-{
- struct m_tag *mtag;
-
- if ((mtag = m_tag_find(m, PACKET_TAG_PF, NULL)) == NULL) {
- mtag = m_tag_get(PACKET_TAG_PF, sizeof(struct pf_mtag),
- M_NOWAIT);
- if (mtag == NULL)
- return (NULL);
- bzero(mtag + 1, sizeof(struct pf_mtag));
- m_tag_prepend(m, mtag);
- }
-
- return ((struct pf_mtag *)(mtag + 1));
-}
-
int
-pf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_mtag *pf_mtag,
- int *tag)
+pf_match_tag(struct mbuf *m, struct pf_rule *r, int *tag)
{
if (*tag == -1)
- *tag = pf_mtag->tag;
+ *tag = m->m_pkthdr.pf.tag;
return ((!r->match_tag_not && r->match_tag == *tag) ||
(r->match_tag_not && r->match_tag != *tag));
}
int
-pf_tag_packet(struct mbuf *m, struct pf_mtag *pf_mtag, int tag, int rtableid)
+pf_tag_packet(struct mbuf *m, int tag, int rtableid)
{
if (tag <= 0 && rtableid < 0)
return (0);
- if (pf_mtag == NULL)
- if ((pf_mtag = pf_get_mtag(m)) == NULL)
- return (1);
if (tag > 0)
- pf_mtag->tag = tag;
+ m->m_pkthdr.pf.tag = tag;
if (rtableid >= 0)
- pf_mtag->rtableid = rtableid;
+ m->m_pkthdr.pf.rtableid = rtableid;
return (0);
}
-static void
+void
pf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n,
struct pf_rule **r, struct pf_rule **a, int *match)
{
@@ -2279,7 +2240,7 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high,
struct pf_src_node **sn)
{
- struct pf_state_cmp key;
+ struct pf_state_key_cmp key;
struct pf_addr init_addr;
u_int16_t cut;
@@ -2416,7 +2377,7 @@ 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, pd->pf_mtag, &tag))
+ else if (r->match_tag && !pf_match_tag(m, r, &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,
@@ -2437,7 +2398,7 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r,
NULL, NULL);
}
- if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid))
+ if (pf_tag_packet(m, tag, rtableid))
return (NULL);
if (rm != NULL && (rm->action == PF_NONAT ||
rm->action == PF_NORDR || rm->action == PF_NOBINAT))
@@ -2809,7 +2770,7 @@ pf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr)
s->rt_kif = NULL;
if (!r->rt || r->rt == PF_FASTROUTE)
return;
- switch (s->af) {
+ switch (s->state_key->af) {
#ifdef INET
case AF_INET:
pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL,
@@ -2827,703 +2788,103 @@ 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 ifqueue *ifq)
+void
+pf_attach_state(struct pf_state_key *sk, struct pf_state *s, int tail)
{
- struct pf_rule *nr = NULL;
- struct pf_addr *saddr = pd->src, *daddr = pd->dst;
- struct tcphdr *th = pd->hdr.tcp;
- u_int16_t bport, nport = 0;
- sa_family_t af = pd->af;
- struct pf_rule *r, *a = NULL;
- struct pf_ruleset *ruleset = NULL;
- struct pf_src_node *nsn = NULL;
- u_short reason;
- int rewrite = 0;
- int tag = -1, rtableid = -1;
- u_int16_t mss = tcp_mssdflt;
- int asd = 0;
- int match = 0;
+ s->state_key = sk;
+ sk->refcnt++;
- 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);
-
- if (direction == PF_OUT) {
- bport = nport = th->th_sport;
- /* check outgoing packet for BINAT/NAT */
- if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
- saddr, th->th_sport, daddr, th->th_dport,
- &pd->naddr, &nport)) != NULL) {
- PF_ACPY(&pd->baddr, saddr, af);
- pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
- &th->th_sum, &pd->naddr, nport, 0, af);
- rewrite++;
- if (nr->natpass)
- r = NULL;
- pd->nat_rule = nr;
- }
- } else {
- bport = nport = th->th_dport;
- /* check incoming packet for BINAT/RDR */
- if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
- saddr, th->th_sport, daddr, th->th_dport,
- &pd->naddr, &nport)) != NULL) {
- PF_ACPY(&pd->baddr, daddr, af);
- pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
- &th->th_sum, &pd->naddr, nport, 0, af);
- rewrite++;
- if (nr->natpass)
- r = NULL;
- pd->nat_rule = nr;
- }
- }
-
- while (r != NULL) {
- r->evaluations++;
- if (pfi_kif_match(r->kif, kif) == r->ifnot)
- r = r->skip[PF_SKIP_IFP].ptr;
- else if (r->direction && r->direction != direction)
- r = r->skip[PF_SKIP_DIR].ptr;
- else if (r->af && r->af != af)
- r = r->skip[PF_SKIP_AF].ptr;
- else if (r->proto && r->proto != IPPROTO_TCP)
- r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
- r->src.neg, kif))
- r = r->skip[PF_SKIP_SRC_ADDR].ptr;
- else if (r->src.port_op && !pf_match_port(r->src.port_op,
- r->src.port[0], r->src.port[1], th->th_sport))
- r = r->skip[PF_SKIP_SRC_PORT].ptr;
- else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
- r->dst.neg, NULL))
- r = r->skip[PF_SKIP_DST_ADDR].ptr;
- else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
- r->dst.port[0], r->dst.port[1], th->th_dport))
- r = r->skip[PF_SKIP_DST_PORT].ptr;
- else if (r->tos && !(r->tos == pd->tos))
- r = TAILQ_NEXT(r, entries);
- else if (r->rule_flag & PFRULE_FRAGMENT)
- r = TAILQ_NEXT(r, entries);
- else if ((r->flagset & th->th_flags) != r->flags)
- r = TAILQ_NEXT(r, entries);
- else if (r->uid.op && (pd->lookup.done || (pd->lookup.done =
- pf_socket_lookup(direction, pd), 1)) &&
- !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
- pd->lookup.uid))
- r = TAILQ_NEXT(r, entries);
- else if (r->gid.op && (pd->lookup.done || (pd->lookup.done =
- pf_socket_lookup(direction, pd), 1)) &&
- !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
- pd->lookup.gid))
- r = TAILQ_NEXT(r, entries);
- else if (r->prob && r->prob <= arc4random())
- r = TAILQ_NEXT(r, entries);
- else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
- 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))
- r = TAILQ_NEXT(r, entries);
- else {
- if (r->tag)
- tag = r->tag;
- if (r->rtableid >= 0)
- rtableid = r->rtableid;
- if (r->anchor == NULL) {
- match = 1;
- *rm = r;
- *am = a;
- *rsm = ruleset;
- if ((*rm)->quick)
- break;
- r = TAILQ_NEXT(r, entries);
- } else
- pf_step_into_anchor(&asd, &ruleset,
- PF_RULESET_FILTER, &r, &a, &match);
- }
- if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
- PF_RULESET_FILTER, &r, &a, &match))
- break;
- }
- r = *rm;
- a = *am;
- ruleset = *rsm;
-
- REASON_SET(&reason, PFRES_MATCH);
-
- if (r->log || (nr != NULL && nr->natpass && nr->log)) {
- if (rewrite)
- m_copyback(m, off, sizeof(*th), th);
- PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
- a, ruleset, pd);
- }
-
- if ((r->action == PF_DROP) &&
- ((r->rule_flag & PFRULE_RETURNRST) ||
- (r->rule_flag & PFRULE_RETURNICMP) ||
- (r->rule_flag & PFRULE_RETURN))) {
- /* undo NAT changes, if they have taken place */
- if (nr != NULL) {
- if (direction == PF_OUT) {
- pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
- &th->th_sum, &pd->baddr, bport, 0, af);
- rewrite++;
- } else {
- pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
- &th->th_sum, &pd->baddr, bport, 0, af);
- rewrite++;
- }
- }
- if (((r->rule_flag & PFRULE_RETURNRST) ||
- (r->rule_flag & PFRULE_RETURN)) &&
- !(th->th_flags & TH_RST)) {
- u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
+ /* list is sorted, if-bound states before floating */
+ if (tail)
+ TAILQ_INSERT_TAIL(&sk->states, s, next);
+ else
+ TAILQ_INSERT_HEAD(&sk->states, s, next);
+}
- if (th->th_flags & TH_SYN)
- ack++;
- if (th->th_flags & TH_FIN)
- ack++;
- 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, 1, 0, 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);
- else if ((af == AF_INET6) && r->return_icmp6)
- pf_send_icmp(m, r->return_icmp6 >> 8,
- r->return_icmp6 & 255, af, r);
- }
+void
+pf_detach_state(struct pf_state *s, int flags)
+{
+ struct pf_state_key *sk = s->state_key;
- if (r->action == PF_DROP)
- return (PF_DROP);
+ if (sk == NULL)
+ return;
- if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
- REASON_SET(&reason, PFRES_MEMORY);
- return (PF_DROP);
+ s->state_key = NULL;
+ TAILQ_REMOVE(&sk->states, s, next);
+ if (--sk->refcnt == 0) {
+ if (!(flags & PF_DT_SKIP_EXTGWY))
+ RB_REMOVE(pf_state_tree_ext_gwy,
+ &pf_statetbl_ext_gwy, sk);
+ if (!(flags & PF_DT_SKIP_LANEXT))
+ RB_REMOVE(pf_state_tree_lan_ext,
+ &pf_statetbl_lan_ext, sk);
+ pool_put(&pf_state_key_pl, sk);
}
+}
- if (r->keep_state || nr != NULL ||
- (pd->flags & PFDESC_TCP_NORM)) {
- /* create new state */
- u_int16_t len;
- struct pf_state *s = NULL;
- struct pf_src_node *sn = NULL;
-
- len = pd->tot_len - off - (th->th_off << 2);
-
- /* check maximums */
- if (r->max_states && (r->states >= r->max_states)) {
- pf_status.lcounters[LCNT_STATES]++;
- REASON_SET(&reason, PFRES_MAXSTATES);
- goto cleanup;
- }
- /* src node for filter rule */
- if ((r->rule_flag & PFRULE_SRCTRACK ||
- r->rpool.opts & PF_POOL_STICKYADDR) &&
- 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))) {
- 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);
- pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
- pf_status.src_nodes--;
- pool_put(&pf_src_tree_pl, sn);
- }
- if (nsn != sn && nsn != NULL && nsn->states == 0 &&
- nsn->expire == 0) {
- RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
- pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
- pf_status.src_nodes--;
- pool_put(&pf_src_tree_pl, nsn);
- }
- return (PF_DROP);
- }
- bzero(s, sizeof(*s));
- s->rule.ptr = r;
- s->nat_rule.ptr = nr;
- s->anchor.ptr = a;
- STATE_INC_COUNTERS(s);
- s->allow_opts = r->allow_opts;
- s->log = r->log & PF_LOG_ALL;
- if (nr != NULL)
- s->log |= nr->log & PF_LOG_ALL;
- s->proto = IPPROTO_TCP;
- s->direction = direction;
- s->af = af;
- if (direction == PF_OUT) {
- PF_ACPY(&s->gwy.addr, saddr, af);
- s->gwy.port = th->th_sport; /* sport */
- PF_ACPY(&s->ext.addr, daddr, af);
- s->ext.port = th->th_dport;
- if (nr != NULL) {
- PF_ACPY(&s->lan.addr, &pd->baddr, af);
- s->lan.port = bport;
- } else {
- PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
- s->lan.port = s->gwy.port;
- }
- } else {
- PF_ACPY(&s->lan.addr, daddr, af);
- s->lan.port = th->th_dport;
- PF_ACPY(&s->ext.addr, saddr, af);
- s->ext.port = th->th_sport;
- if (nr != NULL) {
- PF_ACPY(&s->gwy.addr, &pd->baddr, af);
- s->gwy.port = bport;
- } else {
- PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
- s->gwy.port = s->lan.port;
- }
- }
-
- s->src.seqlo = ntohl(th->th_seq);
- s->src.seqhi = s->src.seqlo + len + 1;
- if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
- r->keep_state == PF_STATE_MODULATE) {
- /* Generate sequence number modulator */
- while ((s->src.seqdiff =
- tcp_rndiss_next() - s->src.seqlo) == 0)
- ;
- pf_change_a(&th->th_seq, &th->th_sum,
- htonl(s->src.seqlo + s->src.seqdiff), 0);
- rewrite = 1;
- } else
- s->src.seqdiff = 0;
- if (th->th_flags & TH_SYN) {
- s->src.seqhi++;
- s->src.wscale = pf_get_wscale(m, off, th->th_off, af);
- }
- s->src.max_win = MAX(ntohs(th->th_win), 1);
- if (s->src.wscale & PF_WSCALE_MASK) {
- /* Remove scale factor from initial window */
- int win = s->src.max_win;
- win += 1 << (s->src.wscale & PF_WSCALE_MASK);
- s->src.max_win = (win - 1) >>
- (s->src.wscale & PF_WSCALE_MASK);
- }
- if (th->th_flags & TH_FIN)
- s->src.seqhi++;
- s->dst.seqhi = 1;
- s->dst.max_win = 1;
- s->src.state = TCPS_SYN_SENT;
- s->dst.state = TCPS_CLOSED;
- s->creation = time_second;
- s->expire = time_second;
- s->timeout = PFTM_TCP_FIRST_PACKET;
- pf_set_rt_ifp(s, saddr);
- if (sn != NULL) {
- s->src_node = sn;
- s->src_node->states++;
- }
- if (nsn != NULL) {
- PF_ACPY(&nsn->raddr, &pd->naddr, af);
- s->nat_src_node = nsn;
- s->nat_src_node->states++;
- }
- if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m,
- 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,
- &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_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;
- if (nr != NULL) {
- if (direction == PF_OUT) {
- pf_change_ap(saddr, &th->th_sport,
- pd->ip_sum, &th->th_sum, &pd->baddr,
- bport, 0, af);
- } else {
- pf_change_ap(daddr, &th->th_dport,
- pd->ip_sum, &th->th_sum, &pd->baddr,
- bport, 0, af);
- }
- }
- 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);
- mss = pf_calc_mss(daddr, af, mss);
- 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, 1, 0, NULL, NULL);
- REASON_SET(&reason, PFRES_SYNPROXY);
- return (PF_SYNPROXY_DROP);
- }
- }
+struct pf_state_key *
+pf_alloc_state_key(struct pf_state *s)
+{
+ struct pf_state_key *sk;
- /* copy back packet headers if we performed NAT operations */
- if (rewrite)
- m_copyback(m, off, sizeof(*th), th);
+ if ((sk = pool_get(&pf_state_key_pl, PR_NOWAIT)) == NULL)
+ return (NULL);
+ bzero(sk, sizeof(*sk));
+ TAILQ_INIT(&sk->states);
+ pf_attach_state(sk, s, 0);
- return (PF_PASS);
+ return (sk);
}
int
-pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
+pf_test_rule(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 ifqueue *ifq)
{
struct pf_rule *nr = NULL;
struct pf_addr *saddr = pd->src, *daddr = pd->dst;
- struct udphdr *uh = pd->hdr.udp;
u_int16_t bport, nport = 0;
sa_family_t af = pd->af;
struct pf_rule *r, *a = NULL;
struct pf_ruleset *ruleset = NULL;
struct pf_src_node *nsn = NULL;
+ struct tcphdr *th = pd->hdr.tcp;
u_short reason;
- int rewrite = 0;
+ int rewrite = 0, hdrlen = 0;
int tag = -1, rtableid = -1;
int asd = 0;
int match = 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);
-
- if (direction == PF_OUT) {
- bport = nport = uh->uh_sport;
- /* check outgoing packet for BINAT/NAT */
- if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
- saddr, uh->uh_sport, daddr, uh->uh_dport,
- &pd->naddr, &nport)) != NULL) {
- PF_ACPY(&pd->baddr, saddr, af);
- pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
- &uh->uh_sum, &pd->naddr, nport, 1, af);
- rewrite++;
- if (nr->natpass)
- r = NULL;
- pd->nat_rule = nr;
- }
- } else {
- bport = nport = uh->uh_dport;
- /* check incoming packet for BINAT/RDR */
- if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
- saddr, uh->uh_sport, daddr, uh->uh_dport, &pd->naddr,
- &nport)) != NULL) {
- PF_ACPY(&pd->baddr, daddr, af);
- pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
- &uh->uh_sum, &pd->naddr, nport, 1, af);
- rewrite++;
- if (nr->natpass)
- r = NULL;
- pd->nat_rule = nr;
- }
- }
-
- while (r != NULL) {
- r->evaluations++;
- if (pfi_kif_match(r->kif, kif) == r->ifnot)
- r = r->skip[PF_SKIP_IFP].ptr;
- else if (r->direction && r->direction != direction)
- r = r->skip[PF_SKIP_DIR].ptr;
- else if (r->af && r->af != af)
- r = r->skip[PF_SKIP_AF].ptr;
- else if (r->proto && r->proto != IPPROTO_UDP)
- r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
- r->src.neg, kif))
- r = r->skip[PF_SKIP_SRC_ADDR].ptr;
- else if (r->src.port_op && !pf_match_port(r->src.port_op,
- r->src.port[0], r->src.port[1], uh->uh_sport))
- r = r->skip[PF_SKIP_SRC_PORT].ptr;
- else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
- r->dst.neg, NULL))
- r = r->skip[PF_SKIP_DST_ADDR].ptr;
- else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
- r->dst.port[0], r->dst.port[1], uh->uh_dport))
- r = r->skip[PF_SKIP_DST_PORT].ptr;
- else if (r->tos && !(r->tos == pd->tos))
- r = TAILQ_NEXT(r, entries);
- else if (r->rule_flag & PFRULE_FRAGMENT)
- r = TAILQ_NEXT(r, entries);
- else if (r->uid.op && (pd->lookup.done || (pd->lookup.done =
- pf_socket_lookup(direction, pd), 1)) &&
- !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
- pd->lookup.uid))
- r = TAILQ_NEXT(r, entries);
- else if (r->gid.op && (pd->lookup.done || (pd->lookup.done =
- pf_socket_lookup(direction, pd), 1)) &&
- !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
- pd->lookup.gid))
- r = TAILQ_NEXT(r, entries);
- else if (r->prob && r->prob <= arc4random())
- r = TAILQ_NEXT(r, entries);
- else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
- r = TAILQ_NEXT(r, entries);
- else if (r->os_fingerprint != PF_OSFP_ANY)
- r = TAILQ_NEXT(r, entries);
- else {
- if (r->tag)
- tag = r->tag;
- if (r->rtableid >= 0)
- rtableid = r->rtableid;
- if (r->anchor == NULL) {
- match = 1;
- *rm = r;
- *am = a;
- *rsm = ruleset;
- if ((*rm)->quick)
- break;
- r = TAILQ_NEXT(r, entries);
- } else
- pf_step_into_anchor(&asd, &ruleset,
- PF_RULESET_FILTER, &r, &a, &match);
- }
- if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
- PF_RULESET_FILTER, &r, &a, &match))
- break;
- }
- r = *rm;
- a = *am;
- ruleset = *rsm;
-
- REASON_SET(&reason, PFRES_MATCH);
-
- if (r->log || (nr != NULL && nr->natpass && nr->log)) {
- if (rewrite)
- m_copyback(m, off, sizeof(*uh), uh);
- PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
- a, ruleset, pd);
- }
-
- if ((r->action == PF_DROP) &&
- ((r->rule_flag & PFRULE_RETURNICMP) ||
- (r->rule_flag & PFRULE_RETURN))) {
- /* undo NAT changes, if they have taken place */
- if (nr != NULL) {
- if (direction == PF_OUT) {
- pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
- &uh->uh_sum, &pd->baddr, bport, 1, af);
- rewrite++;
- } else {
- pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
- &uh->uh_sum, &pd->baddr, bport, 1, af);
- rewrite++;
- }
- }
- if ((af == AF_INET) && r->return_icmp)
- pf_send_icmp(m, r->return_icmp >> 8,
- r->return_icmp & 255, af, r);
- else if ((af == AF_INET6) && r->return_icmp6)
- pf_send_icmp(m, r->return_icmp6 >> 8,
- r->return_icmp6 & 255, af, r);
- }
-
- if (r->action == PF_DROP)
- return (PF_DROP);
-
- if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
- REASON_SET(&reason, PFRES_MEMORY);
- return (PF_DROP);
- }
-
- if (r->keep_state || nr != NULL) {
- /* create new state */
- struct pf_state *s = NULL;
- struct pf_src_node *sn = NULL;
-
- /* check maximums */
- if (r->max_states && (r->states >= r->max_states)) {
- pf_status.lcounters[LCNT_STATES]++;
- REASON_SET(&reason, PFRES_MAXSTATES);
- goto cleanup;
- }
- /* src node for filter rule */
- if ((r->rule_flag & PFRULE_SRCTRACK ||
- r->rpool.opts & PF_POOL_STICKYADDR) &&
- 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))) {
- 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);
- pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
- pf_status.src_nodes--;
- pool_put(&pf_src_tree_pl, sn);
- }
- if (nsn != sn && nsn != NULL && nsn->states == 0 &&
- nsn->expire == 0) {
- RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
- pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
- pf_status.src_nodes--;
- pool_put(&pf_src_tree_pl, nsn);
- }
- return (PF_DROP);
- }
- bzero(s, sizeof(*s));
- s->rule.ptr = r;
- s->nat_rule.ptr = nr;
- s->anchor.ptr = a;
- STATE_INC_COUNTERS(s);
- s->allow_opts = r->allow_opts;
- s->log = r->log & PF_LOG_ALL;
- if (nr != NULL)
- s->log |= nr->log & PF_LOG_ALL;
- s->proto = IPPROTO_UDP;
- s->direction = direction;
- s->af = af;
- if (direction == PF_OUT) {
- PF_ACPY(&s->gwy.addr, saddr, af);
- s->gwy.port = uh->uh_sport;
- PF_ACPY(&s->ext.addr, daddr, af);
- s->ext.port = uh->uh_dport;
- if (nr != NULL) {
- PF_ACPY(&s->lan.addr, &pd->baddr, af);
- s->lan.port = bport;
- } else {
- PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
- s->lan.port = s->gwy.port;
- }
- } else {
- PF_ACPY(&s->lan.addr, daddr, af);
- s->lan.port = uh->uh_dport;
- PF_ACPY(&s->ext.addr, saddr, af);
- s->ext.port = uh->uh_sport;
- if (nr != NULL) {
- PF_ACPY(&s->gwy.addr, &pd->baddr, af);
- s->gwy.port = bport;
- } else {
- PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
- s->gwy.port = s->lan.port;
- }
- }
- s->src.state = PFUDPS_SINGLE;
- s->dst.state = PFUDPS_NO_TRAFFIC;
- s->creation = time_second;
- s->expire = time_second;
- s->timeout = PFTM_UDP_FIRST_PACKET;
- pf_set_rt_ifp(s, saddr);
- if (sn != NULL) {
- s->src_node = sn;
- s->src_node->states++;
- }
- if (nsn != NULL) {
- PF_ACPY(&nsn->raddr, &pd->naddr, af);
- s->nat_src_node = nsn;
- s->nat_src_node->states++;
- }
- if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
- 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 */
- if (rewrite)
- m_copyback(m, off, sizeof(*uh), uh);
-
- return (PF_PASS);
-}
-
-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 ifqueue *ifq)
-{
- struct pf_rule *nr = NULL;
- struct pf_addr *saddr = pd->src, *daddr = pd->dst;
- struct pf_rule *r, *a = NULL;
- struct pf_ruleset *ruleset = NULL;
- struct pf_src_node *nsn = NULL;
- u_short reason;
- u_int16_t icmpid, bport, nport = 0;
- sa_family_t af = pd->af;
- u_int8_t icmptype, icmpcode;
int state_icmp = 0;
- int tag = -1, rtableid = -1;
-#ifdef INET6
- int rewrite = 0;
-#endif /* INET6 */
- int asd = 0;
- int match = 0;
+ u_int16_t mss = tcp_mssdflt;
+ u_int16_t sport, dport;
+ u_int8_t icmptype = 0, icmpcode = 0;
- if (pf_check_congestion(ifq)) {
+ if (direction == PF_IN && pf_check_congestion(ifq)) {
REASON_SET(&reason, PFRES_CONGEST);
return (PF_DROP);
}
+ sport = dport = hdrlen = 0;
+
switch (pd->proto) {
+ case IPPROTO_TCP:
+ sport = th->th_sport;
+ dport = th->th_dport;
+ hdrlen = sizeof(*th);
+ break;
+ case IPPROTO_UDP:
+ sport = pd->hdr.udp->uh_sport;
+ dport = pd->hdr.udp->uh_dport;
+ hdrlen = sizeof(*pd->hdr.udp);
+ break;
#ifdef INET
case IPPROTO_ICMP:
+ if (pd->af != AF_INET)
+ break;
+ sport = dport = pd->hdr.icmp->icmp_id;
icmptype = pd->hdr.icmp->icmp_type;
icmpcode = pd->hdr.icmp->icmp_code;
- icmpid = pd->hdr.icmp->icmp_id;
if (icmptype == ICMP_UNREACH ||
icmptype == ICMP_SOURCEQUENCH ||
@@ -3535,9 +2896,12 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
#endif /* INET */
#ifdef INET6
case IPPROTO_ICMPV6:
+ if (pd->af != AF_INET6)
+ break;
+ sport = dport = pd->hdr.icmp6->icmp6_id;
+ hdrlen = sizeof(*pd->hdr.icmp6);
icmptype = pd->hdr.icmp6->icmp6_type;
icmpcode = pd->hdr.icmp6->icmp6_code;
- icmpid = pd->hdr.icmp6->icmp6_id;
if (icmptype == ICMP6_DST_UNREACH ||
icmptype == ICMP6_PACKET_TOO_BIG ||
@@ -3551,57 +2915,113 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
if (direction == PF_OUT) {
- bport = nport = icmpid;
+ bport = nport = sport;
/* check outgoing packet for BINAT/NAT */
if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
- saddr, icmpid, daddr, icmpid, &pd->naddr, &nport)) !=
- NULL) {
+ saddr, sport, daddr, dport, &pd->naddr, &nport)) != NULL) {
PF_ACPY(&pd->baddr, saddr, af);
- switch (af) {
+ switch (pd->proto) {
+ case IPPROTO_TCP:
+ pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
+ &th->th_sum, &pd->naddr, nport, 0, af);
+ sport = th->th_sport;
+ rewrite++;
+ break;
+ case IPPROTO_UDP:
+ pf_change_ap(saddr, &pd->hdr.udp->uh_sport,
+ pd->ip_sum, &pd->hdr.udp->uh_sum,
+ &pd->naddr, nport, 1, af);
+ sport = pd->hdr.udp->uh_sport;
+ rewrite++;
+ break;
#ifdef INET
- case AF_INET:
+ case IPPROTO_ICMP:
pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
pd->naddr.v4.s_addr, 0);
pd->hdr.icmp->icmp_cksum = pf_cksum_fixup(
- pd->hdr.icmp->icmp_cksum, icmpid, nport, 0);
+ pd->hdr.icmp->icmp_cksum, sport, nport, 0);
pd->hdr.icmp->icmp_id = nport;
m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp);
break;
#endif /* INET */
#ifdef INET6
- case AF_INET6:
+ case IPPROTO_ICMPV6:
pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum,
&pd->naddr, 0);
rewrite++;
break;
-#endif /* INET6 */
+#endif /* INET */
+ default:
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ pf_change_a(&saddr->v4.s_addr,
+ pd->ip_sum, pd->naddr.v4.s_addr, 0);
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ PF_ACPY(saddr, &pd->naddr, af);
+ break;
+#endif /* INET */
+ }
+ break;
}
+
if (nr->natpass)
r = NULL;
pd->nat_rule = nr;
}
} else {
- bport = nport = icmpid;
+ bport = nport = dport;
/* check incoming packet for BINAT/RDR */
if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
- saddr, icmpid, daddr, icmpid, &pd->naddr, &nport)) !=
- NULL) {
+ saddr, sport, daddr, dport, &pd->naddr, &nport)) != NULL) {
PF_ACPY(&pd->baddr, daddr, af);
- switch (af) {
+ switch (pd->proto) {
+ case IPPROTO_TCP:
+ pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
+ &th->th_sum, &pd->naddr, nport, 0, af);
+ dport = th->th_dport;
+ rewrite++;
+ break;
+ case IPPROTO_UDP:
+ pf_change_ap(daddr, &pd->hdr.udp->uh_dport,
+ pd->ip_sum, &pd->hdr.udp->uh_sum,
+ &pd->naddr, nport, 1, af);
+ dport = pd->hdr.udp->uh_dport;
+ rewrite++;
+ break;
#ifdef INET
- case AF_INET:
- pf_change_a(&daddr->v4.s_addr,
- pd->ip_sum, pd->naddr.v4.s_addr, 0);
+ case IPPROTO_ICMP:
+ pf_change_a(&daddr->v4.s_addr, pd->ip_sum,
+ pd->naddr.v4.s_addr, 0);
break;
#endif /* INET */
#ifdef INET6
- case AF_INET6:
+ case IPPROTO_ICMPV6:
pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum,
&pd->naddr, 0);
rewrite++;
break;
#endif /* INET6 */
+ default:
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ pf_change_a(&daddr->v4.s_addr,
+ pd->ip_sum, pd->naddr.v4.s_addr, 0);
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ PF_ACPY(daddr, &pd->naddr, af);
+ break;
+#endif /* INET */
+ }
+ break;
}
+
if (nr->natpass)
r = NULL;
pd->nat_rule = nr;
@@ -3621,22 +3041,50 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
r->src.neg, kif))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
+ /* tcp/udp only. port_op always 0 in other cases */
+ else if (r->src.port_op && !pf_match_port(r->src.port_op,
+ r->src.port[0], r->src.port[1], sport))
+ r = r->skip[PF_SKIP_SRC_PORT].ptr;
else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
r->dst.neg, NULL))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
+ /* tcp/udp only. port_op always 0 in other cases */
+ else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
+ r->dst.port[0], r->dst.port[1], dport))
+ r = r->skip[PF_SKIP_DST_PORT].ptr;
+ /* icmp only. type always 0 in other cases */
else if (r->type && r->type != icmptype + 1)
r = TAILQ_NEXT(r, entries);
+ /* 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))
r = TAILQ_NEXT(r, entries);
else if (r->rule_flag & PFRULE_FRAGMENT)
r = TAILQ_NEXT(r, entries);
+ else if (pd->proto == IPPROTO_TCP &&
+ (r->flagset & th->th_flags) != r->flags)
+ r = TAILQ_NEXT(r, entries);
+ /* tcp/udp only. uid.op always 0 in other cases */
+ else if (r->uid.op && (pd->lookup.done || (pd->lookup.done =
+ pf_socket_lookup(direction, pd), 1)) &&
+ !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
+ pd->lookup.uid))
+ r = TAILQ_NEXT(r, entries);
+ /* tcp/udp only. gid.op always 0 in other cases */
+ else if (r->gid.op && (pd->lookup.done || (pd->lookup.done =
+ pf_socket_lookup(direction, pd), 1)) &&
+ !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
+ pd->lookup.gid))
+ r = TAILQ_NEXT(r, entries);
else if (r->prob && r->prob <= arc4random())
r = TAILQ_NEXT(r, entries);
- else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
+ else if (r->match_tag && !pf_match_tag(m, r, &tag))
r = TAILQ_NEXT(r, entries);
- else if (r->os_fingerprint != PF_OSFP_ANY)
+ else if (r->os_fingerprint != PF_OSFP_ANY &&
+ (pd->proto != IPPROTO_TCP || !pf_osfp_match(
+ pf_osfp_fingerprint(pd, m, off, th),
+ r->os_fingerprint)))
r = TAILQ_NEXT(r, entries);
else {
if (r->tag)
@@ -3665,27 +3113,133 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
REASON_SET(&reason, PFRES_MATCH);
- if (r->log || (nr != NULL && nr->natpass && nr->log)) {
-#ifdef INET6
+ if (r->log || (nr != NULL && nr->log)) {
if (rewrite)
- m_copyback(m, off, sizeof(struct icmp6_hdr),
- pd->hdr.icmp6);
-#endif /* INET6 */
+ m_copyback(m, off, hdrlen, pd->hdr.any);
PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
a, ruleset, pd);
}
- if (r->action != PF_PASS)
+ if ((r->action == PF_DROP) &&
+ ((r->rule_flag & PFRULE_RETURNRST) ||
+ (r->rule_flag & PFRULE_RETURNICMP) ||
+ (r->rule_flag & PFRULE_RETURN))) {
+ /* undo NAT changes, if they have taken place */
+ if (nr != NULL) {
+ if (direction == PF_OUT) {
+ switch (pd->proto) {
+ case IPPROTO_TCP:
+ pf_change_ap(saddr, &th->th_sport,
+ pd->ip_sum, &th->th_sum,
+ &pd->baddr, bport, 0, af);
+ sport = th->th_sport;
+ rewrite++;
+ break;
+ case IPPROTO_UDP:
+ pf_change_ap(saddr,
+ &pd->hdr.udp->uh_sport, pd->ip_sum,
+ &pd->hdr.udp->uh_sum, &pd->baddr,
+ bport, 1, af);
+ sport = pd->hdr.udp->uh_sport;
+ rewrite++;
+ break;
+ case IPPROTO_ICMP:
+#ifdef INET6
+ case IPPROTO_ICMPV6:
+#endif
+ /* nothing! */
+ break;
+ default:
+ switch (af) {
+ case AF_INET:
+ pf_change_a(&saddr->v4.s_addr,
+ pd->ip_sum,
+ pd->baddr.v4.s_addr, 0);
+ break;
+ case AF_INET6:
+ PF_ACPY(saddr, &pd->baddr, af);
+ break;
+ }
+ }
+ } else {
+ switch (pd->proto) {
+ case IPPROTO_TCP:
+ pf_change_ap(daddr, &th->th_dport,
+ pd->ip_sum, &th->th_sum,
+ &pd->baddr, bport, 0, af);
+ dport = th->th_dport;
+ rewrite++;
+ break;
+ case IPPROTO_UDP:
+ pf_change_ap(daddr,
+ &pd->hdr.udp->uh_dport, pd->ip_sum,
+ &pd->hdr.udp->uh_sum, &pd->baddr,
+ bport, 1, af);
+ dport = pd->hdr.udp->uh_dport;
+ rewrite++;
+ break;
+ case IPPROTO_ICMP:
+#ifdef INET6
+ case IPPROTO_ICMPV6:
+#endif
+ /* nothing! */
+ break;
+ default:
+ switch (af) {
+ case AF_INET:
+ pf_change_a(&daddr->v4.s_addr,
+ pd->ip_sum,
+ pd->baddr.v4.s_addr, 0);
+ break;
+ case AF_INET6:
+ PF_ACPY(daddr, &pd->baddr, af);
+ break;
+ }
+ }
+ }
+ }
+ if (pd->proto == IPPROTO_TCP &&
+ ((r->rule_flag & PFRULE_RETURNRST) ||
+ (r->rule_flag & PFRULE_RETURN)) &&
+ !(th->th_flags & TH_RST)) {
+ u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
+ struct ip *h = mtod(m, struct ip *);
+
+ if (pf_check_proto_cksum(m, off,
+ ntohs(h->ip_len) - off, IPPROTO_TCP, AF_INET))
+ REASON_SET(&reason, PFRES_PROTCKSUM);
+ else {
+ if (th->th_flags & TH_SYN)
+ ack++;
+ if (th->th_flags & TH_FIN)
+ ack++;
+ 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, 1, 0, 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);
+ else if ((af == AF_INET6) && r->return_icmp6)
+ pf_send_icmp(m, r->return_icmp6 >> 8,
+ r->return_icmp6 & 255, af, r);
+ }
+
+ if (r->action == PF_DROP)
return (PF_DROP);
- if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
+ if (pf_tag_packet(m, tag, rtableid)) {
REASON_SET(&reason, PFRES_MEMORY);
return (PF_DROP);
}
- if (!state_icmp && (r->keep_state || nr != NULL)) {
+ if (!state_icmp && (r->keep_state || nr != NULL ||
+ (pd->flags & PFDESC_TCP_NORM))) {
/* create new state */
+ u_int16_t len;
struct pf_state *s = NULL;
+ struct pf_state_key *sk = NULL;
struct pf_src_node *sn = NULL;
/* check maximums */
@@ -3726,6 +3280,9 @@ cleanup:
pf_status.src_nodes--;
pool_put(&pf_src_tree_pl, nsn);
}
+ if (sk != NULL) {
+ pool_put(&pf_state_key_pl, sk);
+ }
return (PF_DROP);
}
bzero(s, sizeof(*s));
@@ -3737,38 +3294,63 @@ cleanup:
s->log = r->log & PF_LOG_ALL;
if (nr != NULL)
s->log |= nr->log & PF_LOG_ALL;
- s->proto = pd->proto;
- s->direction = direction;
- s->af = af;
- if (direction == PF_OUT) {
- PF_ACPY(&s->gwy.addr, saddr, af);
- s->gwy.port = nport;
- PF_ACPY(&s->ext.addr, daddr, af);
- s->ext.port = 0;
- if (nr != NULL) {
- PF_ACPY(&s->lan.addr, &pd->baddr, af);
- s->lan.port = bport;
- } else {
- PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
- s->lan.port = s->gwy.port;
+ switch (pd->proto) {
+ case IPPROTO_TCP:
+ len = pd->tot_len - off - (th->th_off << 2);
+ s->src.seqlo = ntohl(th->th_seq);
+ s->src.seqhi = s->src.seqlo + len + 1;
+ if ((th->th_flags & (TH_SYN|TH_ACK)) ==
+ TH_SYN && r->keep_state == PF_STATE_MODULATE) {
+ /* Generate sequence number modulator */
+ while ((s->src.seqdiff =
+ tcp_rndiss_next() - s->src.seqlo) == 0)
+ ;
+ pf_change_a(&th->th_seq, &th->th_sum,
+ htonl(s->src.seqlo + s->src.seqdiff), 0);
+ rewrite = 1;
+ } else
+ s->src.seqdiff = 0;
+ if (th->th_flags & TH_SYN) {
+ s->src.seqhi++;
+ s->src.wscale = pf_get_wscale(m, off,
+ th->th_off, af);
}
- } else {
- PF_ACPY(&s->lan.addr, daddr, af);
- s->lan.port = nport;
- PF_ACPY(&s->ext.addr, saddr, af);
- s->ext.port = 0;
- if (nr != NULL) {
- PF_ACPY(&s->gwy.addr, &pd->baddr, af);
- s->gwy.port = bport;
- } else {
- PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
- s->gwy.port = s->lan.port;
+ s->src.max_win = MAX(ntohs(th->th_win), 1);
+ if (s->src.wscale & PF_WSCALE_MASK) {
+ /* Remove scale factor from initial window */
+ int win = s->src.max_win;
+ win += 1 << (s->src.wscale & PF_WSCALE_MASK);
+ s->src.max_win = (win - 1) >>
+ (s->src.wscale & PF_WSCALE_MASK);
}
+ if (th->th_flags & TH_FIN)
+ s->src.seqhi++;
+ s->dst.seqhi = 1;
+ s->dst.max_win = 1;
+ s->src.state = TCPS_SYN_SENT;
+ s->dst.state = TCPS_CLOSED;
+ s->timeout = PFTM_TCP_FIRST_PACKET;
+ break;
+ case IPPROTO_UDP:
+ s->src.state = PFUDPS_SINGLE;
+ s->dst.state = PFUDPS_NO_TRAFFIC;
+ s->timeout = PFTM_UDP_FIRST_PACKET;
+ break;
+ case IPPROTO_ICMP:
+#ifdef INET6
+ case IPPROTO_ICMPV6:
+#endif
+ s->timeout = PFTM_ICMP_FIRST_PACKET;
+ break;
+ default:
+ s->src.state = PFOTHERS_SINGLE;
+ s->dst.state = PFOTHERS_NO_TRAFFIC;
+ s->timeout = PFTM_OTHER_FIRST_PACKET;
}
+
s->creation = time_second;
s->expire = time_second;
- s->timeout = PFTM_ICMP_FIRST_PACKET;
- pf_set_rt_ifp(s, saddr);
+
if (sn != NULL) {
s->src_node = sn;
s->src_node->states++;
@@ -3778,286 +3360,90 @@ cleanup:
s->nat_src_node = nsn;
s->nat_src_node->states++;
}
- if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
- 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
- /* copy back packet headers if we performed IPv6 NAT operations */
- if (rewrite)
- m_copyback(m, off, sizeof(struct icmp6_hdr),
- pd->hdr.icmp6);
-#endif /* INET6 */
-
- return (PF_PASS);
-}
-
-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 ifqueue *ifq)
-{
- struct pf_rule *nr = NULL;
- struct pf_rule *r, *a = NULL;
- struct pf_ruleset *ruleset = NULL;
- struct pf_src_node *nsn = NULL;
- struct pf_addr *saddr = pd->src, *daddr = pd->dst;
- sa_family_t af = pd->af;
- u_short reason;
- int tag = -1, rtableid = -1;
- int asd = 0;
- int match = 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);
-
- 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) {
- PF_ACPY(&pd->baddr, saddr, af);
- switch (af) {
-#ifdef INET
- case AF_INET:
- pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
- pd->naddr.v4.s_addr, 0);
- break;
-#endif /* INET */
-#ifdef INET6
- case AF_INET6:
- PF_ACPY(saddr, &pd->naddr, af);
- break;
-#endif /* INET6 */
+ if (pd->proto == IPPROTO_TCP) {
+ if ((pd->flags & PFDESC_TCP_NORM) &&
+ pf_normalize_tcp_init(m, 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 (nr->natpass)
- r = NULL;
- pd->nat_rule = nr;
- }
- } 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) {
- PF_ACPY(&pd->baddr, daddr, af);
- switch (af) {
-#ifdef INET
- case AF_INET:
- pf_change_a(&daddr->v4.s_addr,
- pd->ip_sum, pd->naddr.v4.s_addr, 0);
- break;
-#endif /* INET */
-#ifdef INET6
- case AF_INET6:
- PF_ACPY(daddr, &pd->naddr, af);
- break;
-#endif /* INET6 */
+ if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub &&
+ 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 (nr->natpass)
- r = NULL;
- pd->nat_rule = nr;
}
- }
- while (r != NULL) {
- r->evaluations++;
- if (pfi_kif_match(r->kif, kif) == r->ifnot)
- r = r->skip[PF_SKIP_IFP].ptr;
- else if (r->direction && r->direction != direction)
- r = r->skip[PF_SKIP_DIR].ptr;
- else if (r->af && r->af != af)
- r = r->skip[PF_SKIP_AF].ptr;
- else if (r->proto && r->proto != pd->proto)
- r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&r->src.addr, pd->src, af,
- r->src.neg, kif))
- r = r->skip[PF_SKIP_SRC_ADDR].ptr;
- else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af,
- r->dst.neg, NULL))
- r = r->skip[PF_SKIP_DST_ADDR].ptr;
- else if (r->tos && !(r->tos == pd->tos))
- r = TAILQ_NEXT(r, entries);
- else if (r->rule_flag & PFRULE_FRAGMENT)
- r = TAILQ_NEXT(r, entries);
- else if (r->prob && r->prob <= arc4random())
- r = TAILQ_NEXT(r, entries);
- else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
- r = TAILQ_NEXT(r, entries);
- else if (r->os_fingerprint != PF_OSFP_ANY)
- r = TAILQ_NEXT(r, entries);
- else {
- if (r->tag)
- tag = r->tag;
- if (r->rtableid >= 0)
- rtableid = r->rtableid;
- if (r->anchor == NULL) {
- match = 1;
- *rm = r;
- *am = a;
- *rsm = ruleset;
- if ((*rm)->quick)
- break;
- r = TAILQ_NEXT(r, entries);
- } else
- pf_step_into_anchor(&asd, &ruleset,
- PF_RULESET_FILTER, &r, &a, &match);
+ if ((sk = pf_alloc_state_key(s)) == NULL) {
+ REASON_SET(&reason, PFRES_MEMORY);
+ goto cleanup;
}
- if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
- PF_RULESET_FILTER, &r, &a, &match))
- break;
- }
- r = *rm;
- a = *am;
- ruleset = *rsm;
-
- REASON_SET(&reason, PFRES_MATCH);
-
- if (r->log || (nr != NULL && nr->natpass && nr->log))
- PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
- a, ruleset, pd);
- if ((r->action == PF_DROP) &&
- ((r->rule_flag & PFRULE_RETURNICMP) ||
- (r->rule_flag & PFRULE_RETURN))) {
- struct pf_addr *a = NULL;
-
- if (nr != NULL) {
- if (direction == PF_OUT)
- a = saddr;
- else
- a = daddr;
- }
- if (a != NULL) {
- switch (af) {
-#ifdef INET
- case AF_INET:
- pf_change_a(&a->v4.s_addr, pd->ip_sum,
- pd->baddr.v4.s_addr, 0);
+ sk->proto = pd->proto;
+ sk->direction = direction;
+ sk->af = af;
+ if (direction == PF_OUT) {
+ PF_ACPY(&sk->gwy.addr, saddr, af);
+ PF_ACPY(&sk->ext.addr, daddr, af);
+ switch (pd->proto) {
+ case IPPROTO_ICMP:
+#ifdef INET6
+ case IPPROTO_ICMPV6:
+#endif
+ sk->gwy.port = nport;
+ sk->ext.port = 0;
break;
-#endif /* INET */
+ default:
+ sk->gwy.port = sport;
+ sk->ext.port = dport;
+ }
+ if (nr != NULL) {
+ PF_ACPY(&sk->lan.addr, &pd->baddr, af);
+ sk->lan.port = bport;
+ } else {
+ PF_ACPY(&sk->lan.addr, &sk->gwy.addr, af);
+ sk->lan.port = sk->gwy.port;
+ }
+ } else {
+ PF_ACPY(&sk->lan.addr, daddr, af);
+ PF_ACPY(&sk->ext.addr, saddr, af);
+ switch (pd->proto) {
+ case IPPROTO_ICMP:
#ifdef INET6
- case AF_INET6:
- PF_ACPY(a, &pd->baddr, af);
+ case IPPROTO_ICMPV6:
+#endif
+ sk->lan.port = nport;
+ sk->ext.port = 0;
break;
-#endif /* INET6 */
+ default:
+ sk->lan.port = dport;
+ sk->ext.port = sport;
+ }
+ if (nr != NULL) {
+ PF_ACPY(&sk->gwy.addr, &pd->baddr, af);
+ sk->gwy.port = bport;
+ } else {
+ PF_ACPY(&sk->gwy.addr, &sk->lan.addr, af);
+ sk->gwy.port = sk->lan.port;
}
}
- if ((af == AF_INET) && r->return_icmp)
- pf_send_icmp(m, r->return_icmp >> 8,
- r->return_icmp & 255, af, r);
- else if ((af == AF_INET6) && r->return_icmp6)
- pf_send_icmp(m, r->return_icmp6 >> 8,
- r->return_icmp6 & 255, af, r);
- }
- if (r->action != PF_PASS)
- return (PF_DROP);
+ pf_set_rt_ifp(s, saddr); /* needs s->state_key set */
- if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
- REASON_SET(&reason, PFRES_MEMORY);
- return (PF_DROP);
- }
-
- if (r->keep_state || nr != NULL) {
- /* create new state */
- struct pf_state *s = NULL;
- struct pf_src_node *sn = NULL;
-
- /* check maximums */
- if (r->max_states && (r->states >= r->max_states)) {
- pf_status.lcounters[LCNT_STATES]++;
- REASON_SET(&reason, PFRES_MAXSTATES);
- goto cleanup;
- }
- /* src node for filter rule */
- if ((r->rule_flag & PFRULE_SRCTRACK ||
- r->rpool.opts & PF_POOL_STICKYADDR) &&
- 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))) {
- 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);
- pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
- pf_status.src_nodes--;
- pool_put(&pf_src_tree_pl, sn);
- }
- if (nsn != sn && nsn != NULL && nsn->states == 0 &&
- nsn->expire == 0) {
- RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
- pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
- pf_status.src_nodes--;
- pool_put(&pf_src_tree_pl, nsn);
- }
- return (PF_DROP);
- }
- bzero(s, sizeof(*s));
- s->rule.ptr = r;
- s->nat_rule.ptr = nr;
- s->anchor.ptr = a;
- STATE_INC_COUNTERS(s);
- s->allow_opts = r->allow_opts;
- s->log = r->log & PF_LOG_ALL;
- if (nr != NULL)
- s->log |= nr->log & PF_LOG_ALL;
- s->proto = pd->proto;
- s->direction = direction;
- s->af = af;
- if (direction == PF_OUT) {
- PF_ACPY(&s->gwy.addr, saddr, af);
- PF_ACPY(&s->ext.addr, daddr, af);
- if (nr != NULL)
- PF_ACPY(&s->lan.addr, &pd->baddr, af);
- else
- PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
- } else {
- PF_ACPY(&s->lan.addr, daddr, af);
- PF_ACPY(&s->ext.addr, saddr, af);
- if (nr != NULL)
- PF_ACPY(&s->gwy.addr, &pd->baddr, af);
- else
- PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
- }
- s->src.state = PFOTHERS_SINGLE;
- s->dst.state = PFOTHERS_NO_TRAFFIC;
- s->creation = time_second;
- s->expire = time_second;
- s->timeout = PFTM_OTHER_FIRST_PACKET;
- pf_set_rt_ifp(s, saddr);
- if (sn != NULL) {
- s->src_node = sn;
- s->src_node->states++;
- }
- if (nsn != NULL) {
- PF_ACPY(&nsn->raddr, &pd->naddr, af);
- s->nat_src_node = nsn;
- s->nat_src_node->states++;
- }
if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
+ if (pd->proto == IPPROTO_TCP)
+ pf_normalize_tcp_cleanup(s);
REASON_SET(&reason, PFRES_STATEINS);
pf_src_tree_remove_state(s);
STATE_DEC_COUNTERS(s);
@@ -4069,8 +3455,41 @@ cleanup:
pf_tag_ref(tag);
s->tag = tag;
}
+ if (pd->proto == IPPROTO_TCP &&
+ (th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
+ r->keep_state == PF_STATE_SYNPROXY) {
+ s->src.state = PF_TCPS_PROXY_SRC;
+ if (nr != NULL) {
+ if (direction == PF_OUT) {
+ pf_change_ap(saddr, &th->th_sport,
+ pd->ip_sum, &th->th_sum, &pd->baddr,
+ bport, 0, af);
+ sport = th->th_sport;
+ } else {
+ pf_change_ap(daddr, &th->th_dport,
+ pd->ip_sum, &th->th_sum, &pd->baddr,
+ bport, 0, af);
+ sport = th->th_dport;
+ }
+ }
+ 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);
+ mss = pf_calc_mss(daddr, af, mss);
+ 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, 1, 0, NULL, NULL);
+ REASON_SET(&reason, PFRES_SYNPROXY);
+ return (PF_SYNPROXY_DROP);
+ }
}
+ /* copy back packet headers if we performed NAT operations */
+ if (rewrite)
+ m_copyback(m, off, hdrlen, pd->hdr.any);
+
return (PF_PASS);
}
@@ -4112,7 +3531,7 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
r = TAILQ_NEXT(r, entries);
else if (r->prob && r->prob <= arc4random())
r = TAILQ_NEXT(r, entries);
- else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
+ else if (r->match_tag && !pf_match_tag(m, r, &tag))
r = TAILQ_NEXT(r, entries);
else {
if (r->anchor == NULL) {
@@ -4144,7 +3563,7 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
if (r->action != PF_PASS)
return (PF_DROP);
- if (pf_tag_packet(m, pd->pf_mtag, tag, -1)) {
+ if (pf_tag_packet(m, tag, -1)) {
REASON_SET(&reason, PFRES_MEMORY);
return (PF_DROP);
}
@@ -4157,7 +3576,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
u_short *reason)
{
- struct pf_state_cmp key;
+ struct pf_state_key_cmp key;
struct tcphdr *th = pd->hdr.tcp;
u_int16_t win = ntohs(th->th_win);
u_int32_t ack, end, seq, orig_seq;
@@ -4182,7 +3601,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
STATE_LOOKUP();
- if (direction == (*state)->direction) {
+ if (direction == (*state)->state_key->direction) {
src = &(*state)->src;
dst = &(*state)->dst;
} else {
@@ -4191,7 +3610,7 @@ 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)->state_key->direction) {
REASON_SET(reason, PFRES_SYNPROXY);
return (PF_SYNPROXY_DROP);
}
@@ -4223,13 +3642,13 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
struct pf_state_host *src, *dst;
if (direction == PF_OUT) {
- src = &(*state)->gwy;
- dst = &(*state)->ext;
+ src = &(*state)->state_key->gwy;
+ dst = &(*state)->state_key->ext;
} else {
- src = &(*state)->ext;
- dst = &(*state)->lan;
+ src = &(*state)->state_key->ext;
+ dst = &(*state)->state_key->lan;
}
- if (direction == (*state)->direction) {
+ if (direction == (*state)->state_key->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)) {
@@ -4279,22 +3698,6 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
}
}
- if (((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN) &&
- dst->state >= TCPS_FIN_WAIT_2 &&
- src->state >= TCPS_FIN_WAIT_2) {
- if (pf_status.debug >= PF_DEBUG_MISC) {
- printf("pf: state reuse ");
- pf_print_state(*state);
- pf_print_flags(th->th_flags);
- printf("\n");
- }
- /* XXX make sure it's the same direction ?? */
- (*state)->src.state = (*state)->dst.state = TCPS_CLOSED;
- pf_unlink_state(*state);
- *state = NULL;
- return (PF_DROP);
- }
-
if (src->wscale && dst->wscale && !(th->th_flags & TH_SYN)) {
sws = src->wscale & PF_WSCALE_MASK;
dws = dst->wscale & PF_WSCALE_MASK;
@@ -4591,7 +3994,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
seq, orig_seq, ack, pd->p_len, ackskew,
(*state)->packets[0], (*state)->packets[1],
direction == PF_IN ? "in" : "out",
- direction == (*state)->direction ? "fwd" : "rev");
+ direction == (*state)->state_key->direction ?
+ "fwd" : "rev");
printf("pf: State failure on: %c %c %c %c | %c %c\n",
SEQ_GEQ(src->seqhi, end) ? ' ' : '1',
SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) ?
@@ -4608,15 +4012,15 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
/* Any packets which have gotten here are to be passed */
/* translate source/destination address, if necessary */
- if (STATE_TRANSLATE(*state)) {
+ if (STATE_TRANSLATE((*state)->state_key)) {
if (direction == PF_OUT)
pf_change_ap(pd->src, &th->th_sport, pd->ip_sum,
- &th->th_sum, &(*state)->gwy.addr,
- (*state)->gwy.port, 0, pd->af);
+ &th->th_sum, &(*state)->state_key->gwy.addr,
+ (*state)->state_key->gwy.port, 0, pd->af);
else
pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum,
- &th->th_sum, &(*state)->lan.addr,
- (*state)->lan.port, 0, pd->af);
+ &th->th_sum, &(*state)->state_key->lan.addr,
+ (*state)->state_key->lan.port, 0, pd->af);
m_copyback(m, off, sizeof(*th), th);
} else if (copyback) {
/* Copyback sequence modulation or stateful scrub changes */
@@ -4631,7 +4035,7 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
struct mbuf *m, int off, void *h, struct pf_pdesc *pd)
{
struct pf_state_peer *src, *dst;
- struct pf_state_cmp key;
+ struct pf_state_key_cmp key;
struct udphdr *uh = pd->hdr.udp;
key.af = pd->af;
@@ -4650,7 +4054,7 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
STATE_LOOKUP();
- if (direction == (*state)->direction) {
+ if (direction == (*state)->state_key->direction) {
src = &(*state)->src;
dst = &(*state)->dst;
} else {
@@ -4672,15 +4076,15 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
(*state)->timeout = PFTM_UDP_SINGLE;
/* translate source/destination address, if necessary */
- if (STATE_TRANSLATE(*state)) {
+ if (STATE_TRANSLATE((*state)->state_key)) {
if (direction == PF_OUT)
pf_change_ap(pd->src, &uh->uh_sport, pd->ip_sum,
- &uh->uh_sum, &(*state)->gwy.addr,
- (*state)->gwy.port, 1, pd->af);
+ &uh->uh_sum, &(*state)->state_key->gwy.addr,
+ (*state)->state_key->gwy.port, 1, pd->af);
else
pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum,
- &uh->uh_sum, &(*state)->lan.addr,
- (*state)->lan.port, 1, pd->af);
+ &uh->uh_sum, &(*state)->state_key->lan.addr,
+ (*state)->state_key->lan.port, 1, pd->af);
m_copyback(m, off, sizeof(*uh), uh);
}
@@ -4695,7 +4099,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
u_int16_t icmpid, *icmpsum;
u_int8_t icmptype;
int state_icmp = 0;
- struct pf_state_cmp key;
+ struct pf_state_key_cmp key;
switch (pd->proto) {
#ifdef INET
@@ -4753,20 +4157,20 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
(*state)->timeout = PFTM_ICMP_ERROR_REPLY;
/* translate source/destination address, if necessary */
- if (STATE_TRANSLATE(*state)) {
+ if (STATE_TRANSLATE((*state)->state_key)) {
if (direction == PF_OUT) {
switch (pd->af) {
#ifdef INET
case AF_INET:
pf_change_a(&saddr->v4.s_addr,
pd->ip_sum,
- (*state)->gwy.addr.v4.s_addr, 0);
+ (*state)->state_key->gwy.addr.v4.s_addr, 0);
pd->hdr.icmp->icmp_cksum =
pf_cksum_fixup(
pd->hdr.icmp->icmp_cksum, icmpid,
- (*state)->gwy.port, 0);
+ (*state)->state_key->gwy.port, 0);
pd->hdr.icmp->icmp_id =
- (*state)->gwy.port;
+ (*state)->state_key->gwy.port;
m_copyback(m, off, ICMP_MINLEN,
pd->hdr.icmp);
break;
@@ -4775,7 +4179,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
case AF_INET6:
pf_change_a6(saddr,
&pd->hdr.icmp6->icmp6_cksum,
- &(*state)->gwy.addr, 0);
+ &(*state)->state_key->gwy.addr, 0);
m_copyback(m, off,
sizeof(struct icmp6_hdr),
pd->hdr.icmp6);
@@ -4788,13 +4192,13 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
case AF_INET:
pf_change_a(&daddr->v4.s_addr,
pd->ip_sum,
- (*state)->lan.addr.v4.s_addr, 0);
+ (*state)->state_key->lan.addr.v4.s_addr, 0);
pd->hdr.icmp->icmp_cksum =
pf_cksum_fixup(
pd->hdr.icmp->icmp_cksum, icmpid,
- (*state)->lan.port, 0);
+ (*state)->state_key->lan.port, 0);
pd->hdr.icmp->icmp_id =
- (*state)->lan.port;
+ (*state)->state_key->lan.port;
m_copyback(m, off, ICMP_MINLEN,
pd->hdr.icmp);
break;
@@ -4803,7 +4207,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
case AF_INET6:
pf_change_a6(daddr,
&pd->hdr.icmp6->icmp6_cksum,
- &(*state)->lan.addr, 0);
+ &(*state)->state_key->lan.addr, 0);
m_copyback(m, off,
sizeof(struct icmp6_hdr),
pd->hdr.icmp6);
@@ -4957,7 +4361,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
STATE_LOOKUP();
- if (direction == (*state)->direction) {
+ if (direction == (*state)->state_key->direction) {
src = &(*state)->dst;
dst = &(*state)->src;
} else {
@@ -4965,8 +4369,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
dst = &(*state)->dst;
}
- if (src->wscale && dst->wscale &&
- !(th.th_flags & TH_SYN))
+ if (src->wscale && dst->wscale)
dws = dst->wscale & PF_WSCALE_MASK;
else
dws = 0;
@@ -4995,17 +4398,17 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
return (PF_DROP);
}
- if (STATE_TRANSLATE(*state)) {
+ if (STATE_TRANSLATE((*state)->state_key)) {
if (direction == PF_IN) {
pf_change_icmp(pd2.src, &th.th_sport,
- daddr, &(*state)->lan.addr,
- (*state)->lan.port, NULL,
+ daddr, &(*state)->state_key->lan.addr,
+ (*state)->state_key->lan.port, NULL,
pd2.ip_sum, icmpsum,
pd->ip_sum, 0, pd2.af);
} else {
pf_change_icmp(pd2.dst, &th.th_dport,
- saddr, &(*state)->gwy.addr,
- (*state)->gwy.port, NULL,
+ saddr, &(*state)->state_key->gwy.addr,
+ (*state)->state_key->gwy.port, NULL,
pd2.ip_sum, icmpsum,
pd->ip_sum, 0, pd2.af);
}
@@ -5065,17 +4468,20 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
STATE_LOOKUP();
- if (STATE_TRANSLATE(*state)) {
+ if (STATE_TRANSLATE((*state)->state_key)) {
if (direction == PF_IN) {
pf_change_icmp(pd2.src, &uh.uh_sport,
- daddr, &(*state)->lan.addr,
- (*state)->lan.port, &uh.uh_sum,
+ daddr,
+ &(*state)->state_key->lan.addr,
+ (*state)->state_key->lan.port,
+ &uh.uh_sum,
pd2.ip_sum, icmpsum,
pd->ip_sum, 1, pd2.af);
} else {
pf_change_icmp(pd2.dst, &uh.uh_dport,
- saddr, &(*state)->gwy.addr,
- (*state)->gwy.port, &uh.uh_sum,
+ saddr,
+ &(*state)->state_key->gwy.addr,
+ (*state)->state_key->gwy.port, &uh.uh_sum,
pd2.ip_sum, icmpsum,
pd->ip_sum, 1, pd2.af);
}
@@ -5131,17 +4537,19 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
STATE_LOOKUP();
- if (STATE_TRANSLATE(*state)) {
+ if (STATE_TRANSLATE((*state)->state_key)) {
if (direction == PF_IN) {
pf_change_icmp(pd2.src, &iih.icmp_id,
- daddr, &(*state)->lan.addr,
- (*state)->lan.port, NULL,
+ daddr,
+ &(*state)->state_key->lan.addr,
+ (*state)->state_key->lan.port, NULL,
pd2.ip_sum, icmpsum,
pd->ip_sum, 0, AF_INET);
} else {
pf_change_icmp(pd2.dst, &iih.icmp_id,
- saddr, &(*state)->gwy.addr,
- (*state)->gwy.port, NULL,
+ saddr,
+ &(*state)->state_key->gwy.addr,
+ (*state)->state_key->gwy.port, NULL,
pd2.ip_sum, icmpsum,
pd->ip_sum, 0, AF_INET);
}
@@ -5182,17 +4590,18 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
STATE_LOOKUP();
- if (STATE_TRANSLATE(*state)) {
+ if (STATE_TRANSLATE((*state)->state_key)) {
if (direction == PF_IN) {
pf_change_icmp(pd2.src, &iih.icmp6_id,
- daddr, &(*state)->lan.addr,
- (*state)->lan.port, NULL,
+ daddr,
+ &(*state)->state_key->lan.addr,
+ (*state)->state_key->lan.port, NULL,
pd2.ip_sum, icmpsum,
pd->ip_sum, 0, AF_INET6);
} else {
pf_change_icmp(pd2.dst, &iih.icmp6_id,
- saddr, &(*state)->gwy.addr,
- (*state)->gwy.port, NULL,
+ saddr, &(*state)->state_key->gwy.addr,
+ (*state)->state_key->gwy.port, NULL,
pd2.ip_sum, icmpsum,
pd->ip_sum, 0, AF_INET6);
}
@@ -5224,16 +4633,18 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
STATE_LOOKUP();
- if (STATE_TRANSLATE(*state)) {
+ if (STATE_TRANSLATE((*state)->state_key)) {
if (direction == PF_IN) {
pf_change_icmp(pd2.src, NULL,
- daddr, &(*state)->lan.addr,
+ daddr,
+ &(*state)->state_key->lan.addr,
0, NULL,
pd2.ip_sum, icmpsum,
pd->ip_sum, 0, pd2.af);
} else {
pf_change_icmp(pd2.dst, NULL,
- saddr, &(*state)->gwy.addr,
+ saddr,
+ &(*state)->state_key->gwy.addr,
0, NULL,
pd2.ip_sum, icmpsum,
pd->ip_sum, 0, pd2.af);
@@ -5270,7 +4681,7 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
struct pf_pdesc *pd)
{
struct pf_state_peer *src, *dst;
- struct pf_state_cmp key;
+ struct pf_state_key_cmp key;
key.af = pd->af;
key.proto = pd->proto;
@@ -5288,7 +4699,7 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
STATE_LOOKUP();
- if (direction == (*state)->direction) {
+ if (direction == (*state)->state_key->direction) {
src = &(*state)->src;
dst = &(*state)->dst;
} else {
@@ -5310,19 +4721,21 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
(*state)->timeout = PFTM_OTHER_SINGLE;
/* translate source/destination address, if necessary */
- if (STATE_TRANSLATE(*state)) {
+ if (STATE_TRANSLATE((*state)->state_key)) {
if (direction == PF_OUT)
switch (pd->af) {
#ifdef INET
case AF_INET:
pf_change_a(&pd->src->v4.s_addr,
- pd->ip_sum, (*state)->gwy.addr.v4.s_addr,
+ pd->ip_sum,
+ (*state)->state_key->gwy.addr.v4.s_addr,
0);
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
- PF_ACPY(pd->src, &(*state)->gwy.addr, pd->af);
+ PF_ACPY(pd->src,
+ &(*state)->state_key->gwy.addr, pd->af);
break;
#endif /* INET6 */
}
@@ -5331,13 +4744,15 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
#ifdef INET
case AF_INET:
pf_change_a(&pd->dst->v4.s_addr,
- pd->ip_sum, (*state)->lan.addr.v4.s_addr,
+ pd->ip_sum,
+ (*state)->state_key->lan.addr.v4.s_addr,
0);
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
- PF_ACPY(pd->dst, &(*state)->lan.addr, pd->af);
+ PF_ACPY(pd->dst,
+ &(*state)->state_key->lan.addr, pd->af);
break;
#endif /* INET6 */
}
@@ -5543,7 +4958,7 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
(dir != PF_IN && dir != PF_OUT) || oifp == NULL)
panic("pf_route: invalid parameters");
- if (pd->pf_mtag->routed++ > 3) {
+ if ((*m)->m_pkthdr.pf.routed++ > 3) {
m0 = *m;
*m = NULL;
goto bad;
@@ -5734,7 +5149,7 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
(dir != PF_IN && dir != PF_OUT) || oifp == NULL)
panic("pf_route6: invalid parameters");
- if (pd->pf_mtag->routed++ > 3) {
+ if ((*m)->m_pkthdr.pf.routed++ > 3) {
m0 = *m;
*m = NULL;
goto bad;
@@ -5765,8 +5180,8 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
/* Cheat. XXX why only in the v6 case??? */
if (r->rt == PF_FASTROUTE) {
- pd->pf_mtag->flags |= PF_TAG_GENERATED;
- ip6_output(m0, NULL, NULL, 0, NULL, NULL);
+ m0->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
+ ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
return;
}
@@ -5934,6 +5349,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
struct ip *h;
struct pf_rule *a = NULL, *r = &pf_default_rule, *tr, *nr;
struct pf_state *s = NULL;
+ struct pf_state_key *sk = NULL;
struct pf_ruleset *ruleset = NULL;
struct pf_pdesc pd;
int off, dirndx, pqid = 0;
@@ -5942,18 +5358,11 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
return (PF_PASS);
memset(&pd, 0, sizeof(pd));
- if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) {
- DPFPRINTF(PF_DEBUG_URGENT,
- ("pf_test: pf_get_mtag returned NULL\n"));
- return (PF_DROP);
- }
- if (pd.pf_mtag->flags & PF_TAG_GENERATED)
- return (PF_PASS);
-
if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
- ifp = ifp->if_carpdev;
+ kif = (struct pfi_kif *)ifp->if_carpdev->if_pf_kif;
+ else
+ kif = (struct pfi_kif *)ifp->if_pf_kif;
- kif = (struct pfi_kif *)ifp->if_pf_kif;
if (kif == NULL) {
DPFPRINTF(PF_DEBUG_URGENT,
("pf_test: kif == NULL, if_xname %s\n", ifp->if_xname));
@@ -5974,12 +5383,15 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
goto done;
}
+ if (m->m_pkthdr.pf.flags & PF_TAG_GENERATED)
+ return (PF_PASS);
+
/* We do IP header normalization and packet reassembly here */
if (pf_normalize_ip(m0, dir, kif, &reason, &pd) != PF_PASS) {
action = PF_DROP;
goto done;
}
- m = *m0;
+ m = *m0; /* pf_normalize messes with m0 */
h = mtod(m, struct ip *);
off = h->ip_hl << 2;
@@ -6018,12 +5430,6 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
log = action != PF_PASS;
goto done;
}
- if (dir == PF_IN && pf_check_proto_cksum(m, off,
- ntohs(h->ip_len) - off, IPPROTO_TCP, AF_INET)) {
- REASON_SET(&reason, PFRES_PROTCKSUM);
- action = PF_DROP;
- goto done;
- }
pd.p_len = pd.tot_len - off - (th.th_off << 2);
if ((th.th_flags & TH_ACK) && pd.p_len == 0)
pqid = 1;
@@ -6040,7 +5446,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
- action = pf_test_tcp(&r, &s, dir, kif,
+ action = pf_test_rule(&r, &s, dir, kif,
m, off, h, &pd, &a, &ruleset, &ipintrq);
break;
}
@@ -6054,12 +5460,6 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
log = action != PF_PASS;
goto done;
}
- if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
- off, ntohs(h->ip_len) - off, IPPROTO_UDP, AF_INET)) {
- action = PF_DROP;
- REASON_SET(&reason, PFRES_PROTCKSUM);
- goto done;
- }
if (uh.uh_dport == 0 ||
ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
@@ -6076,7 +5476,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
- action = pf_test_udp(&r, &s, dir, kif,
+ action = pf_test_rule(&r, &s, dir, kif,
m, off, h, &pd, &a, &ruleset, &ipintrq);
break;
}
@@ -6090,12 +5490,6 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
log = action != PF_PASS;
goto done;
}
- if (dir == PF_IN && pf_check_proto_cksum(m, off,
- ntohs(h->ip_len) - off, IPPROTO_ICMP, AF_INET)) {
- action = PF_DROP;
- REASON_SET(&reason, PFRES_PROTCKSUM);
- goto done;
- }
action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd,
&reason);
if (action == PF_PASS) {
@@ -6106,7 +5500,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
- action = pf_test_icmp(&r, &s, dir, kif,
+ action = pf_test_rule(&r, &s, dir, kif,
m, off, h, &pd, &a, &ruleset, &ipintrq);
break;
}
@@ -6121,7 +5515,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
- action = pf_test_other(&r, &s, dir, kif, m, off, h,
+ action = pf_test_rule(&r, &s, dir, kif, m, off, h,
&pd, &a, &ruleset, &ipintrq);
break;
}
@@ -6137,17 +5531,16 @@ done:
}
if ((s && s->tag) || r->rtableid)
- pf_tag_packet(m, pd.pf_mtag, s ? s->tag : 0, r->rtableid);
+ pf_tag_packet(m, s ? s->tag : 0, r->rtableid);
#ifdef ALTQ
if (action == PF_PASS && r->qid) {
if (pqid || (pd.tos & IPTOS_LOWDELAY))
- pd.pf_mtag->qid = r->pqid;
+ m->m_pkthdr.pf.qid = r->pqid;
else
- pd.pf_mtag->qid = r->qid;
+ m->m_pkthdr.pf.qid = r->qid;
/* add hints for ecn */
- pd.pf_mtag->af = AF_INET;
- pd.pf_mtag->hdr = h;
+ m->m_pkthdr.pf.hdr = h;
}
#endif /* ALTQ */
@@ -6161,7 +5554,7 @@ done:
(s->nat_rule.ptr->action == PF_RDR ||
s->nat_rule.ptr->action == PF_BINAT) &&
(ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
- pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST;
+ m->m_pkthdr.pf.flags |= PF_TAG_TRANSLATE_LOCALHOST;
if (log) {
struct pf_rule *lr;
@@ -6187,6 +5580,7 @@ done:
a->bytes[dirndx] += pd.tot_len;
}
if (s != NULL) {
+ sk = s->state_key;
if (s->nat_rule.ptr != NULL) {
s->nat_rule.ptr->packets[dirndx]++;
s->nat_rule.ptr->bytes[dirndx] += pd.tot_len;
@@ -6199,7 +5593,7 @@ done:
s->nat_src_node->packets[dirndx]++;
s->nat_src_node->bytes[dirndx] += pd.tot_len;
}
- dirndx = (dir == s->direction) ? 0 : 1;
+ dirndx = (dir == sk->direction) ? 0 : 1;
s->packets[dirndx]++;
s->bytes[dirndx] += pd.tot_len;
}
@@ -6214,10 +5608,10 @@ done:
*/
if (r == &pf_default_rule) {
tr = nr;
- x = (s == NULL || s->direction == dir) ?
+ x = (sk == NULL || sk->direction == dir) ?
&pd.baddr : &pd.naddr;
} else
- x = (s == NULL || s->direction == dir) ?
+ x = (sk == NULL || sk->direction == dir) ?
&pd.naddr : &pd.baddr;
if (x == &pd.baddr || s == NULL) {
/* we need to change the address */
@@ -6228,13 +5622,14 @@ done:
}
}
if (tr->src.addr.type == PF_ADDR_TABLE)
- pfr_update_stats(tr->src.addr.p.tbl, (s == NULL ||
- s->direction == dir) ? pd.src : pd.dst, pd.af,
+ pfr_update_stats(tr->src.addr.p.tbl, (sk == NULL ||
+ sk->direction == dir) ?
+ pd.src : pd.dst, pd.af,
pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
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,
+ pfr_update_stats(tr->dst.addr.p.tbl, (sk == NULL ||
+ sk->direction == dir) ? pd.dst : pd.src, pd.af,
pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
tr->dst.neg);
}
@@ -6246,7 +5641,7 @@ done:
action = PF_PASS;
} else if (r->rt)
/* pf_route can free the mbuf causing *m0 to become NULL */
- pf_route(m0, r, dir, ifp, s, &pd);
+ pf_route(m0, r, dir, kif->pfik_ifp, s, &pd);
return (action);
}
@@ -6263,26 +5658,20 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
struct ip6_hdr *h;
struct pf_rule *a = NULL, *r = &pf_default_rule, *tr, *nr;
struct pf_state *s = NULL;
+ struct pf_state_key *sk = NULL;
struct pf_ruleset *ruleset = NULL;
struct pf_pdesc pd;
- int off, terminal = 0, dirndx;
+ int off, terminal = 0, dirndx, rh_cnt = 0;
if (!pf_status.running)
return (PF_PASS);
memset(&pd, 0, sizeof(pd));
- if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) {
- DPFPRINTF(PF_DEBUG_URGENT,
- ("pf_test6: pf_get_mtag returned NULL\n"));
- return (PF_DROP);
- }
- if (pd.pf_mtag->flags & PF_TAG_GENERATED)
- return (PF_PASS);
-
if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
- ifp = ifp->if_carpdev;
+ kif = (struct pfi_kif *)ifp->if_carpdev->if_pf_kif;
+ else
+ kif = (struct pfi_kif *)ifp->if_pf_kif;
- kif = (struct pfi_kif *)ifp->if_pf_kif;
if (kif == NULL) {
DPFPRINTF(PF_DEBUG_URGENT,
("pf_test6: kif == NULL, if_xname %s\n", ifp->if_xname));
@@ -6303,12 +5692,15 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
goto done;
}
+ if (m->m_pkthdr.pf.flags & PF_TAG_GENERATED)
+ return (PF_PASS);
+
/* We do IP header normalization and packet reassembly here */
if (pf_normalize_ip6(m0, dir, kif, &reason, &pd) != PF_PASS) {
action = PF_DROP;
goto done;
}
- m = *m0;
+ m = *m0; /* pf_normalize messes with m0 */
h = mtod(m, struct ip6_hdr *);
#if 1
@@ -6344,60 +5736,31 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
goto done;
case IPPROTO_ROUTING: {
struct ip6_rthdr rthdr;
- struct ip6_rthdr0 rthdr0;
- struct in6_addr finaldst;
- struct ip6_hdr *ip6;
+ if (rh_cnt++) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: IPv6 more than one rthdr\n"));
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_IPOPTIONS);
+ log = 1;
+ goto done;
+ }
if (!pf_pull_hdr(m, off, &rthdr, sizeof(rthdr), NULL,
&reason, pd.af)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: IPv6 short rthdr\n"));
action = PF_DROP;
+ REASON_SET(&reason, PFRES_SHORT);
log = 1;
goto done;
}
if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) {
- if (!pf_pull_hdr(m, off, &rthdr0,
- sizeof(rthdr0), NULL, &reason, pd.af)) {
- DPFPRINTF(PF_DEBUG_MISC,
- ("pf: IPv6 short rthdr0\n"));
- action = PF_DROP;
- log = 1;
- goto done;
- }
- if (rthdr0.ip6r0_segleft != 0) {
- if (!pf_pull_hdr(m, off +
- sizeof(rthdr0) +
- rthdr0.ip6r0_len * 8 -
- sizeof(finaldst), &finaldst,
- sizeof(finaldst), NULL,
- &reason, pd.af)) {
- DPFPRINTF(PF_DEBUG_MISC,
- ("pf: IPv6 short rthdr0\n"));
- action = PF_DROP;
- log = 1;
- goto done;
- }
-
- n = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
- if (!n) {
- DPFPRINTF(PF_DEBUG_MISC,
- ("pf: mbuf shortage\n"));
- action = PF_DROP;
- log = 1;
- goto done;
- }
- n = m_pullup(n, sizeof(struct ip6_hdr));
- if (!n) {
- DPFPRINTF(PF_DEBUG_MISC,
- ("pf: mbuf shortage\n"));
- action = PF_DROP;
- log = 1;
- goto done;
- }
- ip6 = mtod(n, struct ip6_hdr *);
- ip6->ip6_dst = finaldst;
- }
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: IPv6 rthdr0\n"));
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_IPOPTIONS);
+ log = 1;
+ goto done;
}
/* FALLTHROUGH */
}
@@ -6444,13 +5807,6 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
log = action != PF_PASS;
goto done;
}
- if (dir == PF_IN && pf_check_proto_cksum(n, off,
- 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);
action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
if (action == PF_DROP)
@@ -6465,7 +5821,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
- action = pf_test_tcp(&r, &s, dir, kif,
+ action = pf_test_rule(&r, &s, dir, kif,
m, off, h, &pd, &a, &ruleset, &ip6intrq);
break;
}
@@ -6479,13 +5835,6 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
log = action != PF_PASS;
goto done;
}
- if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(n,
- 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 ||
ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
@@ -6502,7 +5851,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
- action = pf_test_udp(&r, &s, dir, kif,
+ action = pf_test_rule(&r, &s, dir, kif,
m, off, h, &pd, &a, &ruleset, &ip6intrq);
break;
}
@@ -6516,13 +5865,6 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
log = action != PF_PASS;
goto done;
}
- if (dir == PF_IN && pf_check_proto_cksum(n, off,
- 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, &reason);
if (action == PF_PASS) {
@@ -6533,7 +5875,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
- action = pf_test_icmp(&r, &s, dir, kif,
+ action = pf_test_rule(&r, &s, dir, kif,
m, off, h, &pd, &a, &ruleset, &ip6intrq);
break;
}
@@ -6548,7 +5890,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
- action = pf_test_other(&r, &s, dir, kif, m, off, h,
+ action = pf_test_rule(&r, &s, dir, kif, m, off, h,
&pd, &a, &ruleset, &ip6intrq);
break;
}
@@ -6559,20 +5901,27 @@ done:
n = NULL;
}
- /* XXX handle IPv6 options, if not allowed. not implemented. */
+ /* handle dangerous IPv6 extension headers. */
+ if (action == PF_PASS && rh_cnt &&
+ !((s && s->allow_opts) || r->allow_opts)) {
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_IPOPTIONS);
+ log = 1;
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: dropping packet with dangerous v6 headers\n"));
+ }
if ((s && s->tag) || r->rtableid)
- pf_tag_packet(m, pd.pf_mtag, s ? s->tag : 0, r->rtableid);
+ pf_tag_packet(m, s ? s->tag : 0, r->rtableid);
#ifdef ALTQ
if (action == PF_PASS && r->qid) {
if (pd.tos & IPTOS_LOWDELAY)
- pd.pf_mtag->qid = r->pqid;
+ m->m_pkthdr.pf.qid = r->pqid;
else
- pd.pf_mtag->qid = r->qid;
+ m->m_pkthdr.pf.qid = r->qid;
/* add hints for ecn */
- pd.pf_mtag->af = AF_INET6;
- pd.pf_mtag->hdr = h;
+ m->m_pkthdr.pf.hdr = h;
}
#endif /* ALTQ */
@@ -6581,7 +5930,7 @@ done:
(s->nat_rule.ptr->action == PF_RDR ||
s->nat_rule.ptr->action == PF_BINAT) &&
IN6_IS_ADDR_LOOPBACK(&pd.dst->v6))
- pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST;
+ m->m_pkthdr.pf.flags |= PF_TAG_TRANSLATE_LOCALHOST;
if (log) {
struct pf_rule *lr;
@@ -6607,6 +5956,7 @@ done:
a->bytes[dirndx] += pd.tot_len;
}
if (s != NULL) {
+ sk = s->state_key;
if (s->nat_rule.ptr != NULL) {
s->nat_rule.ptr->packets[dirndx]++;
s->nat_rule.ptr->bytes[dirndx] += pd.tot_len;
@@ -6619,7 +5969,7 @@ done:
s->nat_src_node->packets[dirndx]++;
s->nat_src_node->bytes[dirndx] += pd.tot_len;
}
- dirndx = (dir == s->direction) ? 0 : 1;
+ dirndx = (dir == sk->direction) ? 0 : 1;
s->packets[dirndx]++;
s->bytes[dirndx] += pd.tot_len;
}
@@ -6634,10 +5984,10 @@ done:
*/
if (r == &pf_default_rule) {
tr = nr;
- x = (s == NULL || s->direction == dir) ?
+ x = (s == NULL || sk->direction == dir) ?
&pd.baddr : &pd.naddr;
} else {
- x = (s == NULL || s->direction == dir) ?
+ x = (s == NULL || sk->direction == dir) ?
&pd.naddr : &pd.baddr;
}
if (x == &pd.baddr || s == NULL) {
@@ -6648,13 +5998,13 @@ done:
}
}
if (tr->src.addr.type == PF_ADDR_TABLE)
- pfr_update_stats(tr->src.addr.p.tbl, (s == NULL ||
- s->direction == dir) ? pd.src : pd.dst, pd.af,
+ pfr_update_stats(tr->src.addr.p.tbl, (sk == NULL ||
+ sk->direction == dir) ? pd.src : pd.dst, pd.af,
pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
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,
+ pfr_update_stats(tr->dst.addr.p.tbl, (sk == NULL ||
+ sk->direction == dir) ? pd.dst : pd.src, pd.af,
pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
tr->dst.neg);
}
@@ -6666,7 +6016,7 @@ done:
action = PF_PASS;
} else if (r->rt)
/* pf_route6 can free the mbuf causing *m0 to become NULL */
- pf_route6(m0, r, dir, ifp, s, &pd);
+ pf_route6(m0, r, dir, kif->pfik_ifp, s, &pd);
return (action);
}