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