From da18614102dd243fb002131ebdf5e2c9241776e6 Mon Sep 17 00:00:00 2001 From: yamt Date: Sun, 14 Nov 2004 11:12:16 +0000 Subject: [PATCH] resolve conflicts. (pf from OpenBSD 3.6, kernel part) --- sys/dist/pf/net/if_pflog.c | 10 +- sys/dist/pf/net/if_pflog.h | 11 +- sys/dist/pf/net/pf.c | 758 ++++++++++++++++++++++--------------- sys/dist/pf/net/pf_if.c | 92 ++--- sys/dist/pf/net/pf_ioctl.c | 710 +++++++++++++++++++--------------- sys/dist/pf/net/pf_norm.c | 393 +++++++++++++++++-- sys/dist/pf/net/pf_osfp.c | 8 +- sys/dist/pf/net/pf_table.c | 184 +++++---- sys/dist/pf/net/pfvar.h | 146 ++++--- 9 files changed, 1455 insertions(+), 857 deletions(-) diff --git a/sys/dist/pf/net/if_pflog.c b/sys/dist/pf/net/if_pflog.c index bfe90b4cceba..f464feb7dbfd 100644 --- a/sys/dist/pf/net/if_pflog.c +++ b/sys/dist/pf/net/if_pflog.c @@ -1,5 +1,5 @@ -/* $NetBSD: if_pflog.c,v 1.4 2004/09/10 08:48:32 yamt Exp $ */ -/* $OpenBSD: if_pflog.c,v 1.11 2003/12/31 11:18:25 cedric Exp $ */ +/* $NetBSD: if_pflog.c,v 1.5 2004/11/14 11:12:16 yamt Exp $ */ +/* $OpenBSD: if_pflog.c,v 1.12 2004/05/19 17:50:51 dhartmei Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), * Angelos D. Keromytis (kermit@csd.uch.gr) and @@ -230,11 +230,9 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir, } else { hdr.rulenr = htonl(am->nr); hdr.subrulenr = htonl(rm->nr); - if (ruleset != NULL) - memcpy(hdr.ruleset, ruleset->name, + if (ruleset != NULL && ruleset->anchor != NULL) + strlcpy(hdr.ruleset, ruleset->anchor->name, sizeof(hdr.ruleset)); - - } hdr.dir = dir; diff --git a/sys/dist/pf/net/if_pflog.h b/sys/dist/pf/net/if_pflog.h index 9c94cdd2c643..81990658b39f 100644 --- a/sys/dist/pf/net/if_pflog.h +++ b/sys/dist/pf/net/if_pflog.h @@ -1,5 +1,5 @@ -/* $NetBSD: if_pflog.h,v 1.2 2004/06/22 14:17:07 itojun Exp $ */ -/* $OpenBSD: if_pflog.h,v 1.10 2004/03/19 04:52:04 frantzen Exp $ */ +/* $NetBSD: if_pflog.h,v 1.3 2004/11/14 11:12:16 yamt Exp $ */ +/* $OpenBSD: if_pflog.h,v 1.11 2004/05/19 17:50:51 dhartmei Exp $ */ /* * Copyright 2001 Niels Provos * All rights reserved. @@ -32,10 +32,7 @@ struct pflog_softc { struct ifnet sc_if; /* the interface */ }; -/* XXX keep in sync with pfvar.h */ -#ifndef PF_RULESET_NAME_SIZE -#define PF_RULESET_NAME_SIZE 16 -#endif +#define PFLOG_RULESET_NAME_SIZE 16 struct pfloghdr { u_int8_t length; @@ -43,7 +40,7 @@ struct pfloghdr { u_int8_t action; u_int8_t reason; char ifname[IFNAMSIZ]; - char ruleset[PF_RULESET_NAME_SIZE]; + char ruleset[PFLOG_RULESET_NAME_SIZE]; u_int32_t rulenr; u_int32_t subrulenr; u_int8_t dir; diff --git a/sys/dist/pf/net/pf.c b/sys/dist/pf/net/pf.c index db13f5ded43b..8156350fa188 100644 --- a/sys/dist/pf/net/pf.c +++ b/sys/dist/pf/net/pf.c @@ -1,5 +1,5 @@ -/* $NetBSD: pf.c,v 1.4 2004/09/08 12:11:25 yamt Exp $ */ -/* $OpenBSD: pf.c,v 1.433 2004/03/26 22:20:57 dhartmei Exp $ */ +/* $NetBSD: pf.c,v 1.5 2004/11/14 11:12:16 yamt Exp $ */ +/* $OpenBSD: pf.c,v 1.457.2.1 2004/11/06 00:39:35 brad Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -76,6 +76,11 @@ #include #include #include +#ifdef __OpenBSD__ +#include +#else +#include +#endif #ifdef __OpenBSD__ #include @@ -99,14 +104,13 @@ #include #endif /* INET6 */ - #define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x /* * 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; @@ -125,15 +129,18 @@ struct timeout pf_expire_to; /* expire timeout */ struct callout pf_expire_to; /* expire timeout */ #endif +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); -u_int16_t pf_cksum_fixup(u_int16_t, u_int16_t, u_int16_t, - u_int8_t); void pf_change_ap(struct pf_addr *, u_int16_t *, u_int16_t *, u_int16_t *, struct pf_addr *, u_int16_t, u_int8_t, sa_family_t); @@ -148,7 +155,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 *, @@ -163,19 +171,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 **, @@ -193,7 +201,7 @@ 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_rule *, 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 *, @@ -224,6 +232,7 @@ 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_check_congestion(struct ifqueue *); struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = { { &pf_state_pl, PFSTATE_HIWAT }, @@ -270,6 +279,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; @@ -283,6 +293,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) @@ -479,6 +491,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) @@ -497,7 +517,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) @@ -614,7 +634,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++; @@ -739,7 +759,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); @@ -760,7 +780,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); } @@ -773,7 +793,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 && @@ -799,7 +819,7 @@ pf_src_tree_remove_state(struct pf_state *s) 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) { @@ -808,12 +828,48 @@ 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); + pool_put(&pf_state_pl, cur); + pf_status.fcounters[FCNT_STATE_REMOVALS]++; + pf_status.states--; +} + void pf_purge_expired_states(void) { @@ -822,40 +878,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); } } @@ -1045,14 +1069,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] || @@ -1091,21 +1115,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) { @@ -1290,10 +1299,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 = NULL; @@ -1325,17 +1334,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); @@ -1348,7 +1362,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; @@ -1416,8 +1430,36 @@ 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 { +#ifdef __OpenBSD__ + 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); +#else + /* + * on netbsd, pf_test and pf_test6 are always called + * with eh == NULL. + */ + panic("pf_send_tcp: eh != NULL"); +#endif + } break; #endif /* INET */ #ifdef INET6 @@ -1470,7 +1512,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 @@ -1596,12 +1638,12 @@ 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) + 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) @@ -1632,36 +1674,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 @@ -1815,20 +1887,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) @@ -1850,25 +1929,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 */ } @@ -1993,7 +2076,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); @@ -2035,8 +2118,9 @@ 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; + int asd = 0; r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr); while (r && rm == NULL) { @@ -2062,7 +2146,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, @@ -2070,7 +2154,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); @@ -2082,15 +2166,12 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off, 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) 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); + 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 (rm != NULL && (rm->action == PF_NONAT || rm->action == PF_NORDR || rm->action == PF_NOBINAT)) @@ -2143,7 +2224,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); @@ -2153,7 +2236,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); @@ -2163,6 +2249,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, @@ -2172,7 +2260,9 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, break; case PF_IN: if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){ - if (pd->af == AF_INET) { + switch (pd->af) { +#ifdef INET + case AF_INET: if (r->src.addr.p.dyn-> pfid_acnt4 < 1) return (NULL); @@ -2182,7 +2272,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); @@ -2192,6 +2285,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, @@ -2270,6 +2365,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: #ifdef __OpenBSD__ inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport); @@ -2288,6 +2384,7 @@ pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd) } #endif break; +#endif /* INET */ #ifdef INET6 case AF_INET6: #ifdef __OpenBSD__ @@ -2499,7 +2596,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; @@ -2517,6 +2615,10 @@ 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)) + return (PF_DROP); r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); @@ -2561,12 +2663,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)) @@ -2587,9 +2689,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, nr, &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)) @@ -2605,12 +2707,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; @@ -2652,7 +2754,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); @@ -2756,7 +2858,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); @@ -2781,8 +2883,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) { @@ -2802,8 +2904,11 @@ cleanup: 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); pool_put(&pf_state_pl, s); @@ -2831,7 +2936,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); @@ -2839,7 +2944,7 @@ 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); return (PF_SYNPROXY_DROP); } } @@ -2854,7 +2959,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; @@ -2871,6 +2977,10 @@ 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)) + return (PF_DROP); r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); @@ -2915,12 +3025,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)) @@ -2939,9 +3049,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, nr, &pftag, &tag)) r = TAILQ_NEXT(r, entries); else if (r->os_fingerprint != PF_OSFP_ANY) r = TAILQ_NEXT(r, entries); @@ -2956,12 +3066,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; @@ -3085,8 +3195,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) { @@ -3117,7 +3227,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; @@ -3134,6 +3245,10 @@ 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)) + return (PF_DROP); switch (pd->proto) { #ifdef INET @@ -3228,9 +3343,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); @@ -3240,9 +3355,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, nr, &pftag, &tag)) r = TAILQ_NEXT(r, entries); else if (r->os_fingerprint != PF_OSFP_ANY) r = TAILQ_NEXT(r, entries); @@ -3257,12 +3372,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; @@ -3360,8 +3475,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) { @@ -3395,7 +3510,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; @@ -3406,6 +3521,10 @@ 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)) + return (PF_DROP); r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); @@ -3466,17 +3585,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, nr, &pftag, &tag)) r = TAILQ_NEXT(r, entries); else if (r->os_fingerprint != PF_OSFP_ANY) r = TAILQ_NEXT(r, entries); @@ -3491,12 +3610,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; @@ -3618,8 +3737,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) { @@ -3654,6 +3773,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) { @@ -3667,9 +3787,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); @@ -3677,9 +3797,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, NULL, &pftag, &tag)) r = TAILQ_NEXT(r, entries); else { if (r->anchor == NULL) { @@ -3690,12 +3810,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; @@ -3725,7 +3845,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; @@ -3764,7 +3884,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, 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); return (PF_SYNPROXY_DROP); } else if (!(th->th_flags & TH_ACK) || (ntohl(th->th_ack) != (*state)->src.seqhi + 1) || @@ -3790,11 +3911,11 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, 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); return (PF_SYNPROXY_DROP); } else if (((th->th_flags & (TH_SYN|TH_ACK)) != (TH_SYN|TH_ACK)) || @@ -3806,11 +3927,13 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, 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, 1, + 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, 0, + NULL, NULL); (*state)->src.seqdiff = (*state)->dst.seqhi - (*state)->src.seqlo; (*state)->dst.seqdiff = (*state)->src.seqhi - @@ -3838,7 +3961,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 */ @@ -3852,7 +3975,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 + @@ -3948,8 +4071,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) @@ -3979,7 +4111,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, 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; @@ -4035,6 +4167,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; @@ -4073,7 +4211,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, 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); + (*state)->rule.ptr->return_ttl, 1, + pd->eh, kif->pfik_ifp); } src->seqlo = 0; src->seqhi = 1; @@ -4099,11 +4238,6 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, 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 */ @@ -4165,7 +4299,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 @@ -4250,7 +4384,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 */ @@ -4788,7 +4922,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 @@ -4914,12 +5048,12 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, struct pf_state *s) { struct mbuf *m0, *m1; + struct m_tag *mtag; struct route iproute; struct route *ro = NULL; struct sockaddr_in *dst; struct ip *ip; struct ifnet *ifp = NULL; - struct m_tag *mtag; struct pf_addr naddr; struct pf_src_node *sn = NULL; int error = 0; @@ -4931,22 +5065,30 @@ 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 (r->rt == PF_DUPTO) { - m0 = *m; - mtag = m_tag_find(m0, PACKET_TAG_PF_ROUTED, NULL); - if (mtag == NULL) { - mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 0, M_NOWAIT); - if (mtag == NULL) - goto bad; - m_tag_prepend(m0, mtag); + if ((mtag = m_tag_find(*m, PACKET_TAG_PF_ROUTED, NULL)) == NULL) { + if ((mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 1, M_NOWAIT)) == + NULL) { + m0 = *m; + *m = NULL; + goto bad; } -#ifdef __OpenBSD__ - m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT); -#else - m0 = m_dup(*m, 0, M_COPYALL, M_NOWAIT); -#endif - if (m0 == NULL) + *(char *)(mtag + 1) = 1; + m_tag_prepend(*m, mtag); + } else { + if (*(char *)(mtag + 1) > 3) { + m0 = *m; + *m = NULL; + goto bad; + } + (*(char *)(mtag + 1))++; + } + + if (r->rt == PF_DUPTO) { + 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; @@ -4993,22 +5135,11 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL; } } - if (ifp == NULL) goto bad; - mtag = m_tag_find(m0, PACKET_TAG_PF_ROUTED, NULL); - if (mtag == NULL) { - struct m_tag *mtag; - - mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 0, M_NOWAIT); - if (mtag == NULL) - goto bad; - m_tag_prepend(m0, mtag); - } - - if (oifp != ifp && mtag == NULL) { - if (pf_test(PF_OUT, ifp, &m0) != PF_PASS) + if (oifp != ifp) { + if (pf_test(PF_OUT, ifp, &m0, NULL) != PF_PASS) goto bad; else if (m0 == NULL) goto done; @@ -5145,22 +5276,30 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, (dir != PF_IN && dir != PF_OUT) || oifp == NULL) panic("pf_route6: invalid parameters"); - if (r->rt == PF_DUPTO) { - m0 = *m; - mtag = m_tag_find(m0, PACKET_TAG_PF_ROUTED, NULL); - if (mtag == NULL) { - mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 0, M_NOWAIT); - if (mtag == NULL) - goto bad; - m_tag_prepend(m0, mtag); + if ((mtag = m_tag_find(*m, PACKET_TAG_PF_ROUTED, NULL)) == NULL) { + if ((mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 1, M_NOWAIT)) == + NULL) { + m0 = *m; + *m = NULL; + goto bad; } -#ifdef __OpenBSD__ - m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT); -#else - m0 = m_dup(*m, 0, M_COPYALL, M_NOWAIT); -#endif - if (m0 == NULL) + *(char *)(mtag + 1) = 1; + m_tag_prepend(*m, mtag); + } else { + if (*(char *)(mtag + 1) > 3) { + m0 = *m; + *m = NULL; + goto bad; + } + (*(char *)(mtag + 1))++; + } + + if (r->rt == PF_DUPTO) { + 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; @@ -5207,22 +5346,17 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, &s->rt_addr, AF_INET6); ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL; } - if (ifp == NULL) goto bad; if (oifp != ifp) { - mtag = m_tag_find(m0, PACKET_TAG_PF_ROUTED, NULL); - if (mtag == NULL) { - mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 0, M_NOWAIT); - if (mtag == NULL) - goto bad; - m_tag_prepend(m0, mtag); - if (pf_test6(PF_OUT, ifp, &m0) != PF_PASS) - goto bad; - else if (m0 == NULL) - goto done; - } + 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)"); + ip6 = mtod(m0, struct ip6_hdr *); } /* @@ -5297,6 +5431,7 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, if (m->m_pkthdr.len < off + len) return (1); switch (af) { +#ifdef INET case AF_INET: if (p == IPPROTO_ICMP) { if (m->m_len < off) @@ -5312,6 +5447,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)) @@ -5366,7 +5502,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; @@ -5389,7 +5526,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0) #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)) { @@ -5400,7 +5537,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; } @@ -5423,6 +5560,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)) { @@ -5458,13 +5596,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; } @@ -5492,13 +5630,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; } @@ -5520,13 +5658,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_icmp(&r, &s, dir, kif, - m, off, h, &pd, &a, &ruleset); + m, off, h, &pd, &a, &ruleset, &ipintrq); break; } @@ -5535,13 +5673,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; } @@ -5573,7 +5711,7 @@ done: m_tag_prepend(m, mtag); } } -#endif +#endif /* ALTQ */ /* * connections redirected to loopback should not match sockets @@ -5648,12 +5786,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); } @@ -5671,7 +5809,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; @@ -5694,7 +5833,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0) #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)) { @@ -5705,7 +5844,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; } @@ -5719,6 +5858,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; @@ -5785,13 +5925,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; } @@ -5819,13 +5959,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; } @@ -5848,25 +5988,28 @@ 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_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; } @@ -5891,7 +6034,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 && @@ -5961,12 +6104,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); } @@ -5981,3 +6124,16 @@ done: return (action); } #endif /* INET6 */ + +int +pf_check_congestion(struct ifqueue *ifq) +{ +#ifdef __OpenBSD__ + if (ifq->ifq_congestion) + return (1); + else + return (0); +#else + return 0; +#endif +} diff --git a/sys/dist/pf/net/pf_if.c b/sys/dist/pf/net/pf_if.c index 0f69bc5d13cf..1a1fc7d90af4 100644 --- a/sys/dist/pf/net/pf_if.c +++ b/sys/dist/pf/net/pf_if.c @@ -1,5 +1,5 @@ -/* $NetBSD: pf_if.c,v 1.5 2004/07/26 13:46:43 yamt Exp $ */ -/* $OpenBSD: pf_if.c,v 1.11 2004/03/15 11:38:23 cedric Exp $ */ +/* $NetBSD: pf_if.c,v 1.6 2004/11/14 11:12:16 yamt Exp $ */ +/* $OpenBSD: pf_if.c,v 1.20 2004/08/15 15:31:46 henning Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -80,10 +80,6 @@ long pfi_update = 1; struct pfr_addr *pfi_buffer; int pfi_buffer_cnt; int pfi_buffer_max; -char pfi_reserved_anchor[PF_ANCHOR_NAME_SIZE] = - PF_RESERVED_ANCHOR; -char pfi_interface_ruleset[PF_RULESET_NAME_SIZE] = - PF_INTERFACE_RULESET; void pfi_dynaddr_update(void *); void pfi_kifaddr_update(void *); @@ -97,7 +93,6 @@ void pfi_address_add(struct sockaddr *, int, int); int pfi_if_compare(struct pfi_kif *, struct pfi_kif *); struct pfi_kif *pfi_if_create(const char *, struct pfi_kif *, int); void pfi_copy_group(char *, const char *, int); -void pfi_dynamic_drivers(void); void pfi_newgroup(const char *, int); int pfi_skip_if(const char *, struct pfi_kif *, int); int pfi_unmask(void *); @@ -106,7 +101,6 @@ void pfi_dohooks(struct pfi_kif *); RB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); -#define PFI_DYNAMIC_BUSES { "pcmcia", "cardbus", "uhub" } #define PFI_BUFFER_MAX 0x10000 #define PFI_MTYPE M_IFADDR @@ -133,7 +127,6 @@ pfi_initialize(void) pfi_buffer = malloc(pfi_buffer_max * sizeof(*pfi_buffer), PFI_MTYPE, M_WAITOK); pfi_self = pfi_if_create("self", NULL, PFI_IFLAG_GROUP); - pfi_dynamic_drivers(); } #ifdef _LKM @@ -271,7 +264,12 @@ pfi_lookup_create(const char *name) if (p == NULL) { pfi_copy_group(key.pfik_name, name, sizeof(key.pfik_name)); q = pfi_lookup_if(key.pfik_name); - if (q != NULL) + if (q == NULL) { + pfi_newgroup(key.pfik_name, PFI_IFLAG_DYNAMIC); + q = pfi_lookup_if(key.pfik_name); + } + p = pfi_lookup_if(name); + if (p == NULL && q != NULL) p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE); } splx(s); @@ -357,8 +355,7 @@ pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af) if (dyn->pfid_net != 128) snprintf(tblname + strlen(tblname), sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net); - ruleset = pf_find_or_create_ruleset(pfi_reserved_anchor, - pfi_interface_ruleset); + ruleset = pf_find_or_create_ruleset(PF_RESERVED_ANCHOR); if (ruleset == NULL) senderr(1); @@ -473,14 +470,14 @@ pfi_instance_add(struct ifnet *ifp, int net, int flags) } if (af == AF_INET) got4 = 1; - else + else if (af == AF_INET6) got6 = 1; net2 = net; if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) { if (af == AF_INET) { net2 = pfi_unmask(&((struct sockaddr_in *) ia->ifa_netmask)->sin_addr); - } else { + } else if (af == AF_INET6) { net2 = pfi_unmask(&((struct sockaddr_in6 *) ia->ifa_netmask)->sin6_addr); } @@ -639,7 +636,7 @@ pfi_if_create(const char *name, struct pfi_kif *q, int flags) RB_INIT(&p->pfik_ext_gwy); p->pfik_flags = flags; p->pfik_parent = q; - p->pfik_tzero = time.tv_sec; + p->pfik_tzero = time_second; RB_INSERT(pfi_ifhead, &pfi_ifs, p); if (q != NULL) { @@ -693,54 +690,6 @@ pfi_copy_group(char *p, const char *q, int m) *p++ = '\0'; } -void -pfi_dynamic_drivers(void) -{ -#ifdef __OpenBSD__ - char *buses[] = PFI_DYNAMIC_BUSES; - int nbuses = sizeof(buses)/sizeof(buses[0]); - int enabled[sizeof(buses)/sizeof(buses[0])]; - struct device *dev; - struct cfdata *cf; - struct cfdriver *drv; - short *p; - int i; - - bzero(enabled, sizeof(enabled)); - TAILQ_FOREACH(dev, &alldevs, dv_list) { - if (!(dev->dv_flags & DVF_ACTIVE)) - continue; - for (i = 0; i < nbuses; i++) - if (!enabled[i] && !strcmp(buses[i], - dev->dv_cfdata->cf_driver->cd_name)) - enabled[i] = 1; - } - for (cf = cfdata; cf->cf_driver; cf++) { - if (cf->cf_driver->cd_class != DV_IFNET) - continue; - for (p = cf->cf_parents; p && *p >= 0; p++) { - if ((drv = cfdata[*p].cf_driver) == NULL) - continue; - for (i = 0; i < nbuses; i++) - if (enabled[i] && - !strcmp(drv->cd_name, buses[i])) - break; - if (i < nbuses) { - pfi_newgroup(cf->cf_driver->cd_name, - PFI_IFLAG_DYNAMIC); - break; - } - } - } -#else - struct if_clone *ifc; - extern LIST_HEAD(if_cloners, if_clone) if_cloners; - - LIST_FOREACH(ifc, &if_cloners, ifc_list) - pfi_newgroup(ifc->ifc_name, PFI_IFLAG_DYNAMIC); -#endif -} - void pfi_newgroup(const char *name, int flags) { @@ -787,7 +736,7 @@ pfi_clr_istats(const char *name, int *nzero, int flags) { struct pfi_kif *p; int n = 0, s; - long tzero = time.tv_sec; + long tzero = time_second; s = splsoftnet(); ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE); @@ -818,7 +767,7 @@ pfi_get_ifaces(const char *name, struct pfi_if *buf, int *size, int flags) continue; if (*size > n++) { if (!p->pfik_tzero) - p->pfik_tzero = boottime.tv_sec; + p->pfik_tzero = time_second; if (copyout(p, buf++, sizeof(*buf))) { splx(s); return (EFAULT); @@ -893,7 +842,9 @@ pfi_dohooks(struct pfi_kif *p) int pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af) { - if (af == AF_INET) { + switch (af) { +#ifdef INET + case AF_INET: switch (dyn->pfid_acnt4) { case 0: return (0); @@ -903,7 +854,10 @@ pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af) default: return (pfr_match_addr(dyn->pfid_kt, a, AF_INET)); } - } else { + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: switch (dyn->pfid_acnt6) { case 0: return (0); @@ -913,6 +867,10 @@ pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af) default: return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6)); } + break; +#endif /* INET6 */ + default: + return (0); } } diff --git a/sys/dist/pf/net/pf_ioctl.c b/sys/dist/pf/net/pf_ioctl.c index acadd27959a5..1917ebd9f543 100644 --- a/sys/dist/pf/net/pf_ioctl.c +++ b/sys/dist/pf/net/pf_ioctl.c @@ -1,5 +1,5 @@ -/* $NetBSD: pf_ioctl.c,v 1.11 2004/11/13 21:13:07 yamt Exp $ */ -/* $OpenBSD: pf_ioctl.c,v 1.112 2004/03/22 04:54:18 mcbride Exp $ */ +/* $NetBSD: pf_ioctl.c,v 1.12 2004/11/14 11:12:16 yamt Exp $ */ +/* $OpenBSD: pf_ioctl.c,v 1.130 2004/09/09 22:08:42 dhartmei Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -103,10 +103,16 @@ void pfdetach(void); #endif int pfopen(dev_t, int, int, struct proc *); int pfclose(dev_t, int, int, struct proc *); -struct pf_pool *pf_get_pool(char *, char *, u_int32_t, - u_int8_t, u_int8_t, u_int8_t, u_int8_t, u_int8_t); +struct pf_pool *pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t, + u_int8_t, u_int8_t, u_int8_t); int pf_get_ruleset_number(u_int8_t); void pf_init_ruleset(struct pf_ruleset *); +int pf_anchor_setup(struct pf_rule *, + const struct pf_ruleset *, const char *); +int pf_anchor_copyout(const struct pf_ruleset *, + const struct pf_rule *, struct pfioc_rule *); +void pf_anchor_remove(struct pf_rule *); + void pf_mv_pool(struct pf_palist *, struct pf_palist *); void pf_empty_pool(struct pf_palist *); int pfioctl(dev_t, u_long, caddr_t, int, struct proc *); @@ -114,10 +120,12 @@ int pfioctl(dev_t, u_long, caddr_t, int, struct proc *); int pf_begin_altq(u_int32_t *); int pf_rollback_altq(u_int32_t); int pf_commit_altq(u_int32_t); +int pf_enable_altq(struct pf_altq *); +int pf_disable_altq(struct pf_altq *); #endif /* ALTQ */ -int pf_begin_rules(u_int32_t *, int, char *, char *); -int pf_rollback_rules(u_int32_t, int, char *, char *); -int pf_commit_rules(u_int32_t, int, char *, char *); +int pf_begin_rules(u_int32_t *, int, const char *); +int pf_rollback_rules(u_int32_t, int, char *); +int pf_commit_rules(u_int32_t, int, char *); #ifdef __NetBSD__ const struct cdevsw pf_cdevsw = { @@ -138,6 +146,9 @@ extern struct callout pf_expire_to; #endif struct pf_rule pf_default_rule; +#ifdef ALTQ +static int pf_altq_running; +#endif #define TAGID_MAX 50000 TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags), @@ -168,9 +179,9 @@ pfattach(int num) pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl", NULL); pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl", - NULL); + &pool_allocator_nointr); pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0, - "pfpooladdrpl", NULL); + "pfpooladdrpl", &pool_allocator_nointr); pfr_initialize(); pfi_initialize(); pf_osfp_initialize(); @@ -179,7 +190,7 @@ pfattach(int num) pf_pool_limits[PF_LIMIT_STATES].limit, NULL, 0); RB_INIT(&tree_src_tracking); - TAILQ_INIT(&pf_anchors); + RB_INIT(&pf_anchors); pf_init_ruleset(&pf_main_ruleset); TAILQ_INIT(&pf_altqs[0]); TAILQ_INIT(&pf_altqs[1]); @@ -211,6 +222,7 @@ pfattach(int num) timeout[PFTM_FRAG] = 30; /* Fragment expire */ timeout[PFTM_INTERVAL] = 10; /* Expire interval */ timeout[PFTM_SRC_NODE] = 0; /* Source tracking */ + timeout[PFTM_TS_DIFF] = 30; /* Allowed TS diff */ #ifdef __OpenBSD__ timeout_set(&pf_expire_to, pf_purge_timeout, &pf_expire_to); @@ -255,9 +267,11 @@ pfdetach(void) TAILQ_DRAIN(&pf_pabuf, pooladdr_e); TAILQ_DRAIN(&pf_altqs[1], altq_e); TAILQ_DRAIN(&pf_altqs[0], altq_e); - TAILQ_DRAIN(&pf_anchors, anchor_e); - - pf_remove_if_empty_ruleset(&pf_main_ruleset); + while ((anchor_e = RB_ROOT(&pf_anchors)) != NULL) { + RB_REMOVE(pf_anchor_global, &pf_anchors, anchor_e); + free(anchor_e, M_TEMP); + } + /* pf_remove_if_empty_ruleset(&pf_main_ruleset); */ pfr_destroy(); pool_destroy(&pf_pooladdr_pl); pool_destroy(&pf_altq_pl); @@ -284,15 +298,15 @@ pfclose(dev_t dev, int flags, int fmt, struct proc *p) } struct pf_pool * -pf_get_pool(char *anchorname, char *rulesetname, u_int32_t ticket, - u_int8_t rule_action, u_int8_t rule_number, u_int8_t r_last, - u_int8_t active, u_int8_t check_ticket) +pf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action, + u_int32_t rule_number, u_int8_t r_last, u_int8_t active, + u_int8_t check_ticket) { struct pf_ruleset *ruleset; struct pf_rule *rule; int rs_num; - ruleset = pf_find_ruleset(anchorname, rulesetname); + ruleset = pf_find_ruleset(anchor); if (ruleset == NULL) return (NULL); rs_num = pf_get_ruleset_number(rule_action); @@ -371,120 +385,248 @@ pf_init_ruleset(struct pf_ruleset *ruleset) } struct pf_anchor * -pf_find_anchor(const char *anchorname) +pf_find_anchor(const char *path) { - struct pf_anchor *anchor; - int n = -1; + static struct pf_anchor key; - anchor = TAILQ_FIRST(&pf_anchors); - while (anchor != NULL && (n = strcmp(anchor->name, anchorname)) < 0) - anchor = TAILQ_NEXT(anchor, entries); - if (n == 0) - return (anchor); - else - return (NULL); + memset(&key, 0, sizeof(key)); + strlcpy(key.path, path, sizeof(key.path)); + return (RB_FIND(pf_anchor_global, &pf_anchors, &key)); } struct pf_ruleset * -pf_find_ruleset(char *anchorname, char *rulesetname) +pf_find_ruleset(const char *path) { struct pf_anchor *anchor; - struct pf_ruleset *ruleset; - if (!anchorname[0] && !rulesetname[0]) + while (*path == '/') + path++; + if (!*path) return (&pf_main_ruleset); - if (!anchorname[0] || !rulesetname[0]) - return (NULL); - anchorname[PF_ANCHOR_NAME_SIZE-1] = 0; - rulesetname[PF_RULESET_NAME_SIZE-1] = 0; - anchor = pf_find_anchor(anchorname); + anchor = pf_find_anchor(path); if (anchor == NULL) return (NULL); - ruleset = TAILQ_FIRST(&anchor->rulesets); - while (ruleset != NULL && strcmp(ruleset->name, rulesetname) < 0) - ruleset = TAILQ_NEXT(ruleset, entries); - if (ruleset != NULL && !strcmp(ruleset->name, rulesetname)) - return (ruleset); else - return (NULL); + return (&anchor->ruleset); } struct pf_ruleset * -pf_find_or_create_ruleset(char anchorname[PF_ANCHOR_NAME_SIZE], - char rulesetname[PF_RULESET_NAME_SIZE]) +pf_find_or_create_ruleset(const char *path) { - struct pf_anchor *anchor, *a; - struct pf_ruleset *ruleset, *r; + static char p[MAXPATHLEN]; + char *q, *r; + struct pf_ruleset *ruleset; + struct pf_anchor *anchor = NULL /* XXX gcc */, + *dup, *parent = NULL; - if (!anchorname[0] && !rulesetname[0]) - return (&pf_main_ruleset); - if (!anchorname[0] || !rulesetname[0]) + while (*path == '/') + path++; + ruleset = pf_find_ruleset(path); + if (ruleset != NULL) + return (ruleset); + strlcpy(p, path, sizeof(p)); + while (parent == NULL && (q = strrchr(p, '/')) != NULL) { + *q = 0; + if ((ruleset = pf_find_ruleset(p)) != NULL) { + parent = ruleset->anchor; + break; + } + } + if (q == NULL) + q = p; + else + q++; + strlcpy(p, path, sizeof(p)); + if (!*q) return (NULL); - anchorname[PF_ANCHOR_NAME_SIZE-1] = 0; - rulesetname[PF_RULESET_NAME_SIZE-1] = 0; - a = TAILQ_FIRST(&pf_anchors); - while (a != NULL && strcmp(a->name, anchorname) < 0) - a = TAILQ_NEXT(a, entries); - if (a != NULL && !strcmp(a->name, anchorname)) - anchor = a; - else { - anchor = (struct pf_anchor *)malloc(sizeof(struct pf_anchor), - M_TEMP, M_NOWAIT); + while ((r = strchr(q, '/')) != NULL || *q) { + if (r != NULL) + *r = 0; + if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE || + (parent != NULL && strlen(parent->path) >= + MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)) + return (NULL); + anchor = (struct pf_anchor *)malloc(sizeof(*anchor), M_TEMP, + M_NOWAIT); if (anchor == NULL) return (NULL); - memset(anchor, 0, sizeof(struct pf_anchor)); - bcopy(anchorname, anchor->name, sizeof(anchor->name)); - TAILQ_INIT(&anchor->rulesets); - if (a != NULL) - TAILQ_INSERT_BEFORE(a, anchor, entries); - else - TAILQ_INSERT_TAIL(&pf_anchors, anchor, entries); - } - r = TAILQ_FIRST(&anchor->rulesets); - while (r != NULL && strcmp(r->name, rulesetname) < 0) - r = TAILQ_NEXT(r, entries); - if (r != NULL && !strcmp(r->name, rulesetname)) - return (r); - ruleset = (struct pf_ruleset *)malloc(sizeof(struct pf_ruleset), - M_TEMP, M_NOWAIT); - if (ruleset != NULL) { - pf_init_ruleset(ruleset); - bcopy(rulesetname, ruleset->name, sizeof(ruleset->name)); - ruleset->anchor = anchor; + memset(anchor, 0, sizeof(*anchor)); + RB_INIT(&anchor->children); + strlcpy(anchor->name, q, sizeof(anchor->name)); + if (parent != NULL) { + strlcpy(anchor->path, parent->path, + sizeof(anchor->path)); + strlcat(anchor->path, "/", sizeof(anchor->path)); + } + strlcat(anchor->path, anchor->name, sizeof(anchor->path)); + if ((dup = RB_INSERT(pf_anchor_global, &pf_anchors, anchor)) != + NULL) { + printf("pf_find_or_create_ruleset: RB_INSERT1 " + "'%s' '%s' collides with '%s' '%s'\n", + anchor->path, anchor->name, dup->path, dup->name); + free(anchor, M_TEMP); + return (NULL); + } + if (parent != NULL) { + anchor->parent = parent; + if ((dup = RB_INSERT(pf_anchor_node, &parent->children, + anchor)) != NULL) { + printf("pf_find_or_create_ruleset: " + "RB_INSERT2 '%s' '%s' collides with " + "'%s' '%s'\n", anchor->path, anchor->name, + dup->path, dup->name); + RB_REMOVE(pf_anchor_global, &pf_anchors, + anchor); + free(anchor, M_TEMP); + return (NULL); + } + } + pf_init_ruleset(&anchor->ruleset); + anchor->ruleset.anchor = anchor; + parent = anchor; if (r != NULL) - TAILQ_INSERT_BEFORE(r, ruleset, entries); + q = r + 1; else - TAILQ_INSERT_TAIL(&anchor->rulesets, ruleset, entries); + *q = 0; } - return (ruleset); + return (&anchor->ruleset); } void pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset) { - struct pf_anchor *anchor; + struct pf_anchor *parent; int i; - if (ruleset == NULL || ruleset->anchor == NULL || ruleset->tables > 0 || - ruleset->topen) - return; - for (i = 0; i < PF_RULESET_MAX; ++i) - if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) || - !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) || - ruleset->rules[i].inactive.open) + while (ruleset != NULL) { + if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL || + !RB_EMPTY(&ruleset->anchor->children) || + ruleset->anchor->refcnt > 0 || ruleset->tables > 0 || + ruleset->topen) return; - - anchor = ruleset->anchor; - TAILQ_REMOVE(&anchor->rulesets, ruleset, entries); - free(ruleset, M_TEMP); - - if (TAILQ_EMPTY(&anchor->rulesets)) { - TAILQ_REMOVE(&pf_anchors, anchor, entries); - free(anchor, M_TEMP); - pf_update_anchor_rules(); + for (i = 0; i < PF_RULESET_MAX; ++i) + if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) || + !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) || + ruleset->rules[i].inactive.open) + return; + RB_REMOVE(pf_anchor_global, &pf_anchors, ruleset->anchor); + if ((parent = ruleset->anchor->parent) != NULL) + RB_REMOVE(pf_anchor_node, &parent->children, + ruleset->anchor); + free(ruleset->anchor, M_TEMP); + if (parent == NULL) + return; + ruleset = &parent->ruleset; } } +int +pf_anchor_setup(struct pf_rule *r, const struct pf_ruleset *s, + const char *name) +{ + static char *p, path[MAXPATHLEN]; + struct pf_ruleset *ruleset; + + r->anchor = NULL; + r->anchor_relative = 0; + r->anchor_wildcard = 0; + if (!name[0]) + return (0); + if (name[0] == '/') + strlcpy(path, name + 1, sizeof(path)); + else { + /* relative path */ + r->anchor_relative = 1; + if (s->anchor == NULL || !s->anchor->path[0]) + path[0] = 0; + else + strlcpy(path, s->anchor->path, sizeof(path)); + while (name[0] == '.' && name[1] == '.' && name[2] == '/') { + if (!path[0]) { + printf("pf_anchor_setup: .. beyond root\n"); + return (1); + } + if ((p = strrchr(path, '/')) != NULL) + *p = 0; + else + path[0] = 0; + r->anchor_relative++; + name += 3; + } + if (path[0]) + strlcat(path, "/", sizeof(path)); + strlcat(path, name, sizeof(path)); + } + if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) { + r->anchor_wildcard = 1; + *p = 0; + } + ruleset = pf_find_or_create_ruleset(path); + if (ruleset == NULL || ruleset->anchor == NULL) { + printf("pf_anchor_setup: ruleset\n"); + return (1); + } + r->anchor = ruleset->anchor; + r->anchor->refcnt++; + return (0); +} + +int +pf_anchor_copyout(const struct pf_ruleset *rs, const struct pf_rule *r, + struct pfioc_rule *pr) +{ + pr->anchor_call[0] = 0; + if (r->anchor == NULL) + return (0); + if (!r->anchor_relative) { + strlcpy(pr->anchor_call, "/", sizeof(pr->anchor_call)); + strlcat(pr->anchor_call, r->anchor->path, + sizeof(pr->anchor_call)); + } else { + char a[MAXPATHLEN], b[MAXPATHLEN], *p; + int i; + + if (rs->anchor == NULL) + a[0] = 0; + else + strlcpy(a, rs->anchor->path, sizeof(a)); + strlcpy(b, r->anchor->path, sizeof(b)); + for (i = 1; i < r->anchor_relative; ++i) { + if ((p = strrchr(a, '/')) == NULL) + p = a; + *p = 0; + strlcat(pr->anchor_call, "../", + sizeof(pr->anchor_call)); + } + if (strncmp(a, b, strlen(a))) { + printf("pf_anchor_copyout: '%s' '%s'\n", a, b); + return (1); + } + if (strlen(b) > strlen(a)) + strlcat(pr->anchor_call, b + (a[0] ? strlen(a) + 1 : 0), + sizeof(pr->anchor_call)); + } + if (r->anchor_wildcard) + strlcat(pr->anchor_call, pr->anchor_call[0] ? "/*" : "*", + sizeof(pr->anchor_call)); + return (0); +} + +void +pf_anchor_remove(struct pf_rule *r) +{ + if (r->anchor == NULL) + return; + if (r->anchor->refcnt <= 0) { + printf("pf_anchor_remove: broken refcount"); + r->anchor = NULL; + return; + } + if (!--r->anchor->refcnt) + pf_remove_if_empty_ruleset(&r->anchor->ruleset); + r->anchor = NULL; +} + void pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb) { @@ -545,6 +687,7 @@ pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule) pf_tbladdr_remove(&rule->dst.addr); } pfi_detach_rule(rule->kif); + pf_anchor_remove(rule); pf_empty_pool(&rule->rpool.list); pool_put(&pf_rule_pl, rule); } @@ -730,7 +873,9 @@ pf_commit_altq(u_int32_t ticket) if (altq->qname[0] == 0) { /* attach the discipline */ error = altq_pfattach(altq); - if (error) { + if (error == 0 && pf_altq_running) + error = pf_enable_altq(altq); + if (error != 0) { splx(s); return (error); } @@ -742,6 +887,8 @@ pf_commit_altq(u_int32_t ticket) TAILQ_REMOVE(pf_altqs_inactive, altq, entries); if (altq->qname[0] == 0) { /* detach and destroy the discipline */ + if (pf_altq_running) + error = pf_disable_altq(altq); err = altq_pfdetach(altq); if (err != 0 && error == 0) error = err; @@ -757,17 +904,72 @@ pf_commit_altq(u_int32_t ticket) altqs_inactive_open = 0; return (error); } + +int +pf_enable_altq(struct pf_altq *altq) +{ + struct ifnet *ifp; + struct tb_profile tb; + int s, error = 0; + + if ((ifp = ifunit(altq->ifname)) == NULL) + return (EINVAL); + + if (ifp->if_snd.altq_type != ALTQT_NONE) + error = altq_enable(&ifp->if_snd); + + /* set tokenbucket regulator */ + if (error == 0 && ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) { + tb.rate = altq->ifbandwidth; + tb.depth = altq->tbrsize; + s = splimp(); + error = tbr_set(&ifp->if_snd, &tb); + splx(s); + } + + return (error); +} + +int +pf_disable_altq(struct pf_altq *altq) +{ + struct ifnet *ifp; + struct tb_profile tb; + int s, error; + + if ((ifp = ifunit(altq->ifname)) == NULL) + return (EINVAL); + + /* + * when the discipline is no longer referenced, it was overridden + * by a new one. if so, just return. + */ + if (altq->altq_disc != ifp->if_snd.altq_disc) + return (0); + + error = altq_disable(&ifp->if_snd); + + if (error == 0) { + /* clear tokenbucket regulator */ + tb.rate = 0; + s = splimp(); + error = tbr_set(&ifp->if_snd, &tb); + splx(s); + } + + return (error); +} #endif /* ALTQ */ int -pf_begin_rules(u_int32_t *ticket, int rs_num, char *anchor, char *ruleset) +pf_begin_rules(u_int32_t *ticket, int rs_num, const char *anchor) { struct pf_ruleset *rs; struct pf_rule *rule; if (rs_num < 0 || rs_num >= PF_RULESET_MAX) return (EINVAL); - rs = pf_find_or_create_ruleset(anchor, ruleset); + rs = pf_find_or_create_ruleset(anchor); if (rs == NULL) return (EINVAL); while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) @@ -778,14 +980,14 @@ pf_begin_rules(u_int32_t *ticket, int rs_num, char *anchor, char *ruleset) } int -pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor, char *ruleset) +pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor) { struct pf_ruleset *rs; struct pf_rule *rule; if (rs_num < 0 || rs_num >= PF_RULESET_MAX) return (EINVAL); - rs = pf_find_ruleset(anchor, ruleset); + rs = pf_find_ruleset(anchor); if (rs == NULL || !rs->rules[rs_num].inactive.open || rs->rules[rs_num].inactive.ticket != ticket) return (0); @@ -796,7 +998,7 @@ pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor, char *ruleset) } int -pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor, char *ruleset) +pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor) { struct pf_ruleset *rs; struct pf_rule *rule; @@ -805,7 +1007,7 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor, char *ruleset) if (rs_num < 0 || rs_num >= PF_RULESET_MAX) return (EINVAL); - rs = pf_find_ruleset(anchor, ruleset); + rs = pf_find_ruleset(anchor); if (rs == NULL || !rs->rules[rs_num].inactive.open || ticket != rs->rules[rs_num].inactive.ticket) return (EBUSY); @@ -825,7 +1027,6 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor, char *ruleset) pf_rm_rule(old_rules, rule); rs->rules[rs_num].inactive.open = 0; pf_remove_if_empty_ruleset(rs); - pf_update_anchor_rules(); splx(s); return (0); } @@ -858,8 +1059,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCGETALTQS: case DIOCGETALTQ: case DIOCGETQSTATS: - case DIOCGETANCHORS: - case DIOCGETANCHOR: case DIOCGETRULESETS: case DIOCGETRULESET: case DIOCRGETTABLES: @@ -905,8 +1104,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCGETALTQS: case DIOCGETALTQ: case DIOCGETQSTATS: - case DIOCGETANCHORS: - case DIOCGETANCHOR: case DIOCGETRULESETS: case DIOCGETRULESET: case DIOCRGETTABLES: @@ -947,9 +1144,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; #endif pf_status.running = 1; - pf_status.since = time.tv_sec; + pf_status.since = time_second; if (pf_status.stateid == 0) { - pf_status.stateid = time.tv_sec; + pf_status.stateid = time_second; pf_status.stateid = pf_status.stateid << 32; } DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n")); @@ -966,19 +1163,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; #endif pf_status.running = 0; - pf_status.since = time.tv_sec; + pf_status.since = time_second; DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n")); } break; - case DIOCBEGINRULES: { - struct pfioc_rule *pr = (struct pfioc_rule *)addr; - - error = pf_begin_rules(&pr->ticket, pf_get_ruleset_number( - pr->rule.action), pr->anchor, pr->ruleset); - break; - } - case DIOCADDRULE: { struct pfioc_rule *pr = (struct pfioc_rule *)addr; struct pf_ruleset *ruleset; @@ -986,7 +1175,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) struct pf_pooladdr *pa; int rs_num; - ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); + pr->anchor[sizeof(pr->anchor) - 1] = 0; + ruleset = pf_find_ruleset(pr->anchor); if (ruleset == NULL) { error = EINVAL; break; @@ -996,10 +1186,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; break; } - if (pr->rule.anchorname[0] && ruleset != &pf_main_ruleset) { - error = EINVAL; - break; - } if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) { error = EINVAL; break; @@ -1084,13 +1270,15 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; if (pf_tbladdr_setup(ruleset, &rule->dst.addr)) error = EINVAL; + if (pf_anchor_setup(rule, ruleset, pr->anchor_call)) + error = EINVAL; TAILQ_FOREACH(pa, &pf_pabuf, entries) if (pf_tbladdr_setup(ruleset, &pa->addr)) error = EINVAL; pf_mv_pool(&pf_pabuf, &rule->rpool.list); if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) || - (rule->action == PF_BINAT)) && !rule->anchorname[0]) || + (rule->action == PF_BINAT)) && rule->anchor == NULL) || (rule->rt > PF_FASTROUTE)) && (TAILQ_FIRST(&rule->rpool.list) == NULL)) error = EINVAL; @@ -1106,21 +1294,14 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } - case DIOCCOMMITRULES: { - struct pfioc_rule *pr = (struct pfioc_rule *)addr; - - error = pf_commit_rules(pr->ticket, pf_get_ruleset_number( - pr->rule.action), pr->anchor, pr->ruleset); - break; - } - case DIOCGETRULES: { struct pfioc_rule *pr = (struct pfioc_rule *)addr; struct pf_ruleset *ruleset; struct pf_rule *tail; int rs_num; - ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); + pr->anchor[sizeof(pr->anchor) - 1] = 0; + ruleset = pf_find_ruleset(pr->anchor); if (ruleset == NULL) { error = EINVAL; break; @@ -1148,7 +1329,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) struct pf_rule *rule; int rs_num, i; - ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); + pr->anchor[sizeof(pr->anchor) - 1] = 0; + ruleset = pf_find_ruleset(pr->anchor); if (ruleset == NULL) { error = EINVAL; break; @@ -1172,6 +1354,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } bcopy(rule, &pr->rule, sizeof(struct pf_rule)); + if (pf_anchor_copyout(ruleset, rule, pr)) { + error = EBUSY; + splx(s); + break; + } pfi_dynaddr_copyout(&pr->rule.src.addr); pfi_dynaddr_copyout(&pr->rule.dst.addr); pf_tbladdr_copyout(&pr->rule.src.addr); @@ -1205,7 +1392,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; break; } - ruleset = pf_find_ruleset(pcr->anchor, pcr->ruleset); + ruleset = pf_find_ruleset(pcr->anchor); if (ruleset == NULL) { error = EINVAL; break; @@ -1279,7 +1466,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } else newrule->pqid = newrule->qid; } -#endif +#endif /* ALTQ */ if (newrule->tagname[0]) if ((newrule->tag = pf_tagname2tag(newrule->tagname)) == 0) @@ -1299,13 +1486,15 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; if (pf_tbladdr_setup(ruleset, &newrule->dst.addr)) error = EINVAL; + if (pf_anchor_setup(newrule, ruleset, pcr->anchor_call)) + error = EINVAL; pf_mv_pool(&pf_pabuf, &newrule->rpool.list); if (((((newrule->action == PF_NAT) || (newrule->action == PF_RDR) || (newrule->action == PF_BINAT) || (newrule->rt > PF_FASTROUTE)) && - !newrule->anchorname[0])) && + !pcr->anchor[0])) && (TAILQ_FIRST(&newrule->rpool.list) == NULL)) error = EINVAL; @@ -1333,7 +1522,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) while ((oldrule != NULL) && (oldrule->nr != pcr->nr)) oldrule = TAILQ_NEXT(oldrule, entries); if (oldrule == NULL) { - pf_rm_rule(NULL, newrule); + if (newrule != NULL) + pf_rm_rule(NULL, newrule); error = EINVAL; splx(s); break; @@ -1361,11 +1551,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) ruleset->rules[rs_num].active.ptr, entries) oldrule->nr = nr++; + ruleset->rules[rs_num].active.ticket++; + pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr); pf_remove_if_empty_ruleset(ruleset); - pf_update_anchor_rules(); - ruleset->rules[rs_num].active.ticket++; splx(s); break; } @@ -1407,11 +1597,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if ((!psk->psk_af || state->af == psk->psk_af) && (!psk->psk_proto || psk->psk_proto == state->proto) && - PF_MATCHA(psk->psk_src.not, + PF_MATCHA(psk->psk_src.neg, &psk->psk_src.addr.v.a.addr, &psk->psk_src.addr.v.a.mask, &state->lan.addr, state->af) && - PF_MATCHA(psk->psk_dst.not, + PF_MATCHA(psk->psk_dst.neg, &psk->psk_dst.addr.v.a.addr, &psk->psk_dst.addr.v.a.mask, &state->ext.addr, state->af) && @@ -1464,7 +1654,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) state->nat_rule.ptr = NULL; state->anchor.ptr = NULL; state->rt_kif = NULL; - state->creation = time.tv_sec; + state->creation = time_second; state->pfsync_time = 0; state->packets[0] = state->packets[1] = 0; state->bytes[0] = state->bytes[1] = 0; @@ -1503,8 +1693,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) -1 : state->anchor.ptr->nr; splx(s); ps->state.expire = pf_state_expires(state); - if (ps->state.expire > time.tv_sec) - ps->state.expire -= time.tv_sec; + if (ps->state.expire > time_second) + ps->state.expire -= time_second; else ps->state.expire = 0; break; @@ -1532,7 +1722,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) RB_FOREACH(state, pf_state_tree_ext_gwy, &kif->pfik_ext_gwy) { - int secs = time.tv_sec; + int secs = time_second; if ((nr+1) * sizeof(*p) > (unsigned)ps->ps_len) break; @@ -1742,31 +1932,18 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) #ifdef ALTQ case DIOCSTARTALTQ: { struct pf_altq *altq; - struct ifnet *ifp; - struct tb_profile tb; /* enable all altq interfaces on active list */ s = splsoftnet(); TAILQ_FOREACH(altq, pf_altqs_active, entries) { if (altq->qname[0] == 0) { - if ((ifp = ifunit(altq->ifname)) == NULL) { - error = EINVAL; - break; - } - if (ifp->if_snd.altq_type != ALTQT_NONE) - error = altq_enable(&ifp->if_snd); - if (error != 0) - break; - /* set tokenbucket regulator */ - tb.rate = altq->ifbandwidth; - tb.depth = altq->tbrsize; - error = tbr_set(&ifp->if_snd, &tb); + error = pf_enable_altq(altq); if (error != 0) break; } } if (error == 0) - pfaltq_running = 1; + pf_altq_running = 1; splx(s); DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n")); break; @@ -1774,44 +1951,23 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCSTOPALTQ: { struct pf_altq *altq; - struct ifnet *ifp; - struct tb_profile tb; - int err; /* disable all altq interfaces on active list */ s = splsoftnet(); TAILQ_FOREACH(altq, pf_altqs_active, entries) { if (altq->qname[0] == 0) { - if ((ifp = ifunit(altq->ifname)) == NULL) { - error = EINVAL; + error = pf_disable_altq(altq); + if (error != 0) break; - } - if (ifp->if_snd.altq_type != ALTQT_NONE) { - err = altq_disable(&ifp->if_snd); - if (err != 0 && error == 0) - error = err; - } - /* clear tokenbucket regulator */ - tb.rate = 0; - err = tbr_set(&ifp->if_snd, &tb); - if (err != 0 && error == 0) - error = err; } } if (error == 0) - pfaltq_running = 0; + pf_altq_running = 0; splx(s); DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n")); break; } - case DIOCBEGINALTQS: { - u_int32_t *ticket = (u_int32_t *)addr; - - error = pf_begin_altq(ticket); - break; - } - case DIOCADDALTQ: { struct pfioc_altq *pa = (struct pfioc_altq *)addr; struct pf_altq *altq, *a; @@ -1857,13 +2013,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } - case DIOCCOMMITALTQS: { - u_int32_t ticket = *(u_int32_t *)addr; - - error = pf_commit_altq(ticket); - break; - } - case DIOCGETALTQS: { struct pfioc_altq *pa = (struct pfioc_altq *)addr; struct pf_altq *altq; @@ -2000,8 +2149,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) pp->nr = 0; s = splsoftnet(); - pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket, - pp->r_action, pp->r_num, 0, 1, 0); + pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action, + pp->r_num, 0, 1, 0); if (pool == NULL) { error = EBUSY; splx(s); @@ -2018,8 +2167,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) u_int32_t nr = 0; s = splsoftnet(); - pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket, - pp->r_action, pp->r_num, 0, 1, 1); + pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action, + pp->r_num, 0, 1, 1); if (pool == NULL) { error = EBUSY; splx(s); @@ -2059,13 +2208,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } - ruleset = pf_find_ruleset(pca->anchor, pca->ruleset); + ruleset = pf_find_ruleset(pca->anchor); if (ruleset == NULL) { error = EBUSY; break; } - pool = pf_get_pool(pca->anchor, pca->ruleset, pca->ticket, - pca->r_action, pca->r_num, pca->r_last, 1, 1); + pool = pf_get_pool(pca->anchor, pca->ticket, pca->r_action, + pca->r_num, pca->r_last, 1, 1); if (pool == NULL) { error = EBUSY; break; @@ -2155,68 +2304,61 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } - case DIOCGETANCHORS: { - struct pfioc_anchor *pa = (struct pfioc_anchor *)addr; - struct pf_anchor *anchor; - - pa->nr = 0; - TAILQ_FOREACH(anchor, &pf_anchors, entries) - pa->nr++; - break; - } - - case DIOCGETANCHOR: { - struct pfioc_anchor *pa = (struct pfioc_anchor *)addr; - struct pf_anchor *anchor; - u_int32_t nr = 0; - - anchor = TAILQ_FIRST(&pf_anchors); - while (anchor != NULL && nr < pa->nr) { - anchor = TAILQ_NEXT(anchor, entries); - nr++; - } - if (anchor == NULL) - error = EBUSY; - else - bcopy(anchor->name, pa->name, sizeof(pa->name)); - break; - } - case DIOCGETRULESETS: { struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; - struct pf_anchor *anchor; struct pf_ruleset *ruleset; + struct pf_anchor *anchor; - pr->anchor[PF_ANCHOR_NAME_SIZE-1] = 0; - if ((anchor = pf_find_anchor(pr->anchor)) == NULL) { + pr->path[sizeof(pr->path) - 1] = 0; + if ((ruleset = pf_find_ruleset(pr->path)) == NULL) { error = EINVAL; break; } pr->nr = 0; - TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) - pr->nr++; + if (ruleset->anchor == NULL) { + /* XXX kludge for pf_main_ruleset */ + RB_FOREACH(anchor, pf_anchor_global, &pf_anchors) + if (anchor->parent == NULL) + pr->nr++; + } else { + RB_FOREACH(anchor, pf_anchor_node, + &ruleset->anchor->children) + pr->nr++; + } break; } case DIOCGETRULESET: { struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; - struct pf_anchor *anchor; struct pf_ruleset *ruleset; + struct pf_anchor *anchor; u_int32_t nr = 0; - if ((anchor = pf_find_anchor(pr->anchor)) == NULL) { + pr->path[sizeof(pr->path) - 1] = 0; + if ((ruleset = pf_find_ruleset(pr->path)) == NULL) { error = EINVAL; break; } - ruleset = TAILQ_FIRST(&anchor->rulesets); - while (ruleset != NULL && nr < pr->nr) { - ruleset = TAILQ_NEXT(ruleset, entries); - nr++; + pr->name[0] = 0; + if (ruleset->anchor == NULL) { + /* XXX kludge for pf_main_ruleset */ + RB_FOREACH(anchor, pf_anchor_global, &pf_anchors) + if (anchor->parent == NULL && nr++ == pr->nr) { + strlcpy(pr->name, anchor->name, + sizeof(pr->name)); + break; + } + } else { + RB_FOREACH(anchor, pf_anchor_node, + &ruleset->anchor->children) + if (nr++ == pr->nr) { + strlcpy(pr->name, anchor->name, + sizeof(pr->name)); + break; + } } - if (ruleset == NULL) + if (!pr->name[0]) error = EBUSY; - else - bcopy(ruleset->name, pr->name, sizeof(pr->name)); break; } @@ -2407,31 +2549,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } - case DIOCRINABEGIN: { - struct pfioc_table *io = (struct pfioc_table *)addr; - - if (io->pfrio_esize != 0) { - error = ENODEV; - break; - } - error = pfr_ina_begin(&io->pfrio_table, &io->pfrio_ticket, - &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL); - break; - } - - case DIOCRINACOMMIT: { - struct pfioc_table *io = (struct pfioc_table *)addr; - - if (io->pfrio_esize != 0) { - error = ENODEV; - break; - } - error = pfr_ina_commit(&io->pfrio_table, io->pfrio_ticket, - &io->pfrio_nadd, &io->pfrio_nchange, io->pfrio_flags | - PFR_FLAG_USERIOCTL); - break; - } - case DIOCRINADEFINE: { struct pfioc_table *io = (struct pfioc_table *)addr; @@ -2462,10 +2579,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } case DIOCXBEGIN: { - struct pfioc_trans *io = (struct pfioc_trans *)addr; - struct pfioc_trans_e ioe; - struct pfr_table table; - int i; + struct pfioc_trans *io = (struct pfioc_trans *) + addr; + static struct pfioc_trans_e ioe; + static struct pfr_table table; + int i; if (io->esize != sizeof(ioe)) { error = ENODEV; @@ -2479,7 +2597,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) switch (ioe.rs_num) { #ifdef ALTQ case PF_RULESET_ALTQ: - if (ioe.anchor[0] || ioe.ruleset[0]) { + if (ioe.anchor[0]) { error = EINVAL; goto fail; } @@ -2491,15 +2609,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) bzero(&table, sizeof(table)); strlcpy(table.pfrt_anchor, ioe.anchor, sizeof(table.pfrt_anchor)); - strlcpy(table.pfrt_ruleset, ioe.ruleset, - sizeof(table.pfrt_ruleset)); if ((error = pfr_ina_begin(&table, &ioe.ticket, NULL, 0))) goto fail; break; default: if ((error = pf_begin_rules(&ioe.ticket, - ioe.rs_num, ioe.anchor, ioe.ruleset))) + ioe.rs_num, ioe.anchor))) goto fail; break; } @@ -2512,10 +2628,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } case DIOCXROLLBACK: { - struct pfioc_trans *io = (struct pfioc_trans *)addr; - struct pfioc_trans_e ioe; - struct pfr_table table; - int i; + struct pfioc_trans *io = (struct pfioc_trans *) + addr; + static struct pfioc_trans_e ioe; + static struct pfr_table table; + int i; if (io->esize != sizeof(ioe)) { error = ENODEV; @@ -2529,7 +2646,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) switch (ioe.rs_num) { #ifdef ALTQ case PF_RULESET_ALTQ: - if (ioe.anchor[0] || ioe.ruleset[0]) { + if (ioe.anchor[0]) { error = EINVAL; goto fail; } @@ -2541,15 +2658,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) bzero(&table, sizeof(table)); strlcpy(table.pfrt_anchor, ioe.anchor, sizeof(table.pfrt_anchor)); - strlcpy(table.pfrt_ruleset, ioe.ruleset, - sizeof(table.pfrt_ruleset)); if ((error = pfr_ina_rollback(&table, ioe.ticket, NULL, 0))) goto fail; /* really bad */ break; default: if ((error = pf_rollback_rules(ioe.ticket, - ioe.rs_num, ioe.anchor, ioe.ruleset))) + ioe.rs_num, ioe.anchor))) goto fail; /* really bad */ break; } @@ -2558,11 +2673,12 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } case DIOCXCOMMIT: { - struct pfioc_trans *io = (struct pfioc_trans *)addr; - struct pfioc_trans_e ioe; - struct pfr_table table; - struct pf_ruleset *rs; - int i; + struct pfioc_trans *io = (struct pfioc_trans *) + addr; + static struct pfioc_trans_e ioe; + static struct pfr_table table; + struct pf_ruleset *rs; + int i; if (io->esize != sizeof(ioe)) { error = ENODEV; @@ -2577,7 +2693,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) switch (ioe.rs_num) { #ifdef ALTQ case PF_RULESET_ALTQ: - if (ioe.anchor[0] || ioe.ruleset[0]) { + if (ioe.anchor[0]) { error = EINVAL; goto fail; } @@ -2589,7 +2705,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; #endif /* ALTQ */ case PF_RULESET_TABLE: - rs = pf_find_ruleset(ioe.anchor, ioe.ruleset); + rs = pf_find_ruleset(ioe.anchor); if (rs == NULL || !rs->topen || ioe.ticket != rs->tticket) { error = EBUSY; @@ -2602,7 +2718,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; goto fail; } - rs = pf_find_ruleset(ioe.anchor, ioe.ruleset); + rs = pf_find_ruleset(ioe.anchor); if (rs == NULL || !rs->rules[ioe.rs_num].inactive.open || rs->rules[ioe.rs_num].inactive.ticket != @@ -2630,15 +2746,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) bzero(&table, sizeof(table)); strlcpy(table.pfrt_anchor, ioe.anchor, sizeof(table.pfrt_anchor)); - strlcpy(table.pfrt_ruleset, ioe.ruleset, - sizeof(table.pfrt_ruleset)); if ((error = pfr_ina_commit(&table, ioe.ticket, NULL, NULL, 0))) goto fail; /* really bad */ break; default: if ((error = pf_commit_rules(ioe.ticket, - ioe.rs_num, ioe.anchor, ioe.ruleset))) + ioe.rs_num, ioe.anchor))) goto fail; /* really bad */ break; } @@ -2665,7 +2779,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) s = splsoftnet(); p = psn->psn_src_nodes; RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { - int secs = time.tv_sec; + int secs = time_second; if ((nr + 1) * sizeof(*p) > (unsigned)psn->psn_len) break; @@ -2788,7 +2902,8 @@ pfil4_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) } } - if (pf_test(dir == PFIL_OUT ? PF_OUT : PF_IN, ifp, mp) != PF_PASS) { + if (pf_test(dir == PFIL_OUT ? PF_OUT : PF_IN, ifp, mp, NULL) + != PF_PASS) { m_freem(*mp); *mp = NULL; return EHOSTUNREACH; @@ -2814,7 +2929,8 @@ pfil6_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) return error; } - if (pf_test6(dir == PFIL_OUT ? PF_OUT : PF_IN, ifp, mp) != PF_PASS) { + if (pf_test6(dir == PFIL_OUT ? PF_OUT : PF_IN, ifp, mp, NULL) + != PF_PASS) { m_freem(*mp); *mp = NULL; return EHOSTUNREACH; diff --git a/sys/dist/pf/net/pf_norm.c b/sys/dist/pf/net/pf_norm.c index 04b1ff9cd020..4a5bf75bb82e 100644 --- a/sys/dist/pf/net/pf_norm.c +++ b/sys/dist/pf/net/pf_norm.c @@ -1,5 +1,5 @@ -/* $NetBSD: pf_norm.c,v 1.5 2004/11/13 21:13:07 yamt Exp $ */ -/* $OpenBSD: pf_norm.c,v 1.80 2004/03/09 21:44:41 mcbride Exp $ */ +/* $NetBSD: pf_norm.c,v 1.6 2004/11/14 11:12:16 yamt Exp $ */ +/* $OpenBSD: pf_norm.c,v 1.96 2004/07/17 00:17:27 frantzen Exp $ */ /* * Copyright 2001 Niels Provos @@ -123,12 +123,15 @@ struct mbuf *pf_reassemble(struct mbuf **, struct pf_fragment **, struct pf_frent *, int); struct mbuf *pf_fragcache(struct mbuf **, struct ip*, struct pf_fragment **, int, int, int *); -u_int16_t pf_cksum_fixup(u_int16_t, u_int16_t, u_int16_t); int pf_normalize_tcpopt(struct pf_rule *, struct mbuf *, struct tcphdr *, int); -#define DPFPRINTF(x) if (pf_status.debug >= PF_DEBUG_MISC) \ - { printf("%s: ", __func__); printf x ;} +#define DPFPRINTF(x) do { \ + if (pf_status.debug >= PF_DEBUG_MISC) { \ + printf("%s: ", __func__); \ + printf x ; \ + } \ +} while(0) /* Globals */ struct pool pf_frent_pl, pf_frag_pl, pf_cache_pl, pf_cent_pl; @@ -205,7 +208,7 @@ void pf_purge_expired_fragments(void) { struct pf_fragment *frag; - u_int32_t expire = time.tv_sec - + u_int32_t expire = time_second - pf_default_rule.timeout[PFTM_FRAG]; while ((frag = TAILQ_LAST(&pf_fragqueue, pf_fragqueue)) != NULL) { @@ -316,7 +319,7 @@ pf_find_fragment(struct ip *ip, struct pf_frag_tree *tree) frag = RB_FIND(pf_frag_tree, tree, &key); if (frag != NULL) { /* XXX Are we sure we want to update the timeout? */ - frag->fr_timeout = time.tv_sec; + frag->fr_timeout = time_second; if (BUFFER_FRAGMENTS(frag)) { TAILQ_REMOVE(&pf_fragqueue, frag, frag_next); TAILQ_INSERT_HEAD(&pf_fragqueue, frag, frag_next); @@ -381,7 +384,7 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag, (*frag)->fr_dst = frent->fr_ip->ip_dst; (*frag)->fr_p = frent->fr_ip->ip_p; (*frag)->fr_id = frent->fr_ip->ip_id; - (*frag)->fr_timeout = time.tv_sec; + (*frag)->fr_timeout = time_second; LIST_INIT(&(*frag)->fr_queue); RB_INSERT(pf_frag_tree, &pf_frag_tree, *frag); @@ -583,7 +586,7 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff, (*frag)->fr_dst = h->ip_dst; (*frag)->fr_p = h->ip_p; (*frag)->fr_id = h->ip_id; - (*frag)->fr_timeout = time.tv_sec; + (*frag)->fr_timeout = time_second; cur->fr_off = off; cur->fr_end = max; @@ -846,7 +849,8 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff, } int -pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason) +pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason, + struct pf_pdesc *pd) { struct mbuf *m = *m0; struct pf_rule *r; @@ -873,10 +877,10 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason) else if (r->proto && r->proto != h->ip_p) r = r->skip[PF_SKIP_PROTO].ptr; else if (PF_MISMATCHAW(&r->src.addr, - (struct pf_addr *)&h->ip_src.s_addr, AF_INET, r->src.not)) + (struct pf_addr *)&h->ip_src.s_addr, AF_INET, r->src.neg)) r = r->skip[PF_SKIP_SRC_ADDR].ptr; else if (PF_MISMATCHAW(&r->dst.addr, - (struct pf_addr *)&h->ip_dst.s_addr, AF_INET, r->dst.not)) + (struct pf_addr *)&h->ip_dst.s_addr, AF_INET, r->dst.neg)) r = r->skip[PF_SKIP_DST_ADDR].ptr; else break; @@ -1012,8 +1016,14 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason) if (r->min_ttl && h->ip_ttl < r->min_ttl) h->ip_ttl = r->min_ttl; - if (r->rule_flag & PFRULE_RANDOMID) + if (r->rule_flag & PFRULE_RANDOMID) { + u_int16_t ip_id = h->ip_id; + h->ip_id = ip_randomid(); + h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_id, h->ip_id, 0); + } + if ((r->rule_flag & (PFRULE_FRAGCROP|PFRULE_FRAGDROP)) == 0) + pd->flags |= PFDESC_IP_REAS; return (PF_PASS); @@ -1021,7 +1031,8 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason) /* Enforce a minimum ttl, may cause endless packet loops */ if (r->min_ttl && h->ip_ttl < r->min_ttl) h->ip_ttl = r->min_ttl; - + if ((r->rule_flag & (PFRULE_FRAGCROP|PFRULE_FRAGDROP)) == 0) + pd->flags |= PFDESC_IP_REAS; return (PF_PASS); no_mem: @@ -1053,7 +1064,7 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason) #ifdef INET6 int pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif, - u_short *reason) + u_short *reason, struct pf_pdesc *pd) { struct mbuf *m = *m0; struct pf_rule *r; @@ -1085,10 +1096,10 @@ pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif, r = r->skip[PF_SKIP_PROTO].ptr; #endif else if (PF_MISMATCHAW(&r->src.addr, - (struct pf_addr *)&h->ip6_src, AF_INET6, r->src.not)) + (struct pf_addr *)&h->ip6_src, AF_INET6, r->src.neg)) r = r->skip[PF_SKIP_SRC_ADDR].ptr; else if (PF_MISMATCHAW(&r->dst.addr, - (struct pf_addr *)&h->ip6_dst, AF_INET6, r->dst.not)) + (struct pf_addr *)&h->ip6_dst, AF_INET6, r->dst.neg)) r = r->skip[PF_SKIP_DST_ADDR].ptr; else break; @@ -1203,6 +1214,7 @@ pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif, goto badfrag; /* do something about it */ + /* remember to set pd->flags |= PFDESC_IP_REAS */ return (PF_PASS); shortpkt: @@ -1223,7 +1235,7 @@ pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif, PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL); return (PF_DROP); } -#endif +#endif /* INET6 */ int pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff, @@ -1248,12 +1260,12 @@ pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff, r = r->skip[PF_SKIP_AF].ptr; else if (r->proto && r->proto != pd->proto) r = r->skip[PF_SKIP_PROTO].ptr; - else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.not)) + else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg)) r = r->skip[PF_SKIP_SRC_ADDR].ptr; else if (r->src.port_op && !pf_match_port(r->src.port_op, r->src.port[0], r->src.port[1], th->th_sport)) r = r->skip[PF_SKIP_SRC_PORT].ptr; - else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.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->dst.port_op && !pf_match_port(r->dst.port_op, r->dst.port[0], r->dst.port[1], th->th_dport)) @@ -1309,13 +1321,13 @@ pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff, th->th_x2 = 0; nv = *(u_int16_t *)(&th->th_ack + 1); - th->th_sum = pf_cksum_fixup(th->th_sum, ov, nv); + th->th_sum = pf_cksum_fixup(th->th_sum, ov, nv, 0); rewrite = 1; } /* Remove urgent pointer, if TH_URG is not set */ if (!(flags & TH_URG) && th->th_urp) { - th->th_sum = pf_cksum_fixup(th->th_sum, th->th_urp, 0); + th->th_sum = pf_cksum_fixup(th->th_sum, th->th_urp, 0, 0); th->th_urp = 0; rewrite = 1; } @@ -1341,6 +1353,7 @@ int pf_normalize_tcp_init(struct mbuf *m, int off, struct pf_pdesc *pd, struct tcphdr *th, struct pf_state_peer *src, struct pf_state_peer *dst) { + u_int32_t tsval, tsecr; u_int8_t hdr[60]; u_int8_t *opt; @@ -1394,12 +1407,23 @@ pf_normalize_tcp_init(struct mbuf *m, int off, struct pf_pdesc *pd, if (opt[1] >= TCPOLEN_TIMESTAMP) { src->scrub->pfss_flags |= PFSS_TIMESTAMP; - src->scrub->pfss_ts_mod = arc4random(); + src->scrub->pfss_ts_mod = + htonl(arc4random()); + + /* note PFSS_PAWS not set yet */ + memcpy(&tsval, &opt[2], + sizeof(u_int32_t)); + memcpy(&tsecr, &opt[6], + sizeof(u_int32_t)); + src->scrub->pfss_tsval0 = ntohl(tsval); + src->scrub->pfss_tsval = ntohl(tsval); + src->scrub->pfss_tsecr = ntohl(tsecr); + getmicrouptime(&src->scrub->pfss_last); } /* FALLTHROUGH */ default: - hlen -= opt[1]; - opt += opt[1]; + hlen -= MAX(opt[1], 2); + opt += MAX(opt[1], 2); break; } } @@ -1421,12 +1445,16 @@ pf_normalize_tcp_cleanup(struct pf_state *state) int pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, - u_short *reason, struct tcphdr *th, struct pf_state_peer *src, - struct pf_state_peer *dst, int *writeback) + u_short *reason, struct tcphdr *th, struct pf_state *state, + struct pf_state_peer *src, struct pf_state_peer *dst, int *writeback) { + struct timeval uptime; + u_int32_t tsval, tsecr; + u_int tsval_from_last; u_int8_t hdr[60]; u_int8_t *opt; int copyback = 0; + int got_ts = 0; KASSERT(src->scrub || dst->scrub); @@ -1480,37 +1508,51 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, * NAT detection, OS uptime determination or * reboot detection. */ + + if (got_ts) { + /* Huh? Multiple timestamps!? */ + if (pf_status.debug >= PF_DEBUG_MISC) { + DPFPRINTF(("multiple TS??")); + pf_print_state(state); + printf("\n"); + } + REASON_SET(reason, PFRES_TS); + return (PF_DROP); + } if (opt[1] >= TCPOLEN_TIMESTAMP) { - u_int32_t ts_value; - if (src->scrub && + memcpy(&tsval, &opt[2], + sizeof(u_int32_t)); + if (tsval && src->scrub && (src->scrub->pfss_flags & PFSS_TIMESTAMP)) { - memcpy(&ts_value, &opt[2], - sizeof(u_int32_t)); - ts_value = htonl(ntohl(ts_value) - + src->scrub->pfss_ts_mod); + tsval = ntohl(tsval); pf_change_a(&opt[2], - &th->th_sum, ts_value, 0); + &th->th_sum, + htonl(tsval + + src->scrub->pfss_ts_mod), + 0); copyback = 1; } /* Modulate TS reply iff valid (!0) */ - memcpy(&ts_value, &opt[6], + memcpy(&tsecr, &opt[6], sizeof(u_int32_t)); - if (ts_value && dst->scrub && + if (tsecr && dst->scrub && (dst->scrub->pfss_flags & PFSS_TIMESTAMP)) { - ts_value = htonl(ntohl(ts_value) - - dst->scrub->pfss_ts_mod); + tsecr = ntohl(tsecr) + - dst->scrub->pfss_ts_mod; pf_change_a(&opt[6], - &th->th_sum, ts_value, 0); + &th->th_sum, htonl(tsecr), + 0); copyback = 1; } + got_ts = 1; } /* FALLTHROUGH */ default: - hlen -= opt[1]; - opt += opt[1]; + hlen -= MAX(opt[1], 2); + opt += MAX(opt[1], 2); break; } } @@ -1524,9 +1566,276 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, } + /* + * Must invalidate PAWS checks on connections idle for too long. + * The fastest allowed timestamp clock is 1ms. That turns out to + * be about 24 days before it wraps. XXX Right now our lowerbound + * TS echo check only works for the first 12 days of a connection + * when the TS has exhausted half its 32bit space + */ +#define TS_MAX_IDLE (24*24*60*60) +#define TS_MAX_CONN (12*24*60*60) /* XXX remove when better tsecr check */ + + getmicrouptime(&uptime); + if (src->scrub && (src->scrub->pfss_flags & PFSS_PAWS) && + (uptime.tv_sec - src->scrub->pfss_last.tv_sec > TS_MAX_IDLE || + time_second - state->creation > TS_MAX_CONN)) { + if (pf_status.debug >= PF_DEBUG_MISC) { + DPFPRINTF(("src idled out of PAWS\n")); + pf_print_state(state); + printf("\n"); + } + src->scrub->pfss_flags = (src->scrub->pfss_flags & ~PFSS_PAWS) + | PFSS_PAWS_IDLED; + } + if (dst->scrub && (dst->scrub->pfss_flags & PFSS_PAWS) && + uptime.tv_sec - dst->scrub->pfss_last.tv_sec > TS_MAX_IDLE) { + if (pf_status.debug >= PF_DEBUG_MISC) { + DPFPRINTF(("dst idled out of PAWS\n")); + pf_print_state(state); + printf("\n"); + } + dst->scrub->pfss_flags = (dst->scrub->pfss_flags & ~PFSS_PAWS) + | PFSS_PAWS_IDLED; + } + + if (got_ts && src->scrub && dst->scrub && + (src->scrub->pfss_flags & PFSS_PAWS) && + (dst->scrub->pfss_flags & PFSS_PAWS)) { + /* Validate that the timestamps are "in-window". + * RFC1323 describes TCP Timestamp options that allow + * measurement of RTT (round trip time) and PAWS + * (protection against wrapped sequence numbers). PAWS + * gives us a set of rules for rejecting packets on + * long fat pipes (packets that were somehow delayed + * in transit longer than the time it took to send the + * full TCP sequence space of 4Gb). We can use these + * rules and infer a few others that will let us treat + * the 32bit timestamp and the 32bit echoed timestamp + * as sequence numbers to prevent a blind attacker from + * inserting packets into a connection. + * + * RFC1323 tells us: + * - The timestamp on this packet must be greater than + * or equal to the last value echoed by the other + * endpoint. The RFC says those will be discarded + * since it is a dup that has already been acked. + * This gives us a lowerbound on the timestamp. + * timestamp >= other last echoed timestamp + * - The timestamp will be less than or equal to + * the last timestamp plus the time between the + * last packet and now. The RFC defines the max + * clock rate as 1ms. We will allow clocks to be + * up to 10% fast and will allow a total difference + * or 30 seconds due to a route change. And this + * gives us an upperbound on the timestamp. + * timestamp <= last timestamp + max ticks + * We have to be careful here. Windows will send an + * initial timestamp of zero and then initialize it + * to a random value after the 3whs; presumably to + * avoid a DoS by having to call an expensive RNG + * during a SYN flood. Proof MS has at least one + * good security geek. + * + * - The TCP timestamp option must also echo the other + * endpoints timestamp. The timestamp echoed is the + * one carried on the earliest unacknowledged segment + * on the left edge of the sequence window. The RFC + * states that the host will reject any echoed + * timestamps that were larger than any ever sent. + * This gives us an upperbound on the TS echo. + * tescr <= largest_tsval + * - The lowerbound on the TS echo is a little more + * tricky to determine. The other endpoint's echoed + * values will not decrease. But there may be + * network conditions that re-order packets and + * cause our view of them to decrease. For now the + * only lowerbound we can safely determine is that + * the TS echo will never be less than the orginal + * TS. XXX There is probably a better lowerbound. + * Remove TS_MAX_CONN with better lowerbound check. + * tescr >= other original TS + * + * It is also important to note that the fastest + * timestamp clock of 1ms will wrap its 32bit space in + * 24 days. So we just disable TS checking after 24 + * days of idle time. We actually must use a 12d + * connection limit until we can come up with a better + * lowerbound to the TS echo check. + */ + struct timeval delta_ts; + int ts_fudge; + + + /* + * PFTM_TS_DIFF is how many seconds of leeway to allow + * a host's timestamp. This can happen if the previous + * packet got delayed in transit for much longer than + * this packet. + */ + if ((ts_fudge = state->rule.ptr->timeout[PFTM_TS_DIFF]) == 0) + ts_fudge = pf_default_rule.timeout[PFTM_TS_DIFF]; + + + /* Calculate max ticks since the last timestamp */ +#define TS_MAXFREQ 1100 /* RFC max TS freq of 1Khz + 10% skew */ +#define TS_MICROSECS 1000000 /* microseconds per second */ + timersub(&uptime, &src->scrub->pfss_last, &delta_ts); + tsval_from_last = (delta_ts.tv_sec + ts_fudge) * TS_MAXFREQ; + tsval_from_last += delta_ts.tv_usec / (TS_MICROSECS/TS_MAXFREQ); + + + if ((src->state >= TCPS_ESTABLISHED && + dst->state >= TCPS_ESTABLISHED) && + (SEQ_LT(tsval, dst->scrub->pfss_tsecr) || + SEQ_GT(tsval, src->scrub->pfss_tsval + tsval_from_last) || + (tsecr && (SEQ_GT(tsecr, dst->scrub->pfss_tsval) || + SEQ_LT(tsecr, dst->scrub->pfss_tsval0))))) { + /* Bad RFC1323 implementation or an insertion attack. + * + * - Solaris 2.6 and 2.7 are known to send another ACK + * after the FIN,FIN|ACK,ACK closing that carries + * an old timestamp. + */ + + DPFPRINTF(("Timestamp failed %c%c%c%c\n", + SEQ_LT(tsval, dst->scrub->pfss_tsecr) ? '0' : ' ', + SEQ_GT(tsval, src->scrub->pfss_tsval + + tsval_from_last) ? '1' : ' ', + SEQ_GT(tsecr, dst->scrub->pfss_tsval) ? '2' : ' ', + SEQ_LT(tsecr, dst->scrub->pfss_tsval0)? '3' : ' ')); + DPFPRINTF((" tsval: %" PRIu32 " tsecr: %" PRIu32 + " +ticks: %" PRIu32 " idle: %lus %lums\n", + tsval, tsecr, tsval_from_last, delta_ts.tv_sec, + delta_ts.tv_usec / 1000)); + DPFPRINTF((" src->tsval: %" PRIu32 " tsecr: %" PRIu32 + "\n", + src->scrub->pfss_tsval, src->scrub->pfss_tsecr)); + DPFPRINTF((" dst->tsval: %" PRIu32 " tsecr: %" PRIu32 + " tsval0: %" PRIu32 "\n", + dst->scrub->pfss_tsval, + dst->scrub->pfss_tsecr, dst->scrub->pfss_tsval0)); + if (pf_status.debug >= PF_DEBUG_MISC) { + pf_print_state(state); + pf_print_flags(th->th_flags); + printf("\n"); + } + REASON_SET(reason, PFRES_TS); + return (PF_DROP); + } + + /* XXX I'd really like to require tsecr but it's optional */ + + } else if (!got_ts && (th->th_flags & TH_RST) == 0 && + ((src->state == TCPS_ESTABLISHED && dst->state == TCPS_ESTABLISHED) + || pd->p_len > 0 || (th->th_flags & TH_SYN)) && + src->scrub && dst->scrub && + (src->scrub->pfss_flags & PFSS_PAWS) && + (dst->scrub->pfss_flags & PFSS_PAWS)) { + /* Didn't send a timestamp. Timestamps aren't really useful + * when: + * - connection opening or closing (often not even sent). + * but we must not let an attacker to put a FIN on a + * data packet to sneak it through our ESTABLISHED check. + * - on a TCP reset. RFC suggests not even looking at TS. + * - on an empty ACK. The TS will not be echoed so it will + * probably not help keep the RTT calculation in sync and + * there isn't as much danger when the sequence numbers + * got wrapped. So some stacks don't include TS on empty + * ACKs :-( + * + * To minimize the disruption to mostly RFC1323 conformant + * stacks, we will only require timestamps on data packets. + * + * And what do ya know, we cannot require timestamps on data + * packets. There appear to be devices that do legitimate + * TCP connection hijacking. There are HTTP devices that allow + * a 3whs (with timestamps) and then buffer the HTTP request. + * If the intermediate device has the HTTP response cache, it + * will spoof the response but not bother timestamping its + * packets. So we can look for the presence of a timestamp in + * the first data packet and if there, require it in all future + * packets. + */ + + if (pd->p_len > 0 && (src->scrub->pfss_flags & PFSS_DATA_TS)) { + /* + * Hey! Someone tried to sneak a packet in. Or the + * stack changed its RFC1323 behavior?!?! + */ + if (pf_status.debug >= PF_DEBUG_MISC) { + DPFPRINTF(("Did not receive expected RFC1323 " + "timestamp\n")); + pf_print_state(state); + pf_print_flags(th->th_flags); + printf("\n"); + } + REASON_SET(reason, PFRES_TS); + return (PF_DROP); + } + } + + + /* + * We will note if a host sends his data packets with or without + * timestamps. And require all data packets to contain a timestamp + * if the first does. PAWS implicitly requires that all data packets be + * timestamped. But I think there are middle-man devices that hijack + * TCP streams immedietly after the 3whs and don't timestamp their + * packets (seen in a WWW accelerator or cache). + */ + if (pd->p_len > 0 && src->scrub && (src->scrub->pfss_flags & + (PFSS_TIMESTAMP|PFSS_DATA_TS|PFSS_DATA_NOTS)) == PFSS_TIMESTAMP) { + if (got_ts) + src->scrub->pfss_flags |= PFSS_DATA_TS; + else { + src->scrub->pfss_flags |= PFSS_DATA_NOTS; + if (pf_status.debug >= PF_DEBUG_MISC && dst->scrub && + (dst->scrub->pfss_flags & PFSS_TIMESTAMP)) { + /* Don't warn if other host rejected RFC1323 */ + DPFPRINTF(("Broken RFC1323 stack did not " + "timestamp data packet. Disabled PAWS " + "security.\n")); + pf_print_state(state); + pf_print_flags(th->th_flags); + printf("\n"); + } + } + } + + + /* + * Update PAWS values + */ + if (got_ts && src->scrub && PFSS_TIMESTAMP == (src->scrub->pfss_flags & + (PFSS_PAWS_IDLED|PFSS_TIMESTAMP))) { + getmicrouptime(&src->scrub->pfss_last); + if (SEQ_GEQ(tsval, src->scrub->pfss_tsval) || + (src->scrub->pfss_flags & PFSS_PAWS) == 0) + src->scrub->pfss_tsval = tsval; + + if (tsecr) { + if (SEQ_GEQ(tsecr, src->scrub->pfss_tsecr) || + (src->scrub->pfss_flags & PFSS_PAWS) == 0) + src->scrub->pfss_tsecr = tsecr; + + if ((src->scrub->pfss_flags & PFSS_PAWS) == 0 && + (SEQ_LT(tsval, src->scrub->pfss_tsval0) || + src->scrub->pfss_tsval0 == 0)) { + /* tsval0 MUST be the lowest timestamp */ + src->scrub->pfss_tsval0 = tsval; + } + + /* Only fully initialized after a TS gets echoed */ + if ((src->scrub->pfss_flags & PFSS_PAWS) == 0) + src->scrub->pfss_flags |= PFSS_PAWS; + } + } + /* I have a dream.... TCP segment reassembly.... */ return (0); } + int pf_normalize_tcpopt(struct pf_rule *r, struct mbuf *m, struct tcphdr *th, int off) @@ -1559,7 +1868,7 @@ pf_normalize_tcpopt(struct pf_rule *r, struct mbuf *m, struct tcphdr *th, mss = (u_int16_t *)(optp + 2); if ((ntohs(*mss)) > r->max_mss) { th->th_sum = pf_cksum_fixup(th->th_sum, - *mss, htons(r->max_mss)); + *mss, htons(r->max_mss), 0); *mss = htons(r->max_mss); rewrite = 1; } diff --git a/sys/dist/pf/net/pf_osfp.c b/sys/dist/pf/net/pf_osfp.c index 84f0975df9d3..0600c8f5502d 100644 --- a/sys/dist/pf/net/pf_osfp.c +++ b/sys/dist/pf/net/pf_osfp.c @@ -1,5 +1,5 @@ -/* $NetBSD: pf_osfp.c,v 1.3 2004/06/29 04:42:55 itojun Exp $ */ -/* $OpenBSD: pf_osfp.c,v 1.9 2004/01/04 20:08:42 pvalchev Exp $ */ +/* $NetBSD: pf_osfp.c,v 1.4 2004/11/14 11:12:16 yamt Exp $ */ +/* $OpenBSD: pf_osfp.c,v 1.10 2004/04/09 19:30:41 frantzen Exp $ */ /* * Copyright (c) 2003 Mike Frantzen @@ -238,9 +238,9 @@ void pf_osfp_initialize(void) { pool_init(&pf_osfp_entry_pl, sizeof(struct pf_osfp_entry), 0, 0, 0, - "pfosfpen", NULL); + "pfosfpen", &pool_allocator_nointr); pool_init(&pf_osfp_pl, sizeof(struct pf_os_fingerprint), 0, 0, 0, - "pfosfp", NULL); + "pfosfp", &pool_allocator_nointr); SLIST_INIT(&pf_osfp_list); } diff --git a/sys/dist/pf/net/pf_table.c b/sys/dist/pf/net/pf_table.c index 3168f5e512f2..3ff521ed13a7 100644 --- a/sys/dist/pf/net/pf_table.c +++ b/sys/dist/pf/net/pf_table.c @@ -1,5 +1,5 @@ -/* $NetBSD: pf_table.c,v 1.4 2004/09/09 14:56:00 yamt Exp $ */ -/* $OpenBSD: pf_table.c,v 1.47 2004/03/09 21:44:41 mcbride Exp $ */ +/* $NetBSD: pf_table.c,v 1.5 2004/11/14 11:12:16 yamt Exp $ */ +/* $OpenBSD: pf_table.c,v 1.59 2004/07/08 23:17:38 mcbride Exp $ */ /* * Copyright (c) 2002 Cedric Berger @@ -194,9 +194,9 @@ void pfr_initialize(void) { pool_init(&pfr_ktable_pl, sizeof(struct pfr_ktable), 0, 0, 0, - "pfrktable", NULL); + "pfrktable", &pool_allocator_oldnointr); pool_init(&pfr_kentry_pl, sizeof(struct pfr_kentry), 0, 0, 0, - "pfrkentry", NULL); + "pfrkentry", &pool_allocator_oldnointr); pfr_sin.sin_len = sizeof(pfr_sin); pfr_sin.sin_family = AF_INET; @@ -255,8 +255,8 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfr_kentryworkq workq; struct pfr_kentry *p, *q; struct pfr_addr ad; - int i, rv, s = 0, xadd = 0; - long tzero = time.tv_sec; + int i, rv, s = 0 /* XXX gcc */, xadd = 0; + long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) @@ -333,7 +333,7 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfr_kentryworkq workq; struct pfr_kentry *p; struct pfr_addr ad; - int i, rv, s = 0, xdel = 0; + int i, rv, s = 0 /* XXX gcc */, xdel = 0, log = 1; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) @@ -343,7 +343,34 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, return (ESRCH); if (kt->pfrkt_flags & PFR_TFLAG_CONST) return (EPERM); - pfr_mark_addrs(kt); + /* + * there are two algorithms to choose from here. + * with: + * n: number of addresses to delete + * N: number of addresses in the table + * + * one is O(N) and is better for large 'n' + * one is O(n*LOG(N)) and is better for small 'n' + * + * following code try to decide which one is best. + */ + for (i = kt->pfrkt_cnt; i > 0; i >>= 1) + log++; + if (size > kt->pfrkt_cnt/log) { + /* full table scan */ + pfr_mark_addrs(kt); + } else { + /* iterate over addresses to delete */ + for (i = 0; i < size; i++) { + if (COPYIN(addr+i, &ad, sizeof(ad))) + return (EFAULT); + if (pfr_validate_addr(&ad)) + return (EINVAL); + p = pfr_lookup_addr(kt, &ad, 1); + if (p != NULL) + p->pfrke_mark = 0; + } + } SLIST_INIT(&workq); for (i = 0; i < size; i++) { if (COPYIN(addr+i, &ad, sizeof(ad))) @@ -395,8 +422,9 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfr_kentryworkq addq, delq, changeq; struct pfr_kentry *p, *q; struct pfr_addr ad; - int i, rv, s = 0, xadd = 0, xdel = 0, xchange = 0; - long tzero = time.tv_sec; + int i, rv, s = 0 /* XXX gcc */, xadd = 0, xdel = 0, + xchange = 0; + long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) @@ -583,8 +611,8 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, struct pfr_ktable *kt; struct pfr_walktree w; struct pfr_kentryworkq workq; - int rv, s = 0; - long tzero = time.tv_sec; + int rv, s = 0 /* XXX gcc */; + long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC); /* XXX PFR_FLAG_CLSTATS disabled */ if (pfr_validate_table(tbl, 0, 0)) @@ -682,14 +710,18 @@ pfr_validate_addr(struct pfr_addr *ad) int i; switch (ad->pfra_af) { +#ifdef INET case AF_INET: if (ad->pfra_net > 32) return (-1); break; +#endif /* INET */ +#ifdef INET6 case AF_INET6: if (ad->pfra_net > 128) return (-1); break; +#endif /* INET6 */ default: return (-1); } @@ -744,7 +776,7 @@ struct pfr_kentry * pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact) { union sockaddr_union sa, mask; - struct radix_node_head *head; + struct radix_node_head *head = (void *)0xdeadb; struct pfr_kentry *ke; int s; @@ -752,7 +784,7 @@ pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact) if (ad->pfra_af == AF_INET) { FILLIN_SIN(sa.sin, ad->pfra_ip4addr); head = kt->pfrkt_ip4; - } else { + } else if ( ad->pfra_af == AF_INET6 ) { FILLIN_SIN6(sa.sin6, ad->pfra_ip6addr); head = kt->pfrkt_ip6; } @@ -785,7 +817,7 @@ pfr_create_kentry(struct pfr_addr *ad) if (ad->pfra_af == AF_INET) FILLIN_SIN(ke->pfrke_sa.sin, ad->pfra_ip4addr); - else + else if (ad->pfra_af == AF_INET6) FILLIN_SIN6(ke->pfrke_sa.sin6, ad->pfra_ip6addr); ke->pfrke_af = ad->pfra_af; ke->pfrke_net = ad->pfra_net; @@ -896,14 +928,14 @@ pfr_prepare_network(union sockaddr_union *sa, int af, int net) if (af == AF_INET) { sa->sin.sin_len = sizeof(sa->sin); sa->sin.sin_family = AF_INET; - sa->sin.sin_addr.s_addr = htonl(-1 << (32-net)); - } else { + sa->sin.sin_addr.s_addr = net ? htonl(-1 << (32-net)) : 0; + } else if (af == AF_INET6) { sa->sin6.sin6_len = sizeof(sa->sin6); sa->sin6.sin6_family = AF_INET6; for (i = 0; i < 4; i++) { if (net <= 32) { sa->sin6.sin6_addr.s6_addr32[i] = - htonl(-1 << (32-net)); + net ? htonl(-1 << (32-net)) : 0; break; } sa->sin6.sin6_addr.s6_addr32[i] = 0xFFFFFFFF; @@ -917,13 +949,13 @@ pfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) { union sockaddr_union mask; struct radix_node *rn; - struct radix_node_head *head; + struct radix_node_head *head = (void *)0xdeadb; int s; bzero(ke->pfrke_node, sizeof(ke->pfrke_node)); if (ke->pfrke_af == AF_INET) head = kt->pfrkt_ip4; - else + else if (ke->pfrke_af == AF_INET6) head = kt->pfrkt_ip6; s = splsoftnet(); @@ -942,20 +974,28 @@ pfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) { union sockaddr_union mask; struct radix_node *rn; - struct radix_node_head *head; + struct radix_node_head *head = (void *)0xdeadb; int s; if (ke->pfrke_af == AF_INET) head = kt->pfrkt_ip4; - else + else if (ke->pfrke_af == AF_INET6) head = kt->pfrkt_ip6; s = splsoftnet(); if (KENTRY_NETWORK(ke)) { pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net); +#ifdef __OpenBSD__ + rn = rn_delete(&ke->pfrke_sa, &mask, head, NULL); +#else rn = rn_delete(&ke->pfrke_sa, &mask, head); +#endif } else +#ifdef __OpenBSD__ + rn = rn_delete(&ke->pfrke_sa, NULL, head, NULL); +#else rn = rn_delete(&ke->pfrke_sa, NULL, head); +#endif splx(s); if (rn == NULL) { @@ -976,7 +1016,7 @@ pfr_copyout_addr(struct pfr_addr *ad, struct pfr_kentry *ke) ad->pfra_not = ke->pfrke_not; if (ad->pfra_af == AF_INET) ad->pfra_ip4addr = ke->pfrke_sa.sin.sin_addr; - else + else if (ad->pfra_af == AF_INET6) ad->pfra_ip6addr = ke->pfrke_sa.sin6.sin6_addr; } @@ -1045,7 +1085,7 @@ pfr_walktree(struct radix_node *rn, void *arg) &ke->pfrke_sa, AF_INET); w->pfrw_dyn->pfid_mask4 = *SUNION2PF( &pfr_mask, AF_INET); - } else { + } else if (ke->pfrke_af == AF_INET6){ if (w->pfrw_dyn->pfid_acnt6++ > 0) break; pfr_prepare_network(&pfr_mask, AF_INET6, ke->pfrke_net); @@ -1099,8 +1139,8 @@ pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) { struct pfr_ktableworkq addq, changeq; struct pfr_ktable *p, *q, *r, key; - int i, rv, s = 0, xadd = 0; - long tzero = time.tv_sec; + int i, rv, s = 0 /* XXX gcc */, xadd = 0; + long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); SLIST_INIT(&addq); @@ -1128,7 +1168,6 @@ pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) /* find or create root table */ bzero(key.pfrkt_anchor, sizeof(key.pfrkt_anchor)); - bzero(key.pfrkt_ruleset, sizeof(key.pfrkt_ruleset)); r = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); if (r != NULL) { p->pfrkt_root = r; @@ -1252,8 +1291,8 @@ pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, { struct pfr_ktable *p; struct pfr_ktableworkq workq; - int s = 0, n, nn; - long tzero = time.tv_sec; + int s = 0 /* XXX gcc */, n, nn; + long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC|PFR_FLAG_ALLRSETS); /* XXX PFR_FLAG_CLSTATS disabled */ @@ -1300,8 +1339,8 @@ pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) { struct pfr_ktableworkq workq; struct pfr_ktable *p, key; - int i, s = 0, xzero = 0; - long tzero = time.tv_sec; + int i, s = 0 /* XXX gcc */, xzero = 0; + long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_ADDRSTOO); SLIST_INIT(&workq); @@ -1391,7 +1430,7 @@ pfr_ina_begin(struct pfr_table *trs, u_int32_t *ticket, int *ndel, int flags) int xdel = 0; ACCEPT_FLAGS(PFR_FLAG_DUMMY); - rs = pf_find_or_create_ruleset(trs->pfrt_anchor, trs->pfrt_ruleset); + rs = pf_find_or_create_ruleset(trs->pfrt_anchor); if (rs == NULL) return (ENOMEM); SLIST_INIT(&workq); @@ -1433,7 +1472,7 @@ pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, if (pfr_validate_table(tbl, PFR_TFLAG_USRMASK, flags & PFR_FLAG_USERIOCTL)) return (EINVAL); - rs = pf_find_ruleset(tbl->pfrt_anchor, tbl->pfrt_ruleset); + rs = pf_find_ruleset(tbl->pfrt_anchor); if (rs == NULL || !rs->topen || ticket != rs->tticket) return (EBUSY); tbl->pfrt_flags |= PFR_TFLAG_INACTIVE; @@ -1524,7 +1563,7 @@ pfr_ina_rollback(struct pfr_table *trs, u_int32_t ticket, int *ndel, int flags) int xdel = 0; ACCEPT_FLAGS(PFR_FLAG_DUMMY); - rs = pf_find_ruleset(trs->pfrt_anchor, trs->pfrt_ruleset); + rs = pf_find_ruleset(trs->pfrt_anchor); if (rs == NULL || !rs->topen || ticket != rs->tticket) return (0); SLIST_INIT(&workq); @@ -1553,11 +1592,11 @@ pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd, struct pfr_ktable *p, *q; struct pfr_ktableworkq workq; struct pf_ruleset *rs; - int s = 0, xadd = 0, xchange = 0; - long tzero = time.tv_sec; + int s = 0 /* XXX gcc */, xadd = 0, xchange = 0; + long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); - rs = pf_find_ruleset(trs->pfrt_anchor, trs->pfrt_ruleset); + rs = pf_find_ruleset(trs->pfrt_anchor); if (rs == NULL || !rs->topen || ticket != rs->tticket) return (EBUSY); @@ -1675,18 +1714,12 @@ int pfr_table_count(struct pfr_table *filter, int flags) { struct pf_ruleset *rs; - struct pf_anchor *ac; if (flags & PFR_FLAG_ALLRSETS) return (pfr_ktable_cnt); - if (filter->pfrt_ruleset[0]) { - rs = pf_find_ruleset(filter->pfrt_anchor, - filter->pfrt_ruleset); - return ((rs != NULL) ? rs->tables : -1); - } if (filter->pfrt_anchor[0]) { - ac = pf_find_anchor(filter->pfrt_anchor); - return ((ac != NULL) ? ac->tables : -1); + rs = pf_find_ruleset(filter->pfrt_anchor); + return ((rs != NULL) ? rs->tables : -1); } return (pf_main_ruleset.tables); } @@ -1696,13 +1729,7 @@ pfr_skip_table(struct pfr_table *filter, struct pfr_ktable *kt, int flags) { if (flags & PFR_FLAG_ALLRSETS) return (0); - if (strncmp(filter->pfrt_anchor, kt->pfrkt_anchor, - PF_ANCHOR_NAME_SIZE)) - return (1); - if (!filter->pfrt_ruleset[0]) - return (0); - if (strncmp(filter->pfrt_ruleset, kt->pfrkt_ruleset, - PF_RULESET_NAME_SIZE)) + if (strcmp(filter->pfrt_anchor, kt->pfrkt_anchor)) return (1); return (0); } @@ -1810,16 +1837,13 @@ pfr_create_ktable(struct pfr_table *tbl, long tzero, int attachruleset) kt->pfrkt_t = *tbl; if (attachruleset) { - rs = pf_find_or_create_ruleset(tbl->pfrt_anchor, - tbl->pfrt_ruleset); + rs = pf_find_or_create_ruleset(tbl->pfrt_anchor); if (!rs) { pfr_destroy_ktable(kt, 0); return (NULL); } kt->pfrkt_rs = rs; rs->tables++; - if (rs->anchor != NULL) - rs->anchor->tables++; } if (!rn_inithead((void **)&kt->pfrkt_ip4, @@ -1863,8 +1887,6 @@ pfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr) pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr); if (kt->pfrkt_rs != NULL) { kt->pfrkt_rs->tables--; - if (kt->pfrkt_rs->anchor != NULL) - kt->pfrkt_rs->anchor->tables--; pf_remove_if_empty_ruleset(kt->pfrkt_rs); } pool_put(&pfr_ktable_pl, kt); @@ -1877,11 +1899,7 @@ pfr_ktable_compare(struct pfr_ktable *p, struct pfr_ktable *q) if ((d = strncmp(p->pfrkt_name, q->pfrkt_name, PF_TABLE_NAME_SIZE))) return (d); - if ((d = strncmp(p->pfrkt_anchor, q->pfrkt_anchor, - PF_ANCHOR_NAME_SIZE))) - return (d); - return (strncmp(p->pfrkt_ruleset, q->pfrkt_ruleset, - PF_RULESET_NAME_SIZE)); + return (strcmp(p->pfrkt_anchor, q->pfrkt_anchor)); } struct pfr_ktable * @@ -1904,18 +1922,22 @@ pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af) return (0); switch (af) { +#ifdef INET case AF_INET: pfr_sin.sin_addr.s_addr = a->addr32[0]; ke = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4); if (ke && KENTRY_RNF_ROOT(ke)) ke = NULL; break; +#endif /* INET */ +#ifdef INET6 case AF_INET6: bcopy(a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr)); ke = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6); if (ke && KENTRY_RNF_ROOT(ke)) ke = NULL; break; +#endif /* INET6 */ } match = (ke && !ke->pfrke_not); if (match) @@ -1937,18 +1959,24 @@ pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af, return; switch (af) { +#ifdef INET case AF_INET: pfr_sin.sin_addr.s_addr = a->addr32[0]; ke = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4); if (ke && KENTRY_RNF_ROOT(ke)) ke = NULL; break; +#endif /* INET */ +#ifdef INET6 case AF_INET6: bcopy(a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr)); ke = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6); if (ke && KENTRY_RNF_ROOT(ke)) ke = NULL; break; +#endif /* INET6 */ + default: + ; } if ((ke == NULL || ke->pfrke_not) != notrule) { if (op_pass != PFR_OP_PASS) @@ -1972,18 +2000,15 @@ pfr_attach_table(struct pf_ruleset *rs, char *name) bzero(&tbl, sizeof(tbl)); strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name)); - if (ac != NULL) { + if (ac != NULL) strlcpy(tbl.pfrt_anchor, ac->name, sizeof(tbl.pfrt_anchor)); - strlcpy(tbl.pfrt_ruleset, rs->name, sizeof(tbl.pfrt_ruleset)); - } kt = pfr_lookup_table(&tbl); if (kt == NULL) { - kt = pfr_create_ktable(&tbl, time.tv_sec, 1); + kt = pfr_create_ktable(&tbl, time_second, 1); if (kt == NULL) return (NULL); if (ac != NULL) { bzero(tbl.pfrt_anchor, sizeof(tbl.pfrt_anchor)); - bzero(tbl.pfrt_ruleset, sizeof(tbl.pfrt_ruleset)); rt = pfr_lookup_table(&tbl); if (rt == NULL) { rt = pfr_create_ktable(&tbl, 0, 1); @@ -2016,13 +2041,15 @@ int pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter, struct pf_addr **raddr, struct pf_addr **rmask, sa_family_t af) { - struct pfr_kentry *ke, *ke2; - struct pf_addr *addr; + struct pfr_kentry *ke, *ke2 = (void *)0xdeadb; + struct pf_addr *addr = (void *)0xdeadb; union sockaddr_union mask; int idx = -1, use_counter = 0; - addr = (af == AF_INET) ? (struct pf_addr *)&pfr_sin.sin_addr : - (struct pf_addr *)&pfr_sin6.sin6_addr; + if (af == AF_INET) + addr = (struct pf_addr *)&pfr_sin.sin_addr; + else if (af == AF_INET6) + addr = (struct pf_addr *)&pfr_sin6.sin6_addr; if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) kt = kt->pfrkt_root; if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) @@ -2065,9 +2092,12 @@ _next_block: } for (;;) { /* we don't want to use a nested block */ - ke2 = (struct pfr_kentry *)(af == AF_INET ? - rn_match(&pfr_sin, kt->pfrkt_ip4) : - rn_match(&pfr_sin6, kt->pfrkt_ip6)); + if (af == AF_INET) + ke2 = (struct pfr_kentry *)rn_match(&pfr_sin, + kt->pfrkt_ip4); + else if (af == AF_INET6) + ke2 = (struct pfr_kentry *)rn_match(&pfr_sin6, + kt->pfrkt_ip6); /* no need to check KENTRY_RNF_ROOT() here */ if (ke2 == ke) { /* lookup return the same block - perfect */ @@ -2100,12 +2130,16 @@ pfr_kentry_byidx(struct pfr_ktable *kt, int idx, int af) w.pfrw_cnt = idx; switch (af) { +#ifdef INET case AF_INET: rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w); return (w.pfrw_kentry); +#endif /* INET */ +#ifdef INET6 case AF_INET6: rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w); return (w.pfrw_kentry); +#endif /* INET6 */ default: return (NULL); } diff --git a/sys/dist/pf/net/pfvar.h b/sys/dist/pf/net/pfvar.h index f74ac53f676e..222f80e4326e 100644 --- a/sys/dist/pf/net/pfvar.h +++ b/sys/dist/pf/net/pfvar.h @@ -1,5 +1,5 @@ -/* $NetBSD: pfvar.h,v 1.5 2004/09/28 00:14:02 dyoung Exp $ */ -/* $OpenBSD: pfvar.h,v 1.187 2004/03/22 04:54:18 mcbride Exp $ */ +/* $NetBSD: pfvar.h,v 1.6 2004/11/14 11:12:16 yamt Exp $ */ +/* $OpenBSD: pfvar.h,v 1.202 2004/07/12 00:50:22 itojun Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -34,6 +34,7 @@ #ifndef _NET_PFVAR_H_ #define _NET_PFVAR_H_ +#include #include #include #include @@ -80,7 +81,7 @@ enum { PFTM_TCP_FIRST_PACKET, PFTM_TCP_OPENING, PFTM_TCP_ESTABLISHED, PFTM_OTHER_FIRST_PACKET, PFTM_OTHER_SINGLE, PFTM_OTHER_MULTIPLE, PFTM_FRAG, PFTM_INTERVAL, PFTM_ADAPTIVE_START, PFTM_ADAPTIVE_END, PFTM_SRC_NODE, - PFTM_MAX, PFTM_PURGE, PFTM_UNTIL_PACKET }; + PFTM_TS_DIFF, PFTM_MAX, PFTM_PURGE, PFTM_UNTIL_PACKET }; enum { PF_NOPFROUTE, PF_FASTROUTE, PF_ROUTETO, PF_DUPTO, PF_REPLYTO }; enum { PF_LIMIT_STATES, PF_LIMIT_SRC_NODES, PF_LIMIT_FRAGS, PF_LIMIT_MAX }; #define PF_POOL_IDMASK 0x0f @@ -294,7 +295,7 @@ struct pfi_dynaddr { #endif /* PF_INET6_ONLY */ #endif /* PF_INET_INET6 */ -#define PF_MISMATCHAW(aw, x, af, not) \ +#define PF_MISMATCHAW(aw, x, af, neg) \ ( \ (((aw)->type == PF_ADDR_NOROUTE && \ pf_routable((x), (af))) || \ @@ -306,7 +307,7 @@ struct pfi_dynaddr { !PF_AZERO(&(aw)->v.a.mask, (af)) && \ !PF_MATCHA(0, &(aw)->v.a.addr, \ &(aw)->v.a.mask, (x), (af)))) != \ - (not) \ + (neg) \ ) struct pf_rule_uid { @@ -322,7 +323,7 @@ struct pf_rule_gid { struct pf_rule_addr { struct pf_addr_wrap addr; u_int16_t port[2]; - u_int8_t not; + u_int8_t neg; u_int8_t port_op; }; @@ -464,6 +465,8 @@ union pf_rule_ptr { u_int32_t nr; }; +#define PF_ANCHOR_NAME_SIZE 64 + struct pf_rule { struct pf_rule_addr src; struct pf_rule_addr dst; @@ -483,8 +486,6 @@ struct pf_rule { char ifname[IFNAMSIZ]; char qname[PF_QNAME_SIZE]; char pqname[PF_QNAME_SIZE]; -#define PF_ANCHOR_NAME_SIZE 16 - char anchorname[PF_ANCHOR_NAME_SIZE]; #define PF_TAG_NAME_SIZE 16 char tagname[PF_TAG_NAME_SIZE]; char match_tagname[PF_TAG_NAME_SIZE]; @@ -511,6 +512,7 @@ struct pf_rule { u_int32_t pqid; u_int32_t rt_listid; u_int32_t nr; + u_int32_t prob; u_int16_t return_icmp; u_int16_t return_icmp6; @@ -545,6 +547,8 @@ struct pf_rule { u_int8_t rt; u_int8_t return_ttl; u_int8_t tos; + u_int8_t anchor_relative; + u_int8_t anchor_wildcard; }; /* rule flags */ @@ -588,11 +592,19 @@ struct pf_src_node { #define PFSNODE_HIWAT 10000 /* default source node table size */ struct pf_state_scrub { + struct timeval pfss_last; /* time received last packet */ + u_int32_t pfss_tsecr; /* last echoed timestamp */ + u_int32_t pfss_tsval; /* largest timestamp */ + u_int32_t pfss_tsval0; /* original timestamp */ u_int16_t pfss_flags; -#define PFSS_TIMESTAMP 0x0001 /* modulate timestamp */ - u_int8_t pfss_ttl; /* stashed TTL */ +#define PFSS_TIMESTAMP 0x0001 /* modulate timestamp */ +#define PFSS_PAWS 0x0010 /* stricter PAWS checks */ +#define PFSS_PAWS_IDLED 0x0020 /* was idle too long. no PAWS */ +#define PFSS_DATA_TS 0x0040 /* timestamp on data packets */ +#define PFSS_DATA_NOTS 0x0080 /* no timestamp on data packets */ + u_int8_t pfss_ttl; /* stashed TTL */ u_int8_t pad; - u_int32_t pfss_ts_mod; /* timestamp modulation */ + u_int32_t pfss_ts_mod; /* timestamp modulation */ }; struct pf_state_host { @@ -661,9 +673,6 @@ TAILQ_HEAD(pf_rulequeue, pf_rule); struct pf_anchor; struct pf_ruleset { - TAILQ_ENTRY(pf_ruleset) entries; -#define PF_RULESET_NAME_SIZE 16 - char name[PF_RULESET_NAME_SIZE]; struct { struct pf_rulequeue queues[2]; struct { @@ -678,19 +687,22 @@ struct pf_ruleset { int topen; }; -TAILQ_HEAD(pf_rulesetqueue, pf_ruleset); - +RB_HEAD(pf_anchor_global, pf_anchor); +RB_HEAD(pf_anchor_node, pf_anchor); struct pf_anchor { - TAILQ_ENTRY(pf_anchor) entries; + RB_ENTRY(pf_anchor) entry_global; + RB_ENTRY(pf_anchor) entry_node; + struct pf_anchor *parent; + struct pf_anchor_node children; char name[PF_ANCHOR_NAME_SIZE]; - struct pf_rulesetqueue rulesets; - int tables; + char path[MAXPATHLEN]; + struct pf_ruleset ruleset; + int refcnt; /* anchor rules */ }; - -TAILQ_HEAD(pf_anchorqueue, pf_anchor); +RB_PROTOTYPE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare); +RB_PROTOTYPE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare); #define PF_RESERVED_ANCHOR "_pf" -#define PF_INTERFACE_RULESET "_if" #define PFR_TFLAG_PERSIST 0x00000001 #define PFR_TFLAG_CONST 0x00000002 @@ -703,8 +715,7 @@ TAILQ_HEAD(pf_anchorqueue, pf_anchor); #define PFR_TFLAG_ALLMASK 0x0000003F struct pfr_table { - char pfrt_anchor[PF_ANCHOR_NAME_SIZE]; - char pfrt_ruleset[PF_RULESET_NAME_SIZE]; + char pfrt_anchor[MAXPATHLEN]; char pfrt_name[PF_TABLE_NAME_SIZE]; u_int32_t pfrt_flags; u_int8_t pfrt_fback; @@ -867,11 +878,14 @@ struct pf_pdesc { struct pf_rule *nat_rule; /* nat/rdr rule applied to packet */ struct pf_addr *src; struct pf_addr *dst; + struct ether_header + *eh; u_int16_t *ip_sum; u_int32_t p_len; /* total length of payload */ u_int16_t flags; /* Let SCRUB trigger behavior in * state code. Easier than tags */ #define PFDESC_TCP_NORM 0x0001 /* TCP shall be statefully scrubbed */ +#define PFDESC_IP_REAS 0x0002 /* IP frags would've been reassembled */ sa_family_t af; u_int8_t proto; u_int8_t tos; @@ -888,7 +902,8 @@ struct pf_pdesc { #define PFRES_SHORT 3 /* Dropping short packet */ #define PFRES_NORM 4 /* Dropping by normalizer */ #define PFRES_MEMORY 5 /* Dropped due to lacking mem */ -#define PFRES_MAX 6 /* total+1 */ +#define PFRES_TS 6 /* Bad TCP Timestamp (RFC1323) */ +#define PFRES_MAX 7 /* total+1 */ #define PFRES_NAMES { \ "match", \ @@ -897,6 +912,7 @@ struct pf_pdesc { "short", \ "normalize", \ "memory", \ + "bad-timestamp", \ NULL \ } @@ -1056,8 +1072,7 @@ struct pfioc_pooladdr { u_int8_t r_action; u_int8_t r_last; u_int8_t af; - char anchor[PF_ANCHOR_NAME_SIZE]; - char ruleset[PF_RULESET_NAME_SIZE]; + char anchor[MAXPATHLEN]; struct pf_pooladdr addr; }; @@ -1066,8 +1081,8 @@ struct pfioc_rule { u_int32_t ticket; u_int32_t pool_ticket; u_int32_t nr; - char anchor[PF_ANCHOR_NAME_SIZE]; - char ruleset[PF_RULESET_NAME_SIZE]; + char anchor[MAXPATHLEN]; + char anchor_call[MAXPATHLEN]; struct pf_rule rule; }; @@ -1148,15 +1163,10 @@ struct pfioc_qstats { u_int8_t scheduler; }; -struct pfioc_anchor { - u_int32_t nr; - char name[PF_ANCHOR_NAME_SIZE]; -}; - struct pfioc_ruleset { u_int32_t nr; - char anchor[PF_ANCHOR_NAME_SIZE]; - char name[PF_RULESET_NAME_SIZE]; + char path[MAXPATHLEN]; + char name[PF_ANCHOR_NAME_SIZE]; }; #define PF_RULESET_ALTQ (PF_RULESET_MAX) @@ -1166,8 +1176,7 @@ struct pfioc_trans { int esize; /* size of each element in bytes */ struct pfioc_trans_e { int rs_num; - char anchor[PF_ANCHOR_NAME_SIZE]; - char ruleset[PF_RULESET_NAME_SIZE]; + char anchor[MAXPATHLEN]; u_int32_t ticket; } *array; }; @@ -1224,9 +1233,7 @@ struct pfioc_iface { #define DIOCSTART _IO ('D', 1) #define DIOCSTOP _IO ('D', 2) -#define DIOCBEGINRULES _IOWR('D', 3, struct pfioc_rule) #define DIOCADDRULE _IOWR('D', 4, struct pfioc_rule) -#define DIOCCOMMITRULES _IOWR('D', 5, struct pfioc_rule) #define DIOCGETRULES _IOWR('D', 6, struct pfioc_rule) #define DIOCGETRULE _IOWR('D', 7, struct pfioc_rule) /* XXX cut 8 - 17 */ @@ -1249,9 +1256,7 @@ struct pfioc_iface { #define DIOCKILLSTATES _IOWR('D', 41, struct pfioc_state_kill) #define DIOCSTARTALTQ _IO ('D', 42) #define DIOCSTOPALTQ _IO ('D', 43) -#define DIOCBEGINALTQS _IOWR('D', 44, u_int32_t) #define DIOCADDALTQ _IOWR('D', 45, struct pfioc_altq) -#define DIOCCOMMITALTQS _IOWR('D', 46, u_int32_t) #define DIOCGETALTQS _IOWR('D', 47, struct pfioc_altq) #define DIOCGETALTQ _IOWR('D', 48, struct pfioc_altq) #define DIOCCHANGEALTQ _IOWR('D', 49, struct pfioc_altq) @@ -1261,8 +1266,7 @@ struct pfioc_iface { #define DIOCGETADDRS _IOWR('D', 53, struct pfioc_pooladdr) #define DIOCGETADDR _IOWR('D', 54, struct pfioc_pooladdr) #define DIOCCHANGEADDR _IOWR('D', 55, struct pfioc_pooladdr) -#define DIOCGETANCHORS _IOWR('D', 56, struct pfioc_anchor) -#define DIOCGETANCHOR _IOWR('D', 57, struct pfioc_anchor) +/* XXX cut 55 - 57 */ #define DIOCGETRULESETS _IOWR('D', 58, struct pfioc_ruleset) #define DIOCGETRULESET _IOWR('D', 59, struct pfioc_ruleset) #define DIOCRCLRTABLES _IOWR('D', 60, struct pfioc_table) @@ -1280,8 +1284,6 @@ struct pfioc_iface { #define DIOCRCLRASTATS _IOWR('D', 72, struct pfioc_table) #define DIOCRTSTADDRS _IOWR('D', 73, struct pfioc_table) #define DIOCRSETTFLAGS _IOWR('D', 74, struct pfioc_table) -#define DIOCRINABEGIN _IOWR('D', 75, struct pfioc_table) -#define DIOCRINACOMMIT _IOWR('D', 76, struct pfioc_table) #define DIOCRINADEFINE _IOWR('D', 77, struct pfioc_table) #define DIOCOSFPFLUSH _IO('D', 78) #define DIOCOSFPADD _IOWR('D', 79, struct pf_osfp_ioctl) @@ -1306,7 +1308,7 @@ RB_PROTOTYPE(pf_state_tree_id, pf_state, extern struct pf_state_tree_id tree_id; extern struct pf_state_queue state_updates; -extern struct pf_anchorqueue pf_anchors; +extern struct pf_anchor_global pf_anchors; extern struct pf_ruleset pf_main_ruleset; TAILQ_HEAD(pf_poolqueue, pf_pool); extern struct pf_poolqueue pf_pools[2]; @@ -1328,13 +1330,13 @@ extern int pf_tbladdr_setup(struct pf_ruleset *, extern void pf_tbladdr_remove(struct pf_addr_wrap *); extern void pf_tbladdr_copyout(struct pf_addr_wrap *); extern void pf_calc_skip_steps(struct pf_rulequeue *); -extern void pf_update_anchor_rules(void); extern struct pool pf_src_tree_pl, pf_rule_pl; extern struct pool pf_state_pl, pf_altq_pl, pf_pooladdr_pl; extern struct pool pf_state_scrub_pl; extern void pf_purge_timeout(void *); extern void pf_purge_expired_src_nodes(void); extern void pf_purge_expired_states(void); +extern void pf_purge_expired_state(struct pf_state *); extern int pf_insert_state(struct pfi_kif *, struct pf_state *); extern int pf_insert_src_node(struct pf_src_node **, @@ -1344,13 +1346,15 @@ void pf_src_tree_remove_state(struct pf_state *); extern struct pf_state *pf_find_state_byid(struct pf_state *); extern struct pf_state *pf_find_state_all(struct pf_state *key, u_int8_t tree, int *more); +extern void pf_print_state(struct pf_state *); +extern void pf_print_flags(u_int8_t); extern struct pf_anchor *pf_find_anchor(const char *); -extern struct pf_ruleset *pf_find_ruleset(char *, char *); -extern struct pf_ruleset *pf_find_or_create_ruleset( - char[PF_ANCHOR_NAME_SIZE], - char[PF_RULESET_NAME_SIZE]); +extern struct pf_ruleset *pf_find_ruleset(const char *); +extern struct pf_ruleset *pf_find_or_create_ruleset(const char *); extern void pf_remove_if_empty_ruleset( struct pf_ruleset *); +extern u_int16_t pf_cksum_fixup(u_int16_t, u_int16_t, u_int16_t, + u_int8_t); extern struct ifnet *sync_ifp; extern struct pf_rule pf_default_rule; @@ -1360,11 +1364,11 @@ void pf_rm_rule(struct pf_rulequeue *, struct pf_rule *); #ifdef INET -int pf_test(int, struct ifnet *, struct mbuf **); +int pf_test(int, struct ifnet *, struct mbuf **, struct ether_header *); #endif /* INET */ #ifdef INET6 -int pf_test6(int, struct ifnet *, struct mbuf **); +int pf_test6(int, struct ifnet *, struct mbuf **, struct ether_header *); void pf_poolmask(struct pf_addr *, struct pf_addr*, struct pf_addr *, struct pf_addr *, u_int8_t); void pf_addr_inc(struct pf_addr *, sa_family_t); @@ -1386,16 +1390,18 @@ void pf_normalize_init(void); #ifdef _LKM void pf_normalize_destroy(void); #endif -int pf_normalize_ip(struct mbuf **, int, struct pfi_kif *, u_short *); -int pf_normalize_ip6(struct mbuf **, int, struct pfi_kif *, u_short *); +int pf_normalize_ip(struct mbuf **, int, struct pfi_kif *, u_short *, + struct pf_pdesc *); +int pf_normalize_ip6(struct mbuf **, int, struct pfi_kif *, u_short *, + struct pf_pdesc *); int pf_normalize_tcp(int, struct pfi_kif *, struct mbuf *, int, int, void *, struct pf_pdesc *); void pf_normalize_tcp_cleanup(struct pf_state *); int pf_normalize_tcp_init(struct mbuf *, int, struct pf_pdesc *, struct tcphdr *, struct pf_state_peer *, struct pf_state_peer *); int pf_normalize_tcp_stateful(struct mbuf *, int, struct pf_pdesc *, - u_short *, struct tcphdr *, struct pf_state_peer *, - struct pf_state_peer *, int *); + u_short *, struct tcphdr *, struct pf_state *, + struct pf_state_peer *, struct pf_state_peer *, int *); u_int32_t pf_state_expires(const struct pf_state *); void pf_purge_expired_fragments(void); @@ -1486,6 +1492,30 @@ int pfil4_wrapper(void *, struct mbuf **, struct ifnet *, int); int pfil6_wrapper(void *, struct mbuf **, struct ifnet *, int); int pfil_ifnet_wrapper(void *, struct mbuf **, struct ifnet *, int); int pfil_ifaddr_wrapper(void *, struct mbuf **, struct ifnet *, int); + +#endif + +/* + * misc compatibility stuffs + */ +#if !defined(PRIu32) +#define PRIu32 "u" /* XXX */ +#endif +#if !defined(__OpenBSD__) +#include /* mono_time */ +static __inline void getmicrouptime(struct timeval *); +static __inline void +getmicrouptime(struct timeval *tvp) +{ + int s; + + s = splclock(); + *tvp = mono_time; + splx(s); +} +#define time_second time.tv_sec +#define m_copym2 m_dup +#define pool_allocator_oldnointr pool_allocator_nointr #endif #endif /* _KERNEL */