diff options
Diffstat (limited to 'sys/contrib/pf/net/pf.c')
-rw-r--r-- | sys/contrib/pf/net/pf.c | 2074 |
1 files changed, 1311 insertions, 763 deletions
diff --git a/sys/contrib/pf/net/pf.c b/sys/contrib/pf/net/pf.c index 793dc34..282cbb5 100644 --- a/sys/contrib/pf/net/pf.c +++ b/sys/contrib/pf/net/pf.c @@ -1,4 +1,5 @@ -/* $OpenBSD: pf.c,v 1.527 2007/02/22 15:23:23 pyr Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: pf.c,v 1.483 2005/03/15 17:38:43 dhartmei Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -35,9 +36,39 @@ * */ +#ifdef __FreeBSD__ +#include "opt_inet.h" +#include "opt_inet6.h" +#endif + +#ifdef __FreeBSD__ +#include "opt_mac.h" +#include "opt_bpf.h" +#include "opt_pf.h" + +#ifdef DEV_BPF +#define NBPFILTER DEV_BPF +#else +#define NBPFILTER 0 +#endif + +#ifdef DEV_PFLOG +#define NPFLOG DEV_PFLOG +#else +#define NPFLOG 0 +#endif + +#ifdef DEV_PFSYNC +#define NPFSYNC DEV_PFSYNC +#else +#define NPFSYNC 0 +#endif + +#else #include "bpfilter.h" #include "pflog.h" #include "pfsync.h" +#endif #include <sys/param.h> #include <sys/systm.h> @@ -47,15 +78,17 @@ #include <sys/socketvar.h> #include <sys/kernel.h> #include <sys/time.h> +#ifdef __FreeBSD__ +#include <sys/sysctl.h> +#include <sys/endian.h> +#else #include <sys/pool.h> -#include <sys/proc.h> -#include <sys/rwlock.h> +#endif #include <net/if.h> #include <net/if_types.h> #include <net/bpf.h> #include <net/route.h> -#include <net/radix_mpath.h> #include <netinet/in.h> #include <netinet/in_var.h> @@ -73,7 +106,9 @@ #include <netinet/icmp_var.h> #include <netinet/if_ether.h> +#ifndef __FreeBSD__ #include <dev/rndvar.h> +#endif #include <net/pfvar.h> #include <net/if_pflog.h> @@ -86,8 +121,20 @@ #include <netinet/in_pcb.h> #include <netinet/icmp6.h> #include <netinet6/nd6.h> +#ifdef __FreeBSD__ +#include <netinet6/ip6_var.h> +#include <netinet6/in6_pcb.h> +#endif #endif /* INET6 */ +#ifdef __FreeBSD__ +#include <machine/in_cksum.h> +#include <sys/limits.h> +#include <sys/ucred.h> +#include <security/mac/mac_framework.h> + +extern int ip_optcopy(struct ip *, struct ip *); +#endif #define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x @@ -95,6 +142,8 @@ * Global variables */ +struct pf_anchor_global pf_anchors; +struct pf_ruleset pf_main_ruleset; struct pf_altqqueue pf_altqs[2]; struct pf_palist pf_pabuf; struct pf_altqqueue *pf_altqs_active; @@ -106,6 +155,12 @@ u_int32_t ticket_altqs_inactive; int altqs_inactive_open; u_int32_t ticket_pabuf; +#ifdef __FreeBSD__ +struct callout pf_expire_to; /* expire timeout */ +#else +struct timeout pf_expire_to; /* expire timeout */ +#endif + struct pf_anchor_stackframe { struct pf_ruleset *rs; struct pf_rule *r; @@ -113,8 +168,13 @@ struct pf_anchor_stackframe { struct pf_anchor *child; } pf_anchor_stack[64]; +#ifdef __FreeBSD__ +uma_zone_t pf_src_tree_pl, pf_rule_pl; +uma_zone_t pf_state_pl, pf_altq_pl, pf_pooladdr_pl; +#else struct pool pf_src_tree_pl, pf_rule_pl; struct pool pf_state_pl, pf_altq_pl, pf_pooladdr_pl; +#endif void pf_print_host(struct pf_addr *, u_int16_t, u_int8_t); @@ -126,8 +186,6 @@ int pf_check_threshold(struct pf_threshold *); void pf_change_ap(struct pf_addr *, u_int16_t *, u_int16_t *, u_int16_t *, struct pf_addr *, u_int16_t, u_int8_t, sa_family_t); -int pf_modulate_sack(struct mbuf *, int, struct pf_pdesc *, - struct tcphdr *, struct pf_state_peer *); #ifdef INET6 void pf_change_a6(struct pf_addr *, u_int16_t *, struct pf_addr *, u_int8_t); @@ -136,11 +194,16 @@ void pf_change_icmp(struct pf_addr *, u_int16_t *, struct pf_addr *, struct pf_addr *, u_int16_t, u_int16_t *, u_int16_t *, u_int16_t *, u_int16_t *, u_int8_t, sa_family_t); +#ifdef __FreeBSD__ +void pf_send_tcp(struct mbuf *, + const struct pf_rule *, sa_family_t, +#else void pf_send_tcp(const struct pf_rule *, sa_family_t, +#endif 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, int, - u_int16_t, struct ether_header *, struct ifnet *); + 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 *, @@ -155,11 +218,21 @@ 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 **, +#ifdef __FreeBSD__ + struct pf_ruleset **, struct ifqueue *, + struct inpcb *); +#else struct pf_ruleset **, struct ifqueue *); +#endif int pf_test_udp(struct pf_rule **, struct pf_state **, int, struct pfi_kif *, struct mbuf *, int, void *, struct pf_pdesc *, struct pf_rule **, +#ifdef __FreeBSD__ + struct pf_ruleset **, struct ifqueue *, + struct inpcb *); +#else struct pf_ruleset **, struct ifqueue *); +#endif int pf_test_icmp(struct pf_rule **, struct pf_state **, int, struct pfi_kif *, struct mbuf *, int, void *, struct pf_pdesc *, struct pf_rule **, @@ -183,11 +256,9 @@ int pf_test_state_icmp(struct pf_state **, int, void *, struct pf_pdesc *, u_short *); int pf_test_state_other(struct pf_state **, int, struct pfi_kif *, struct pf_pdesc *); +struct pf_tag *pf_get_tag(struct mbuf *); int pf_match_tag(struct mbuf *, struct pf_rule *, - struct pf_mtag *, int *); -int pf_step_out_of_anchor(int *, struct pf_ruleset **, - int, struct pf_rule **, struct pf_rule **, - int *); + struct pf_tag **, int *); void pf_hash(struct pf_addr *, struct pf_addr *, struct pf_poolhashkey *, sa_family_t); int pf_map_addr(u_int8_t, struct pf_rule *, @@ -198,12 +269,16 @@ int pf_get_sport(sa_family_t, u_int8_t, struct pf_rule *, struct pf_addr *, u_int16_t*, u_int16_t, u_int16_t, struct pf_src_node **); void pf_route(struct mbuf **, struct pf_rule *, int, - struct ifnet *, struct pf_state *, - struct pf_pdesc *); + struct ifnet *, struct pf_state *); void pf_route6(struct mbuf **, struct pf_rule *, int, - struct ifnet *, struct pf_state *, - struct pf_pdesc *); -int pf_socket_lookup(int, struct pf_pdesc *); + struct ifnet *, struct pf_state *); +#ifdef __FreeBSD__ +int pf_socket_lookup(uid_t *, gid_t *, + int, struct pf_pdesc *, struct inpcb *); +#else +int pf_socket_lookup(uid_t *, gid_t *, + int, struct pf_pdesc *); +#endif u_int8_t pf_get_wscale(struct mbuf *, int, u_int16_t, sa_family_t); u_int16_t pf_get_mss(struct mbuf *, int, u_int16_t, @@ -216,21 +291,24 @@ int pf_check_proto_cksum(struct mbuf *, int, int, u_int8_t, sa_family_t); int pf_addr_wrap_neq(struct pf_addr_wrap *, struct pf_addr_wrap *); +static int pf_add_mbuf_tag(struct mbuf *, u_int); struct pf_state *pf_find_state_recurse(struct pfi_kif *, - struct pf_state_cmp *, u_int8_t); + struct pf_state *, u_int8_t); int pf_src_connlimit(struct pf_state **); int pf_check_congestion(struct ifqueue *); -extern struct pool pfr_ktable_pl; -extern struct pool pfr_kentry_pl; +#ifdef __FreeBSD__ +int in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len); + +struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX]; +#else struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = { { &pf_state_pl, PFSTATE_HIWAT }, { &pf_src_tree_pl, PFSNODE_HIWAT }, - { &pf_frent_pl, PFFRAG_FRENT_HIWAT }, - { &pfr_ktable_pl, PFR_KTABLE_HIWAT }, - { &pfr_kentry_pl, PFR_KENTRY_HIWAT } + { &pf_frent_pl, PFFRAG_FRENT_HIWAT } }; +#endif #define STATE_LOOKUP() \ do { \ @@ -260,8 +338,9 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = { (s)->lan.addr.addr32[3] != (s)->gwy.addr.addr32[3])) || \ (s)->lan.port != (s)->gwy.port -#define BOUND_IFACE(r, k) \ - ((r)->rule_flag & PFRULE_IFBOUND) ? (k) : pfi_all +#define BOUND_IFACE(r, k) (((r)->rule_flag & PFRULE_IFBOUND) ? (k) : \ + ((r)->rule_flag & PFRULE_GRBOUND) ? (k)->pfik_parent : \ + (k)->pfik_parent->pfik_parent) #define STATE_INC_COUNTERS(s) \ do { \ @@ -281,6 +360,7 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = { s->rule.ptr->states--; \ } while (0) +#ifndef __FreeBSD__ static __inline int pf_src_compare(struct pf_src_node *, struct pf_src_node *); static __inline int pf_state_compare_lan_ext(struct pf_state *, struct pf_state *); @@ -288,11 +368,22 @@ 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 *); +#else +static int pf_src_compare(struct pf_src_node *, struct pf_src_node *); +static int pf_state_compare_lan_ext(struct pf_state *, + struct pf_state *); +static int pf_state_compare_ext_gwy(struct pf_state *, + struct pf_state *); +static int pf_state_compare_id(struct pf_state *, + struct pf_state *); +static int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *); +#endif struct pf_src_tree tree_src_tracking; struct pf_state_tree_id tree_id; -struct pf_state_queue state_list; +struct pf_state_queue state_updates; RB_GENERATE(pf_src_tree, pf_src_node, entry, pf_src_compare); RB_GENERATE(pf_state_tree_lan_ext, pf_state, @@ -301,8 +392,14 @@ 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); +#ifdef __FreeBSD__ +static int +#else static __inline int +#endif pf_src_compare(struct pf_src_node *a, struct pf_src_node *b) { int diff; @@ -346,7 +443,11 @@ pf_src_compare(struct pf_src_node *a, struct pf_src_node *b) return (0); } +#ifdef __FreeBSD__ +static int +#else static __inline int +#endif pf_state_compare_lan_ext(struct pf_state *a, struct pf_state *b) { int diff; @@ -414,7 +515,11 @@ pf_state_compare_lan_ext(struct pf_state *a, struct pf_state *b) return (0); } +#ifdef __FreeBSD__ +static int +#else static __inline int +#endif pf_state_compare_ext_gwy(struct pf_state *a, struct pf_state *b) { int diff; @@ -482,7 +587,11 @@ pf_state_compare_ext_gwy(struct pf_state *a, struct pf_state *b) return (0); } +#ifdef __FreeBSD__ +static int +#else static __inline int +#endif pf_state_compare_id(struct pf_state *a, struct pf_state *b) { if (a->id > b->id) @@ -497,6 +606,18 @@ pf_state_compare_id(struct pf_state *a, struct pf_state *b) return (0); } +#ifdef __FreeBSD__ +static int +#else +static __inline int +#endif +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) @@ -518,14 +639,14 @@ pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af) #endif /* INET6 */ struct pf_state * -pf_find_state_byid(struct pf_state_cmp *key) +pf_find_state_byid(struct pf_state *key) { pf_status.fcounters[FCNT_STATE_SEARCH]++; - return (RB_FIND(pf_state_tree_id, &tree_id, (struct pf_state *)key)); + return (RB_FIND(pf_state_tree_id, &tree_id, key)); } struct pf_state * -pf_find_state_recurse(struct pfi_kif *kif, struct pf_state_cmp *key, u_int8_t tree) +pf_find_state_recurse(struct pfi_kif *kif, struct pf_state *key, u_int8_t tree) { struct pf_state *s; @@ -533,20 +654,20 @@ pf_find_state_recurse(struct pfi_kif *kif, struct pf_state_cmp *key, u_int8_t tr switch (tree) { case PF_LAN_EXT: - if ((s = RB_FIND(pf_state_tree_lan_ext, &kif->pfik_lan_ext, - (struct pf_state *)key)) != NULL) - return (s); - if ((s = RB_FIND(pf_state_tree_lan_ext, &pfi_all->pfik_lan_ext, - (struct pf_state *)key)) != NULL) - return (s); + for (; kif != NULL; kif = kif->pfik_parent) { + s = RB_FIND(pf_state_tree_lan_ext, + &kif->pfik_lan_ext, key); + if (s != NULL) + return (s); + } return (NULL); case PF_EXT_GWY: - if ((s = RB_FIND(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, - (struct pf_state *)key)) != NULL) - return (s); - if ((s = RB_FIND(pf_state_tree_ext_gwy, &pfi_all->pfik_ext_gwy, - (struct pf_state *)key)) != NULL) - return (s); + for (; kif != NULL; kif = kif->pfik_parent) { + s = RB_FIND(pf_state_tree_ext_gwy, + &kif->pfik_ext_gwy, key); + if (s != NULL) + return (s); + } return (NULL); default: panic("pf_find_state_recurse"); @@ -554,7 +675,7 @@ pf_find_state_recurse(struct pfi_kif *kif, struct pf_state_cmp *key, u_int8_t tr } struct pf_state * -pf_find_state_all(struct pf_state_cmp *key, u_int8_t tree, int *more) +pf_find_state_all(struct pf_state *key, u_int8_t tree, int *more) { struct pf_state *s, *ss = NULL; struct pfi_kif *kif; @@ -565,7 +686,7 @@ pf_find_state_all(struct pf_state_cmp *key, u_int8_t tree, int *more) case PF_LAN_EXT: TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) { s = RB_FIND(pf_state_tree_lan_ext, - &kif->pfik_lan_ext, (struct pf_state *)key); + &kif->pfik_lan_ext, key); if (s == NULL) continue; if (more == NULL) @@ -577,7 +698,7 @@ pf_find_state_all(struct pf_state_cmp *key, u_int8_t tree, int *more) case PF_EXT_GWY: TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) { s = RB_FIND(pf_state_tree_ext_gwy, - &kif->pfik_ext_gwy, (struct pf_state *)key); + &kif->pfik_ext_gwy, key); if (s == NULL) continue; if (more == NULL) @@ -628,7 +749,9 @@ pf_src_connlimit(struct pf_state **state) int bad = 0; (*state)->src_node->conn++; - (*state)->src.tcp_est = 1; +#ifdef __FreeBSD__ + (*state)->local_flags |= PFSTATE_SRC_CONN; +#endif pf_add_threshold(&(*state)->src_node->conn_rate); if ((*state)->rule.ptr->max_src_conn && @@ -831,9 +954,16 @@ pf_insert_state(struct pfi_kif *kif, struct pf_state *state) } if (RB_INSERT(pf_state_tree_id, &tree_id, state) != NULL) { if (pf_status.debug >= PF_DEBUG_MISC) { +#ifdef __FreeBSD__ + printf("pf: state insert failed: " + "id: %016llx creatorid: %08x", + (long long)be64toh(state->id), + ntohl(state->creatorid)); +#else printf("pf: state insert failed: " "id: %016llx creatorid: %08x", betoh64(state->id), ntohl(state->creatorid)); +#endif if (state->sync_flags & PFSTATE_FROMSYNC) printf(" (from sync)"); printf("\n"); @@ -842,10 +972,11 @@ pf_insert_state(struct pfi_kif *kif, struct pf_state *state) RB_REMOVE(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state); return (-1); } - TAILQ_INSERT_TAIL(&state_list, state, u.s.entry_list); + TAILQ_INSERT_HEAD(&state_updates, state, u.s.entry_updates); + pf_status.fcounters[FCNT_STATE_INSERT]++; pf_status.states++; - pfi_kif_ref(kif, PFI_KIF_REF_STATE); + pfi_attach_state(kif); #if NPFSYNC pfsync_insert_state(state); #endif @@ -853,28 +984,33 @@ pf_insert_state(struct pfi_kif *kif, struct pf_state *state) } void -pf_purge_thread(void *v) +pf_purge_timeout(void *arg) { - int nloops = 0, s; - - for (;;) { - tsleep(pf_purge_thread, PWAIT, "pftm", 1 * hz); - - s = splsoftnet(); - - /* process a fraction of the state table every second */ - pf_purge_expired_states(1 + (pf_status.states - / pf_default_rule.timeout[PFTM_INTERVAL])); +#ifdef __FreeBSD__ + struct callout *to = arg; +#else + struct timeout *to = arg; +#endif + int s; - /* purge other expired types every PFTM_INTERVAL seconds */ - if (++nloops >= pf_default_rule.timeout[PFTM_INTERVAL]) { - pf_purge_expired_fragments(); - pf_purge_expired_src_nodes(0); - nloops = 0; - } +#ifdef __FreeBSD__ + PF_LOCK(); +#endif + s = splsoftnet(); + pf_purge_expired_states(); + pf_purge_expired_fragments(); + pf_purge_expired_src_nodes(); + splx(s); +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif - splx(s); - } +#ifdef __FreeBSD__ + callout_reset(to, pf_default_rule.timeout[PFTM_INTERVAL] * hz, + pf_purge_timeout, to); +#else + timeout_add(to, pf_default_rule.timeout[PFTM_INTERVAL] * hz); +#endif } u_int32_t @@ -890,8 +1026,12 @@ pf_state_expires(const struct pf_state *state) return (time_second); if (state->timeout == PFTM_UNTIL_PACKET) return (0); - KASSERT(state->timeout != PFTM_UNLINKED); +#ifdef __FreeBSD__ + KASSERT((state->timeout < PFTM_MAX), + ("pf_state_expires: timeout > PFTM_MAX")); +#else KASSERT(state->timeout < PFTM_MAX); +#endif timeout = state->rule.ptr->timeout[state->timeout]; if (!timeout) timeout = pf_default_rule.timeout[state->timeout]; @@ -915,21 +1055,14 @@ pf_state_expires(const struct pf_state *state) } void -pf_purge_expired_src_nodes(int waslocked) +pf_purge_expired_src_nodes(void) { struct pf_src_node *cur, *next; - int locked = waslocked; 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_second) { - if (! locked) { - rw_enter_write(&pf_consistency_lock); - next = RB_NEXT(pf_src_tree, - &tree_src_tracking, cur); - locked = 1; - } if (cur->rule.ptr != NULL) { cur->rule.ptr->src_nodes--; if (cur->rule.ptr->states <= 0 && @@ -942,9 +1075,6 @@ pf_purge_expired_src_nodes(int waslocked) pool_put(&pf_src_tree_pl, cur); } } - - if (locked && !waslocked) - rw_exit_write(&pf_consistency_lock); } void @@ -954,7 +1084,12 @@ pf_src_tree_remove_state(struct pf_state *s) if (s->src_node != NULL) { if (s->proto == IPPROTO_TCP) { - if (s->src.tcp_est) +#ifdef __FreeBSD__ + if (s->local_flags & PFSTATE_SRC_CONN) +#else + if (s->src.state == PF_TCPS_PROXY_DST || + s->timeout >= PFTM_TCP_ESTABLISHED) +#endif --s->src_node->conn; } if (--s->src_node->states <= 0) { @@ -977,42 +1112,33 @@ pf_src_tree_remove_state(struct pf_state *s) s->src_node = s->nat_src_node = NULL; } -/* callers should be at splsoftnet */ void -pf_unlink_state(struct pf_state *cur) +pf_purge_expired_state(struct pf_state *cur) { - if (cur->src.state == PF_TCPS_PROXY_DST) { +#ifdef __FreeBSD__ + if (cur->local_flags & PFSTATE_EXPIRING) + return; + cur->local_flags |= PFSTATE_EXPIRING; +#endif + if (cur->src.state == PF_TCPS_PROXY_DST) +#ifdef __FreeBSD__ + pf_send_tcp(NULL, cur->rule.ptr, cur->af, +#else pf_send_tcp(cur->rule.ptr, cur->af, +#endif &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, cur->tag, NULL, NULL); - } + 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 - if (cur->creatorid == pf_status.hostid) - pfsync_delete_state(cur); + pfsync_delete_state(cur); #endif - cur->timeout = PFTM_UNLINKED; pf_src_tree_remove_state(cur); -} - -/* callers should be at splsoftnet and hold the - * write_lock on pf_consistency_lock */ -void -pf_free_state(struct pf_state *cur) -{ -#if NPFSYNC - if (pfsyncif != NULL && - (pfsyncif->sc_bulk_send_next == cur || - pfsyncif->sc_bulk_terminator == cur)) - return; -#endif - KASSERT(cur->timeout == PFTM_UNLINKED); if (--cur->rule.ptr->states <= 0 && cur->rule.ptr->src_nodes <= 0) pf_rm_rule(NULL, cur->rule.ptr); @@ -1024,8 +1150,8 @@ pf_free_state(struct pf_state *cur) if (--cur->anchor.ptr->states <= 0) pf_rm_rule(NULL, cur->anchor.ptr); pf_normalize_tcp_cleanup(cur); - pfi_kif_unref(cur->u.s.kif, PFI_KIF_REF_STATE); - TAILQ_REMOVE(&state_list, cur, u.s.entry_list); + pfi_detach_state(cur->u.s.kif); + TAILQ_REMOVE(&state_updates, cur, u.s.entry_updates); if (cur->tag) pf_tag_unref(cur->tag); pool_put(&pf_state_pl, cur); @@ -1034,44 +1160,16 @@ pf_free_state(struct pf_state *cur) } void -pf_purge_expired_states(u_int32_t maxcheck) +pf_purge_expired_states(void) { - static struct pf_state *cur = NULL; - struct pf_state *next; - int locked = 0; - - while (maxcheck--) { - /* wrap to start of list when we hit the end */ - if (cur == NULL) { - cur = TAILQ_FIRST(&state_list); - if (cur == NULL) - break; /* list empty */ - } - - /* get next state, as cur may get deleted */ - next = TAILQ_NEXT(cur, u.s.entry_list); - - if (cur->timeout == PFTM_UNLINKED) { - /* free unlinked state */ - if (! locked) { - rw_enter_write(&pf_consistency_lock); - locked = 1; - } - pf_free_state(cur); - } else if (pf_state_expires(cur) <= time_second) { - /* unlink and free expired state */ - pf_unlink_state(cur); - if (! locked) { - rw_enter_write(&pf_consistency_lock); - locked = 1; - } - pf_free_state(cur); - } - cur = next; - } + struct pf_state *cur, *next; - if (locked) - rw_exit_write(&pf_consistency_lock); + 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_second) + pf_purge_expired_state(cur); + } } int @@ -1297,12 +1395,9 @@ pf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2) case PF_ADDR_DYNIFTL: return (aw1->p.dyn->pfid_kt != aw2->p.dyn->pfid_kt); case PF_ADDR_NOROUTE: - case PF_ADDR_URPFFAILED: return (0); case PF_ADDR_TABLE: return (aw1->p.tbl != aw2->p.tbl); - case PF_ADDR_RTLABEL: - return (aw1->v.rtlabel != aw2->v.rtlabel); default: printf("invalid address type: %d\n", aw1->type); return (1); @@ -1417,7 +1512,7 @@ pf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa, /* Change inner protocol port, fix inner protocol checksum. */ if (ip != NULL) { u_int16_t oip = *ip; - u_int32_t opc; + u_int32_t opc = 0; /* make the compiler happy */ if (pc != NULL) opc = *pc; @@ -1489,82 +1584,27 @@ pf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa, } } - -/* - * Need to modulate the sequence numbers in the TCP SACK option - * (credits to Krzysztof Pfaff for report and patch) - */ -int -pf_modulate_sack(struct mbuf *m, int off, struct pf_pdesc *pd, - struct tcphdr *th, struct pf_state_peer *dst) -{ - int hlen = (th->th_off << 2) - sizeof(*th), thoptlen = hlen; - u_int8_t opts[MAX_TCPOPTLEN], *opt = opts; - int copyback = 0, i, olen; - struct sackblk sack; - -#define TCPOLEN_SACKLEN (TCPOLEN_SACK + 2) - if (hlen < TCPOLEN_SACKLEN || - !pf_pull_hdr(m, off + sizeof(*th), opts, hlen, NULL, NULL, pd->af)) - return 0; - - while (hlen >= TCPOLEN_SACKLEN) { - olen = opt[1]; - switch (*opt) { - case TCPOPT_EOL: /* FALLTHROUGH */ - case TCPOPT_NOP: - opt++; - hlen--; - break; - case TCPOPT_SACK: - if (olen > hlen) - olen = hlen; - if (olen >= TCPOLEN_SACKLEN) { - for (i = 2; i + TCPOLEN_SACK <= olen; - i += TCPOLEN_SACK) { - memcpy(&sack, &opt[i], sizeof(sack)); - pf_change_a(&sack.start, &th->th_sum, - htonl(ntohl(sack.start) - - dst->seqdiff), 0); - pf_change_a(&sack.end, &th->th_sum, - htonl(ntohl(sack.end) - - dst->seqdiff), 0); - memcpy(&opt[i], &sack, sizeof(sack)); - } - copyback = 1; - } - /* FALLTHROUGH */ - default: - if (olen < 2) - olen = 2; - hlen -= olen; - opt += olen; - } - } - - if (copyback) - m_copyback(m, off + sizeof(*th), thoptlen, opts); - return (copyback); -} - void +#ifdef __FreeBSD__ +pf_send_tcp(struct mbuf *replyto, const struct pf_rule *r, sa_family_t af, +#else pf_send_tcp(const struct pf_rule *r, sa_family_t af, +#endif 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, int tag, - u_int16_t rtag, struct ether_header *eh, struct ifnet *ifp) + struct ether_header *eh, struct ifnet *ifp) { struct mbuf *m; - int len, tlen; + int len = 0, tlen; /* make the compiler happy */ #ifdef INET - struct ip *h; + struct ip *h = NULL; /* make the compiler happy */ #endif /* INET */ #ifdef INET6 - struct ip6_hdr *h6; + struct ip6_hdr *h6 = NULL; /* make the compiler happy */ #endif /* INET6 */ - struct tcphdr *th; - char *opt; - struct pf_mtag *pf_mtag; + struct tcphdr *th = NULL; /* make the compiler happy */ + char *opt; /* maximum segment size tcp option */ tlen = sizeof(struct tcphdr); @@ -1588,24 +1628,44 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, m = m_gethdr(M_DONTWAIT, MT_HEADER); if (m == NULL) return; - if ((pf_mtag = pf_get_mtag(m)) == NULL) { - m_freem(m); - return; - } - if (tag) - pf_mtag->flags |= PF_TAG_GENERATED; - - pf_mtag->tag = rtag; - - if (r != NULL && r->rtableid >= 0) - pf_mtag->rtableid = r->rtableid; +#ifdef __FreeBSD__ +#ifdef MAC + if (replyto) + mac_create_mbuf_netlayer(replyto, m); + else + mac_create_mbuf_from_firewall(m); +#else + (void)replyto; +#endif +#endif + if (tag) { +#ifdef __FreeBSD__ + m->m_flags |= M_SKIP_FIREWALL; +#else + 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); +#endif + } #ifdef ALTQ if (r != NULL && r->qid) { - pf_mtag->qid = r->qid; - /* add hints for ecn */ - pf_mtag->af = af; - pf_mtag->hdr = mtod(m, struct ip *); + struct m_tag *mtag; + struct altq_tag *atag; + + mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT); + if (mtag != NULL) { + atag = (struct altq_tag *)(mtag + 1); + atag->qid = r->qid; + /* add hints for ecn */ + atag->af = af; + atag->hdr = mtod(m, struct ip *); + m_tag_prepend(m, mtag); + } } #endif /* ALTQ */ m->m_data += max_linkhdr; @@ -1668,13 +1728,25 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, h->ip_v = 4; h->ip_hl = sizeof(*h) >> 2; h->ip_tos = IPTOS_LOWDELAY; - h->ip_len = htons(len); +#ifdef __FreeBSD__ + h->ip_off = path_mtu_discovery ? IP_DF : 0; + h->ip_len = len; +#else h->ip_off = htons(ip_mtudisc ? IP_DF : 0); + h->ip_len = htons(len); +#endif h->ip_ttl = ttl ? ttl : ip_defttl; h->ip_sum = 0; if (eh == NULL) { +#ifdef __FreeBSD__ + PF_UNLOCK(); ip_output(m, (void *)NULL, (void *)NULL, 0, (void *)NULL, (void *)NULL); + PF_LOCK(); +#else /* ! __FreeBSD__ */ + ip_output(m, (void *)NULL, (void *)NULL, 0, + (void *)NULL, (void *)NULL); +#endif } else { struct route ro; struct rtentry rt; @@ -1691,8 +1763,16 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, 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; +#ifdef __FreeBSD__ + PF_UNLOCK(); + /* XXX_IMPORT: later */ + ip_output(m, (void *)NULL, &ro, 0, + (void *)NULL, (void *)NULL); + PF_LOCK(); +#else /* ! __FreeBSD__ */ ip_output(m, (void *)NULL, &ro, IP_ROUTETOETHER, (void *)NULL, (void *)NULL); +#endif } break; #endif /* INET */ @@ -1705,7 +1785,13 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, h6->ip6_vfc |= IPV6_VERSION; h6->ip6_hlim = IPV6_DEFHLIM; +#ifdef __FreeBSD__ + PF_UNLOCK(); + ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); + PF_LOCK(); +#else ip6_output(m, NULL, NULL, 0, NULL, NULL); +#endif break; #endif /* INET6 */ } @@ -1715,36 +1801,72 @@ void pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af, struct pf_rule *r) { - struct pf_mtag *pf_mtag; +#ifdef ALTQ + struct m_tag *mtag; +#endif struct mbuf *m0; +#ifdef __FreeBSD__ + struct ip *ip; +#endif +#ifdef __FreeBSD__ + m0 = m_copypacket(m, M_DONTWAIT); + if (m0 == NULL) + return; + m0->m_flags |= M_SKIP_FIREWALL; +#else + mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT); + if (mtag == NULL) + return; m0 = m_copy(m, 0, M_COPYALL); - - if ((pf_mtag = pf_get_mtag(m0)) == NULL) + if (m0 == NULL) { + m_tag_free(mtag); return; - pf_mtag->flags |= PF_TAG_GENERATED; - - if (r->rtableid >= 0) - pf_mtag->rtableid = r->rtableid; + } + m_tag_prepend(m0, mtag); +#endif #ifdef ALTQ if (r->qid) { - pf_mtag->qid = r->qid; - /* add hints for ecn */ - pf_mtag->af = af; - pf_mtag->hdr = mtod(m0, struct ip *); + struct altq_tag *atag; + + mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT); + if (mtag != NULL) { + atag = (struct altq_tag *)(mtag + 1); + atag->qid = r->qid; + /* add hints for ecn */ + atag->af = af; + atag->hdr = mtod(m0, struct ip *); + m_tag_prepend(m0, mtag); + } } #endif /* ALTQ */ switch (af) { #ifdef INET case AF_INET: +#ifdef __FreeBSD__ + /* icmp_error() expects host byte ordering */ + ip = mtod(m0, struct ip *); + NTOHS(ip->ip_len); + NTOHS(ip->ip_off); + PF_UNLOCK(); icmp_error(m0, type, code, 0, 0); + PF_LOCK(); +#else + icmp_error(m0, type, code, 0, (void *)NULL); +#endif break; #endif /* INET */ #ifdef INET6 case AF_INET6: +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif icmp6_error(m0, type, code, 0); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif break; #endif /* INET6 */ } @@ -1847,71 +1969,58 @@ pf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g) return (pf_match(op, a1, a2, g)); } -struct pf_mtag * -pf_find_mtag(struct mbuf *m) +struct pf_tag * +pf_get_tag(struct mbuf *m) { struct m_tag *mtag; - if ((mtag = m_tag_find(m, PACKET_TAG_PF, NULL)) == NULL) + if ((mtag = m_tag_find(m, PACKET_TAG_PF_TAG, NULL)) != NULL) + return ((struct pf_tag *)(mtag + 1)); + else return (NULL); - - return ((struct pf_mtag *)(mtag + 1)); -} - -struct pf_mtag * -pf_get_mtag(struct mbuf *m) -{ - struct m_tag *mtag; - - if ((mtag = m_tag_find(m, PACKET_TAG_PF, NULL)) == NULL) { - mtag = m_tag_get(PACKET_TAG_PF, sizeof(struct pf_mtag), - M_NOWAIT); - if (mtag == NULL) - return (NULL); - bzero(mtag + 1, sizeof(struct pf_mtag)); - m_tag_prepend(m, mtag); - } - - return ((struct pf_mtag *)(mtag + 1)); } int -pf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_mtag *pf_mtag, - int *tag) +pf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_tag **pftag, int *tag) { - if (*tag == -1) - *tag = pf_mtag->tag; + if (*tag == -1) { /* find mbuf tag */ + *pftag = pf_get_tag(m); + if (*pftag != NULL) + *tag = (*pftag)->tag; + else + *tag = 0; + } return ((!r->match_tag_not && r->match_tag == *tag) || (r->match_tag_not && r->match_tag != *tag)); } int -pf_tag_packet(struct mbuf *m, struct pf_mtag *pf_mtag, int tag, int rtableid) +pf_tag_packet(struct mbuf *m, struct pf_tag *pftag, int tag) { - if (tag <= 0 && rtableid < 0) + struct m_tag *mtag; + + if (tag <= 0) return (0); - if (pf_mtag == NULL) - if ((pf_mtag = pf_get_mtag(m)) == NULL) + if (pftag == NULL) { + mtag = m_tag_get(PACKET_TAG_PF_TAG, sizeof(*pftag), M_NOWAIT); + if (mtag == NULL) return (1); - if (tag > 0) - pf_mtag->tag = tag; - if (rtableid >= 0) - pf_mtag->rtableid = rtableid; + ((struct pf_tag *)(mtag + 1))->tag = tag; + m_tag_prepend(m, mtag); + } else + pftag->tag = tag; return (0); } static void pf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n, - struct pf_rule **r, struct pf_rule **a, int *match) + struct pf_rule **r, struct pf_rule **a) { struct pf_anchor_stackframe *f; - (*r)->anchor->match = 0; - if (match) - *match = 0; if (*depth >= sizeof(pf_anchor_stack) / sizeof(pf_anchor_stack[0])) { printf("pf_step_into_anchor: stack overflow\n"); @@ -1938,23 +2047,17 @@ pf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n, *r = TAILQ_FIRST((*rs)->rules[n].active.ptr); } -int +static void pf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n, - struct pf_rule **r, struct pf_rule **a, int *match) + struct pf_rule **r, struct pf_rule **a) { struct pf_anchor_stackframe *f; - int quick = 0; do { if (*depth <= 0) break; f = pf_anchor_stack + *depth - 1; if (f->parent != NULL && f->child != NULL) { - if (f->child->match || - (match != NULL && *match)) { - f->r->anchor->match = 1; - *match = 0; - } f->child = RB_NEXT(pf_anchor_node, f->parent, f->child); if (f->child != NULL) { *rs = &f->child->ruleset; @@ -1969,12 +2072,8 @@ pf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n, if (*depth == 0 && a != NULL) *a = NULL; *rs = f->rs; - if (f->r->anchor->match || (match != NULL && *match)) - quick = f->r->quick; *r = TAILQ_NEXT(f->r, entries); } while (*r == NULL); - - return (quick); } #ifdef INET6 @@ -2278,7 +2377,7 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high, struct pf_src_node **sn) { - struct pf_state_cmp key; + struct pf_state key; struct pf_addr init_addr; u_int16_t cut; @@ -2370,8 +2469,8 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off, { struct pf_rule *r, *rm = NULL; struct pf_ruleset *ruleset = NULL; + struct pf_tag *pftag = NULL; int tag = -1; - int rtableid = -1; int asd = 0; r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr); @@ -2389,7 +2488,8 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off, } r->evaluations++; - if (pfi_kif_match(r->kif, kif) == r->ifnot) + if (r->kif != NULL && + (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR].ptr; @@ -2397,8 +2497,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->neg, kif)) + 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, @@ -2406,16 +2505,15 @@ 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->neg, NULL)) + 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, NULL)) + else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af, 0)) r = TAILQ_NEXT(r, entries); else if (dst != NULL && dst->port_op && !pf_match_port(dst->port_op, dst->port[0], dst->port[1], dport)) r = r->skip[PF_SKIP_DST_PORT].ptr; - else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag)) + else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag)) r = TAILQ_NEXT(r, entries); else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto != IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m, @@ -2424,19 +2522,15 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off, else { if (r->tag) tag = r->tag; - if (r->rtableid >= 0) - rtableid = r->rtableid; if (r->anchor == NULL) { rm = r; } else - pf_step_into_anchor(&asd, &ruleset, rs_num, - &r, NULL, NULL); + pf_step_into_anchor(&asd, &ruleset, rs_num, &r, NULL); } if (r == NULL) - pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r, - NULL, NULL); + pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r, NULL); } - if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) + if (pf_tag_packet(m, pftag, tag)) return (NULL); if (rm != NULL && (rm->action == PF_NONAT || rm->action == PF_NORDR || rm->action == PF_NOBINAT)) @@ -2596,35 +2690,56 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, } int -pf_socket_lookup(int direction, struct pf_pdesc *pd) +#ifdef __FreeBSD__ +pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd, + struct inpcb *inp_arg) +#else +pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd) +#endif { struct pf_addr *saddr, *daddr; u_int16_t sport, dport; +#ifdef __FreeBSD__ + struct inpcbinfo *pi; +#else struct inpcbtable *tb; +#endif struct inpcb *inp; - if (pd == NULL) - return (-1); - pd->lookup.uid = UID_MAX; - pd->lookup.gid = GID_MAX; - pd->lookup.pid = NO_PID; + *uid = UID_MAX; + *gid = GID_MAX; +#ifdef __FreeBSD__ + if (inp_arg != NULL) { + INP_LOCK_ASSERT(inp_arg); + if (inp_arg->inp_socket) { + *uid = inp_arg->inp_socket->so_cred->cr_uid; + *gid = inp_arg->inp_socket->so_cred->cr_groups[0]; + return (1); + } else + return (0); + } +#endif switch (pd->proto) { case IPPROTO_TCP: - if (pd->hdr.tcp == NULL) - return (-1); sport = pd->hdr.tcp->th_sport; dport = pd->hdr.tcp->th_dport; +#ifdef __FreeBSD__ + pi = &tcbinfo; +#else tb = &tcbtable; +#endif break; case IPPROTO_UDP: - if (pd->hdr.udp == NULL) - return (-1); sport = pd->hdr.udp->uh_sport; dport = pd->hdr.udp->uh_dport; +#ifdef __FreeBSD__ + pi = &udbinfo; +#else tb = &udbtable; +#endif break; default: - return (-1); + return (0); } if (direction == PF_IN) { saddr = pd->src; @@ -2641,32 +2756,72 @@ pf_socket_lookup(int direction, struct pf_pdesc *pd) switch (pd->af) { #ifdef INET case AF_INET: +#ifdef __FreeBSD__ + INP_INFO_RLOCK(pi); /* XXX LOR */ + inp = in_pcblookup_hash(pi, saddr->v4, sport, daddr->v4, + dport, 0, NULL); + if (inp == NULL) { + inp = in_pcblookup_hash(pi, saddr->v4, sport, + daddr->v4, dport, INPLOOKUP_WILDCARD, NULL); + if(inp == NULL) { + INP_INFO_RUNLOCK(pi); + return (0); + } + } +#else inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport); if (inp == NULL) { inp = in_pcblookup_listen(tb, daddr->v4, dport, 0); if (inp == NULL) - return (-1); + return (0); } +#endif break; #endif /* INET */ #ifdef INET6 case AF_INET6: +#ifdef __FreeBSD__ + INP_INFO_RLOCK(pi); + inp = in6_pcblookup_hash(pi, &saddr->v6, sport, + &daddr->v6, dport, 0, NULL); + if (inp == NULL) { + inp = in6_pcblookup_hash(pi, &saddr->v6, sport, + &daddr->v6, dport, INPLOOKUP_WILDCARD, NULL); + if (inp == NULL) { + INP_INFO_RUNLOCK(pi); + return (0); + } + } +#else inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6, dport); if (inp == NULL) { inp = in6_pcblookup_listen(tb, &daddr->v6, dport, 0); if (inp == NULL) - return (-1); + return (0); } +#endif break; #endif /* INET6 */ default: - return (-1); + return (0); } - pd->lookup.uid = inp->inp_socket->so_euid; - pd->lookup.gid = inp->inp_socket->so_egid; - pd->lookup.pid = inp->inp_socket->so_cpid; +#ifdef __FreeBSD__ + INP_LOCK(inp); + if ((inp->inp_socket == NULL) || (inp->inp_socket->so_cred == NULL)) { + INP_UNLOCK(inp); + INP_INFO_RUNLOCK(pi); + return (0); + } + *uid = inp->inp_socket->so_cred->cr_uid; + *gid = inp->inp_socket->so_cred->cr_groups[0]; + INP_UNLOCK(inp); + INP_INFO_RUNLOCK(pi); +#else + *uid = inp->inp_socket->so_euid; + *gid = inp->inp_socket->so_egid; +#endif return (1); } @@ -2760,7 +2915,7 @@ pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer) struct route_in6 ro6; #endif /* INET6 */ struct rtentry *rt = NULL; - int hlen; + int hlen = 0; /* make the compiler happy */ u_int16_t mss = tcp_mssdflt; switch (af) { @@ -2772,7 +2927,15 @@ pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer) dst->sin_family = AF_INET; dst->sin_len = sizeof(*dst); dst->sin_addr = addr->v4; +#ifdef __FreeBSD__ +#ifdef RTF_PRCLONING + rtalloc_ign(&ro, (RTF_CLONING | RTF_PRCLONING)); +#else /* !RTF_PRCLONING */ + rtalloc_ign(&ro, RTF_CLONING); +#endif +#else /* ! __FreeBSD__ */ rtalloc_noclone(&ro, NO_CLONING); +#endif rt = ro.ro_rt; break; #endif /* INET */ @@ -2784,7 +2947,16 @@ pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer) dst6->sin6_family = AF_INET6; dst6->sin6_len = sizeof(*dst6); dst6->sin6_addr = addr->v6; +#ifdef __FreeBSD__ +#ifdef RTF_PRCLONING + rtalloc_ign((struct route *)&ro6, + (RTF_CLONING | RTF_PRCLONING)); +#else /* !RTF_PRCLONING */ + rtalloc_ign((struct route *)&ro6, RTF_CLONING); +#endif +#else /* ! __FreeBSD__ */ rtalloc_noclone((struct route *)&ro6, NO_CLONING); +#endif rt = ro6.ro_rt; break; #endif /* INET6 */ @@ -2829,29 +3001,43 @@ 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, +#ifdef __FreeBSD__ + struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, + struct ifqueue *ifq, struct inpcb *inp) +#else struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, struct ifqueue *ifq) +#endif { struct pf_rule *nr = NULL; struct pf_addr *saddr = pd->src, *daddr = pd->dst; struct tcphdr *th = pd->hdr.tcp; u_int16_t bport, nport = 0; sa_family_t af = pd->af; + int lookup = -1; + uid_t uid; + gid_t gid; struct pf_rule *r, *a = NULL; struct pf_ruleset *ruleset = NULL; struct pf_src_node *nsn = NULL; u_short reason; int rewrite = 0; - int tag = -1, rtableid = -1; + struct pf_tag *pftag = NULL; + int tag = -1; u_int16_t mss = tcp_mssdflt; int asd = 0; - int match = 0; if (pf_check_congestion(ifq)) { REASON_SET(&reason, PFRES_CONGEST); return (PF_DROP); } +#if defined(__FreeBSD__) && defined(PF_MPSAFE_UGID) + PF_UNLOCK(); + lookup = pf_socket_lookup(&uid, &gid, direction, pd, inp); + PF_LOCK(); +#endif + r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); if (direction == PF_OUT) { @@ -2886,7 +3072,8 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, while (r != NULL) { r->evaluations++; - if (pfi_kif_match(r->kif, kif) == r->ifnot) + if (r->kif != NULL && + (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR].ptr; @@ -2894,37 +3081,43 @@ 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.neg, kif)) + 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.neg, NULL)) + 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)) r = r->skip[PF_SKIP_DST_PORT].ptr; - else if (r->tos && !(r->tos == pd->tos)) + else if (r->tos && !(r->tos & pd->tos)) r = TAILQ_NEXT(r, entries); else if (r->rule_flag & PFRULE_FRAGMENT) r = TAILQ_NEXT(r, entries); else if ((r->flagset & th->th_flags) != r->flags) r = TAILQ_NEXT(r, entries); - else if (r->uid.op && (pd->lookup.done || (pd->lookup.done = - pf_socket_lookup(direction, pd), 1)) && + else if (r->uid.op && (lookup != -1 || (lookup = +#ifdef __FreeBSD__ + pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) && +#else + pf_socket_lookup(&uid, &gid, direction, pd), 1)) && +#endif !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1], - pd->lookup.uid)) + uid)) r = TAILQ_NEXT(r, entries); - else if (r->gid.op && (pd->lookup.done || (pd->lookup.done = - pf_socket_lookup(direction, pd), 1)) && + else if (r->gid.op && (lookup != -1 || (lookup = +#ifdef __FreeBSD__ + pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) && +#else + pf_socket_lookup(&uid, &gid, direction, pd), 1)) && +#endif !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1], - pd->lookup.gid)) + gid)) r = TAILQ_NEXT(r, entries); else if (r->prob && r->prob <= arc4random()) r = TAILQ_NEXT(r, entries); - else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag)) + else if (r->match_tag && !pf_match_tag(m, r, &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)) @@ -2932,10 +3125,7 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, else { if (r->tag) tag = r->tag; - if (r->rtableid >= 0) - rtableid = r->rtableid; if (r->anchor == NULL) { - match = 1; *rm = r; *am = a; *rsm = ruleset; @@ -2944,11 +3134,11 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, r = TAILQ_NEXT(r, entries); } else pf_step_into_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match); + PF_RULESET_FILTER, &r, &a); } - if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match)) - break; + if (r == NULL) + pf_step_out_of_anchor(&asd, &ruleset, + PF_RULESET_FILTER, &r, &a); } r = *rm; a = *am; @@ -2956,11 +3146,10 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_MATCH); - if (r->log || (nr != NULL && nr->natpass && nr->log)) { + if (r->log) { if (rewrite) - m_copyback(m, off, sizeof(*th), th); - PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr, - a, ruleset, pd); + m_copyback(m, off, sizeof(*th), (caddr_t)th); + PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset); } if ((r->action == PF_DROP) && @@ -2988,10 +3177,14 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, ack++; if (th->th_flags & TH_FIN) ack++; +#ifdef __FreeBSD__ + pf_send_tcp(m, r, af, pd->dst, +#else pf_send_tcp(r, af, pd->dst, +#endif pd->src, th->th_dport, th->th_sport, ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0, - r->return_ttl, 1, 0, pd->eh, kif->pfik_ifp); + 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); @@ -3003,7 +3196,7 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, if (r->action == PF_DROP) return (PF_DROP); - if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) { + if (pf_tag_packet(m, pftag, tag)) { REASON_SET(&reason, PFRES_MEMORY); return (PF_DROP); } @@ -3023,7 +3216,7 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_MAXSTATES); goto cleanup; } - /* src node for filter rule */ + /* src node for flter rule */ if ((r->rule_flag & PFRULE_SRCTRACK || r->rpool.opts & PF_POOL_STICKYADDR) && pf_insert_src_node(&sn, r, saddr, af) != 0) { @@ -3063,9 +3256,7 @@ cleanup: s->anchor.ptr = a; STATE_INC_COUNTERS(s); s->allow_opts = r->allow_opts; - s->log = r->log & PF_LOG_ALL; - if (nr != NULL) - s->log |= nr->log & PF_LOG_ALL; + s->log = r->log & 2; s->proto = IPPROTO_TCP; s->direction = direction; s->af = af; @@ -3100,8 +3291,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 = - tcp_rndiss_next() - s->src.seqlo) == 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); @@ -3192,9 +3382,13 @@ cleanup: mss = pf_calc_mss(saddr, af, mss); mss = pf_calc_mss(daddr, af, mss); s->src.mss = mss; +#ifdef __FreeBSD__ + pf_send_tcp(NULL, r, af, daddr, saddr, th->th_dport, +#else pf_send_tcp(r, af, daddr, saddr, th->th_dport, +#endif th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1, - TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL, NULL); + TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, NULL, NULL); REASON_SET(&reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); } @@ -3202,7 +3396,7 @@ cleanup: /* copy back packet headers if we performed NAT operations */ if (rewrite) - m_copyback(m, off, sizeof(*th), th); + m_copyback(m, off, sizeof(*th), (caddr_t)th); return (PF_PASS); } @@ -3210,28 +3404,42 @@ 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, +#ifdef __FreeBSD__ + struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, + struct ifqueue *ifq, struct inpcb *inp) +#else struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, struct ifqueue *ifq) +#endif { struct pf_rule *nr = NULL; struct pf_addr *saddr = pd->src, *daddr = pd->dst; struct udphdr *uh = pd->hdr.udp; u_int16_t bport, nport = 0; sa_family_t af = pd->af; + int lookup = -1; + uid_t uid; + gid_t gid; struct pf_rule *r, *a = NULL; struct pf_ruleset *ruleset = NULL; struct pf_src_node *nsn = NULL; u_short reason; int rewrite = 0; - int tag = -1, rtableid = -1; + struct pf_tag *pftag = NULL; + int tag = -1; int asd = 0; - int match = 0; if (pf_check_congestion(ifq)) { REASON_SET(&reason, PFRES_CONGEST); return (PF_DROP); } +#if defined(__FreeBSD__) && defined(PF_MPSAFE_UGID) + PF_UNLOCK(); + lookup = pf_socket_lookup(&uid, &gid, direction, pd, inp); + PF_LOCK(); +#endif + r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); if (direction == PF_OUT) { @@ -3266,7 +3474,8 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, while (r != NULL) { r->evaluations++; - if (pfi_kif_match(r->kif, kif) == r->ifnot) + if (r->kif != NULL && + (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR].ptr; @@ -3274,45 +3483,48 @@ 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.neg, kif)) + 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.neg, NULL)) + 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)) r = r->skip[PF_SKIP_DST_PORT].ptr; - else if (r->tos && !(r->tos == pd->tos)) + else if (r->tos && !(r->tos & pd->tos)) r = TAILQ_NEXT(r, entries); else if (r->rule_flag & PFRULE_FRAGMENT) r = TAILQ_NEXT(r, entries); - else if (r->uid.op && (pd->lookup.done || (pd->lookup.done = - pf_socket_lookup(direction, pd), 1)) && + else if (r->uid.op && (lookup != -1 || (lookup = +#ifdef __FreeBSD__ + pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) && +#else + pf_socket_lookup(&uid, &gid, direction, pd), 1)) && +#endif !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1], - pd->lookup.uid)) + uid)) r = TAILQ_NEXT(r, entries); - else if (r->gid.op && (pd->lookup.done || (pd->lookup.done = - pf_socket_lookup(direction, pd), 1)) && + else if (r->gid.op && (lookup != -1 || (lookup = +#ifdef __FreeBSD__ + pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) && +#else + pf_socket_lookup(&uid, &gid, direction, pd), 1)) && +#endif !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1], - pd->lookup.gid)) + gid)) r = TAILQ_NEXT(r, entries); else if (r->prob && r->prob <= arc4random()) r = TAILQ_NEXT(r, entries); - else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag)) + else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag)) r = TAILQ_NEXT(r, entries); else if (r->os_fingerprint != PF_OSFP_ANY) r = TAILQ_NEXT(r, entries); else { if (r->tag) tag = r->tag; - if (r->rtableid >= 0) - rtableid = r->rtableid; if (r->anchor == NULL) { - match = 1; *rm = r; *am = a; *rsm = ruleset; @@ -3321,11 +3533,11 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, r = TAILQ_NEXT(r, entries); } else pf_step_into_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match); + PF_RULESET_FILTER, &r, &a); } - if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match)) - break; + if (r == NULL) + pf_step_out_of_anchor(&asd, &ruleset, + PF_RULESET_FILTER, &r, &a); } r = *rm; a = *am; @@ -3333,11 +3545,10 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_MATCH); - if (r->log || (nr != NULL && nr->natpass && nr->log)) { + if (r->log) { if (rewrite) - m_copyback(m, off, sizeof(*uh), uh); - PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr, - a, ruleset, pd); + m_copyback(m, off, sizeof(*uh), (caddr_t)uh); + PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset); } if ((r->action == PF_DROP) && @@ -3366,7 +3577,7 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, if (r->action == PF_DROP) return (PF_DROP); - if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) { + if (pf_tag_packet(m, pftag, tag)) { REASON_SET(&reason, PFRES_MEMORY); return (PF_DROP); } @@ -3382,7 +3593,7 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_MAXSTATES); goto cleanup; } - /* src node for filter rule */ + /* src node for flter rule */ if ((r->rule_flag & PFRULE_SRCTRACK || r->rpool.opts & PF_POOL_STICKYADDR) && pf_insert_src_node(&sn, r, saddr, af) != 0) { @@ -3422,9 +3633,7 @@ cleanup: s->anchor.ptr = a; STATE_INC_COUNTERS(s); s->allow_opts = r->allow_opts; - s->log = r->log & PF_LOG_ALL; - if (nr != NULL) - s->log |= nr->log & PF_LOG_ALL; + s->log = r->log & 2; s->proto = IPPROTO_UDP; s->direction = direction; s->af = af; @@ -3484,7 +3693,7 @@ cleanup: /* copy back packet headers if we performed NAT operations */ if (rewrite) - m_copyback(m, off, sizeof(*uh), uh); + m_copyback(m, off, sizeof(*uh), (caddr_t)uh); return (PF_PASS); } @@ -3501,16 +3710,17 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, struct pf_ruleset *ruleset = NULL; struct pf_src_node *nsn = NULL; u_short reason; - u_int16_t icmpid, bport, nport = 0; + u_int16_t icmpid = 0, bport, nport = 0; sa_family_t af = pd->af; - u_int8_t icmptype, icmpcode; + u_int8_t icmptype = 0; /* make the compiler happy */ + u_int8_t icmpcode = 0; /* make the compiler happy */ int state_icmp = 0; - int tag = -1, rtableid = -1; + struct pf_tag *pftag = NULL; + int tag = -1; #ifdef INET6 int rewrite = 0; #endif /* INET6 */ int asd = 0; - int match = 0; if (pf_check_congestion(ifq)) { REASON_SET(&reason, PFRES_CONGEST); @@ -3564,7 +3774,8 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, pd->hdr.icmp->icmp_cksum = pf_cksum_fixup( pd->hdr.icmp->icmp_cksum, icmpid, nport, 0); pd->hdr.icmp->icmp_id = nport; - m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp); + m_copyback(m, off, ICMP_MINLEN, + (caddr_t)pd->hdr.icmp); break; #endif /* INET */ #ifdef INET6 @@ -3609,7 +3820,8 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, while (r != NULL) { r->evaluations++; - if (pfi_kif_match(r->kif, kif) == r->ifnot) + if (r->kif != NULL && + (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR].ptr; @@ -3617,33 +3829,28 @@ 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.neg, kif)) + 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.neg, NULL)) + 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); else if (r->code && r->code != icmpcode + 1) r = TAILQ_NEXT(r, entries); - else if (r->tos && !(r->tos == pd->tos)) + else if (r->tos && !(r->tos & pd->tos)) r = TAILQ_NEXT(r, entries); else if (r->rule_flag & PFRULE_FRAGMENT) r = TAILQ_NEXT(r, entries); else if (r->prob && r->prob <= arc4random()) r = TAILQ_NEXT(r, entries); - else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag)) + else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag)) r = TAILQ_NEXT(r, entries); else if (r->os_fingerprint != PF_OSFP_ANY) r = TAILQ_NEXT(r, entries); else { if (r->tag) tag = r->tag; - if (r->rtableid >= 0) - rtableid = r->rtableid; if (r->anchor == NULL) { - match = 1; *rm = r; *am = a; *rsm = ruleset; @@ -3652,11 +3859,11 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, r = TAILQ_NEXT(r, entries); } else pf_step_into_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match); + PF_RULESET_FILTER, &r, &a); } - if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match)) - break; + if (r == NULL) + pf_step_out_of_anchor(&asd, &ruleset, + PF_RULESET_FILTER, &r, &a); } r = *rm; a = *am; @@ -3664,20 +3871,19 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_MATCH); - if (r->log || (nr != NULL && nr->natpass && nr->log)) { + if (r->log) { #ifdef INET6 if (rewrite) m_copyback(m, off, sizeof(struct icmp6_hdr), - pd->hdr.icmp6); + (caddr_t)pd->hdr.icmp6); #endif /* INET6 */ - PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr, - a, ruleset, pd); + PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset); } if (r->action != PF_PASS) return (PF_DROP); - if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) { + if (pf_tag_packet(m, pftag, tag)) { REASON_SET(&reason, PFRES_MEMORY); return (PF_DROP); } @@ -3693,7 +3899,7 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_MAXSTATES); goto cleanup; } - /* src node for filter rule */ + /* src node for flter rule */ if ((r->rule_flag & PFRULE_SRCTRACK || r->rpool.opts & PF_POOL_STICKYADDR) && pf_insert_src_node(&sn, r, saddr, af) != 0) { @@ -3733,9 +3939,7 @@ cleanup: s->anchor.ptr = a; STATE_INC_COUNTERS(s); s->allow_opts = r->allow_opts; - s->log = r->log & PF_LOG_ALL; - if (nr != NULL) - s->log |= nr->log & PF_LOG_ALL; + s->log = r->log & 2; s->proto = pd->proto; s->direction = direction; s->af = af; @@ -3795,7 +3999,7 @@ cleanup: /* copy back packet headers if we performed IPv6 NAT operations */ if (rewrite) m_copyback(m, off, sizeof(struct icmp6_hdr), - pd->hdr.icmp6); + (caddr_t)pd->hdr.icmp6); #endif /* INET6 */ return (PF_PASS); @@ -3813,9 +4017,9 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, struct pf_addr *saddr = pd->src, *daddr = pd->dst; sa_family_t af = pd->af; u_short reason; - int tag = -1, rtableid = -1; + struct pf_tag *pftag = NULL; + int tag = -1; int asd = 0; - int match = 0; if (pf_check_congestion(ifq)) { REASON_SET(&reason, PFRES_CONGEST); @@ -3872,7 +4076,8 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, while (r != NULL) { r->evaluations++; - if (pfi_kif_match(r->kif, kif) == r->ifnot) + if (r->kif != NULL && + (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR].ptr; @@ -3880,29 +4085,24 @@ 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.neg, kif)) + 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.neg, NULL)) + 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)) + else if (r->tos && !(r->tos & pd->tos)) r = TAILQ_NEXT(r, entries); else if (r->rule_flag & PFRULE_FRAGMENT) r = TAILQ_NEXT(r, entries); else if (r->prob && r->prob <= arc4random()) r = TAILQ_NEXT(r, entries); - else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag)) + else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag)) r = TAILQ_NEXT(r, entries); else if (r->os_fingerprint != PF_OSFP_ANY) r = TAILQ_NEXT(r, entries); else { if (r->tag) tag = r->tag; - if (r->rtableid >= 0) - rtableid = r->rtableid; if (r->anchor == NULL) { - match = 1; *rm = r; *am = a; *rsm = ruleset; @@ -3911,11 +4111,11 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, r = TAILQ_NEXT(r, entries); } else pf_step_into_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match); + PF_RULESET_FILTER, &r, &a); } - if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match)) - break; + if (r == NULL) + pf_step_out_of_anchor(&asd, &ruleset, + PF_RULESET_FILTER, &r, &a); } r = *rm; a = *am; @@ -3923,9 +4123,8 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_MATCH); - if (r->log || (nr != NULL && nr->natpass && nr->log)) - PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr, - a, ruleset, pd); + if (r->log) + PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset); if ((r->action == PF_DROP) && ((r->rule_flag & PFRULE_RETURNICMP) || @@ -3964,7 +4163,7 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, if (r->action != PF_PASS) return (PF_DROP); - if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) { + if (pf_tag_packet(m, pftag, tag)) { REASON_SET(&reason, PFRES_MEMORY); return (PF_DROP); } @@ -3980,7 +4179,7 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_MAXSTATES); goto cleanup; } - /* src node for filter rule */ + /* src node for flter rule */ if ((r->rule_flag & PFRULE_SRCTRACK || r->rpool.opts & PF_POOL_STICKYADDR) && pf_insert_src_node(&sn, r, saddr, af) != 0) { @@ -4020,9 +4219,7 @@ cleanup: s->anchor.ptr = a; STATE_INC_COUNTERS(s); s->allow_opts = r->allow_opts; - s->log = r->log & PF_LOG_ALL; - if (nr != NULL) - s->log |= nr->log & PF_LOG_ALL; + s->log = r->log & 2; s->proto = pd->proto; s->direction = direction; s->af = af; @@ -4082,14 +4279,15 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, struct pf_ruleset *ruleset = NULL; sa_family_t af = pd->af; u_short reason; + struct pf_tag *pftag = NULL; int tag = -1; int asd = 0; - int match = 0; r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); while (r != NULL) { r->evaluations++; - if (pfi_kif_match(r->kif, kif) == r->ifnot) + if (r->kif != NULL && + (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot) r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR].ptr; @@ -4097,13 +4295,11 @@ 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.neg, kif)) + 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.neg, NULL)) + 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)) + else if (r->tos && !(r->tos & pd->tos)) r = TAILQ_NEXT(r, entries); else if (r->src.port_op || r->dst.port_op || r->flagset || r->type || r->code || @@ -4111,11 +4307,10 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, r = TAILQ_NEXT(r, entries); else if (r->prob && r->prob <= arc4random()) r = TAILQ_NEXT(r, entries); - else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag)) + else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag)) r = TAILQ_NEXT(r, entries); else { if (r->anchor == NULL) { - match = 1; *rm = r; *am = a; *rsm = ruleset; @@ -4124,11 +4319,11 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, r = TAILQ_NEXT(r, entries); } else pf_step_into_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match); + PF_RULESET_FILTER, &r, &a); } - if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match)) - break; + if (r == NULL) + pf_step_out_of_anchor(&asd, &ruleset, + PF_RULESET_FILTER, &r, &a); } r = *rm; a = *am; @@ -4137,13 +4332,12 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, REASON_SET(&reason, PFRES_MATCH); if (r->log) - PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset, - pd); + PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset); if (r->action != PF_PASS) return (PF_DROP); - if (pf_tag_packet(m, pd->pf_mtag, tag, -1)) { + if (pf_tag_packet(m, pftag, tag)) { REASON_SET(&reason, PFRES_MEMORY); return (PF_DROP); } @@ -4156,7 +4350,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason) { - struct pf_state_cmp key; + struct pf_state key; struct tcphdr *th = pd->hdr.tcp; u_int16_t win = ntohs(th->th_win); u_int32_t ack, end, seq, orig_seq; @@ -4199,11 +4393,15 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, REASON_SET(reason, PFRES_SYNPROXY); return (PF_DROP); } +#ifdef __FreeBSD__ + pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst, +#else pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst, +#endif 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, 1, - 0, NULL, NULL); + NULL, NULL); REASON_SET(reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); } else if (!(th->th_flags & TH_ACK) || @@ -4238,10 +4436,15 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, (*state)->src.max_win = MAX(ntohs(th->th_win), 1); if ((*state)->dst.seqhi == 1) (*state)->dst.seqhi = htonl(arc4random()); +#ifdef __FreeBSD__ + pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, + &src->addr, +#else pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr, +#endif &dst->addr, src->port, dst->port, (*state)->dst.seqhi, 0, TH_SYN, 0, - (*state)->src.mss, 0, 0, (*state)->tag, NULL, NULL); + (*state)->src.mss, 0, 0, NULL, NULL); REASON_SET(reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); } else if (((th->th_flags & (TH_SYN|TH_ACK)) != @@ -4252,16 +4455,25 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, } else { (*state)->dst.max_win = MAX(ntohs(th->th_win), 1); (*state)->dst.seqlo = ntohl(th->th_seq); +#ifdef __FreeBSD__ + pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst, +#else pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst, +#endif 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, 0, - (*state)->tag, NULL, NULL); + NULL, NULL); +#ifdef __FreeBSD__ + pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, + &src->addr, +#else pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr, +#endif &dst->addr, src->port, dst->port, (*state)->src.seqhi + 1, (*state)->src.seqlo + 1, TH_ACK, (*state)->dst.max_win, 0, 0, 1, - 0, NULL, NULL); + NULL, NULL); (*state)->src.seqdiff = (*state)->dst.seqhi - (*state)->src.seqlo; (*state)->dst.seqdiff = (*state)->src.seqhi - @@ -4304,7 +4516,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 = tcp_rndiss_next() - seq) == 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 + @@ -4393,25 +4605,6 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, ackskew = dst->seqlo - ack; - - /* - * Need to demodulate the sequence numbers in any TCP SACK options - * (Selective ACK). We could optionally validate the SACK values - * against the current ACK window, either forwards or backwards, but - * I'm not confident that SACK has been implemented properly - * everywhere. It wouldn't surprise me if several stacks accidently - * SACK too far backwards of previously ACKed data. There really aren't - * any security implications of bad SACKing unless the target stack - * doesn't validate the option length correctly. Someone trying to - * spoof into a TCP connection won't bother blindly sending SACK - * options anyway. - */ - if (dst->seqdiff && (th->th_off << 2) > sizeof(struct tcphdr)) { - if (pf_modulate_sack(m, off, pd, th, dst)) - copyback = 1; - } - - #define MAXACKWINDOW (0xffff + 1500) /* 1500 is an arbitrary fudge factor */ if (SEQ_GEQ(src->seqhi, end) && /* Last octet inside other's window space */ @@ -4422,8 +4615,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, (ackskew <= (MAXACKWINDOW << sws)) && /* Acking not more than one window forward */ ((th->th_flags & TH_RST) == 0 || orig_seq == src->seqlo || - (orig_seq == src->seqlo + 1) || (pd->flags & PFDESC_IP_REAS) == 0)) { - /* Require an exact/+1 sequence match on resets when possible */ + (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, @@ -4469,8 +4662,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, if (src->state >= TCPS_FIN_WAIT_2 && dst->state >= TCPS_FIN_WAIT_2) (*state)->timeout = PFTM_TCP_CLOSED; - else if (src->state >= TCPS_CLOSING && - dst->state >= TCPS_CLOSING) + else if (src->state >= TCPS_FIN_WAIT_2 || + dst->state >= TCPS_FIN_WAIT_2) (*state)->timeout = PFTM_TCP_FIN_WAIT; else if (src->state < TCPS_ESTABLISHED || dst->state < TCPS_ESTABLISHED) @@ -4516,10 +4709,9 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, printf("pf: loose state match: "); pf_print_state(*state); pf_print_flags(th->th_flags); - printf(" seq=%u (%u) ack=%u len=%u ackskew=%d " - "pkts=%llu:%llu\n", seq, orig_seq, ack, pd->p_len, - ackskew, (*state)->packets[0], - (*state)->packets[1]); + printf(" seq=%u ack=%u len=%u ackskew=%d pkts=%d:%d\n", + seq, ack, pd->p_len, ackskew, + (*state)->packets[0], (*state)->packets[1]); } if (dst->scrub || src->scrub) { @@ -4556,11 +4748,15 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, (*state)->src.state == TCPS_SYN_SENT) { /* Send RST for state mismatches during handshake */ if (!(th->th_flags & TH_RST)) +#ifdef __FreeBSD__ + pf_send_tcp(m, (*state)->rule.ptr, pd->af, +#else pf_send_tcp((*state)->rule.ptr, pd->af, +#endif pd->dst, pd->src, th->th_dport, th->th_sport, ntohl(th->th_ack), 0, TH_RST, 0, 0, - (*state)->rule.ptr->return_ttl, 1, 0, + (*state)->rule.ptr->return_ttl, 1, pd->eh, kif->pfik_ifp); src->seqlo = 0; src->seqhi = 1; @@ -4569,9 +4765,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, printf("pf: BAD state: "); pf_print_state(*state); pf_print_flags(th->th_flags); - printf(" seq=%u (%u) ack=%u len=%u ackskew=%d " - "pkts=%llu:%llu dir=%s,%s\n", - seq, orig_seq, ack, pd->p_len, ackskew, + printf(" seq=%u ack=%u len=%u ackskew=%d pkts=%d:%d " + "dir=%s,%s\n", seq, ack, pd->p_len, ackskew, (*state)->packets[0], (*state)->packets[1], direction == PF_IN ? "in" : "out", direction == (*state)->direction ? "fwd" : "rev"); @@ -4600,10 +4795,10 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum, &th->th_sum, &(*state)->lan.addr, (*state)->lan.port, 0, pd->af); - m_copyback(m, off, sizeof(*th), th); + m_copyback(m, off, sizeof(*th), (caddr_t)th); } else if (copyback) { /* Copyback sequence modulation or stateful scrub changes */ - m_copyback(m, off, sizeof(*th), th); + m_copyback(m, off, sizeof(*th), (caddr_t)th); } return (PF_PASS); @@ -4614,7 +4809,7 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd) { struct pf_state_peer *src, *dst; - struct pf_state_cmp key; + struct pf_state key; struct udphdr *uh = pd->hdr.udp; key.af = pd->af; @@ -4664,7 +4859,7 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif, pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum, &uh->uh_sum, &(*state)->lan.addr, (*state)->lan.port, 1, pd->af); - m_copyback(m, off, sizeof(*uh), uh); + m_copyback(m, off, sizeof(*uh), (caddr_t)uh); } return (PF_PASS); @@ -4675,10 +4870,10 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason) { struct pf_addr *saddr = pd->src, *daddr = pd->dst; - u_int16_t icmpid, *icmpsum; - u_int8_t icmptype; + u_int16_t icmpid = 0; /* make the compiler happy */ + u_int16_t *icmpsum = NULL; /* make the compiler happy */ + u_int8_t icmptype = 0; /* make the compiler happy */ int state_icmp = 0; - struct pf_state_cmp key; switch (pd->proto) { #ifdef INET @@ -4716,6 +4911,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, * ICMP query/reply message not related to a TCP/UDP packet. * Search for an ICMP state. */ + struct pf_state key; + key.af = pd->af; key.proto = pd->proto; if (direction == PF_IN) { @@ -4751,7 +4948,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, pd->hdr.icmp->icmp_id = (*state)->gwy.port; m_copyback(m, off, ICMP_MINLEN, - pd->hdr.icmp); + (caddr_t)pd->hdr.icmp); break; #endif /* INET */ #ifdef INET6 @@ -4761,7 +4958,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, &(*state)->gwy.addr, 0); m_copyback(m, off, sizeof(struct icmp6_hdr), - pd->hdr.icmp6); + (caddr_t)pd->hdr.icmp6); break; #endif /* INET6 */ } @@ -4779,7 +4976,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, pd->hdr.icmp->icmp_id = (*state)->lan.port; m_copyback(m, off, ICMP_MINLEN, - pd->hdr.icmp); + (caddr_t)pd->hdr.icmp); break; #endif /* INET */ #ifdef INET6 @@ -4789,7 +4986,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, &(*state)->lan.addr, 0); m_copyback(m, off, sizeof(struct icmp6_hdr), - pd->hdr.icmp6); + (caddr_t)pd->hdr.icmp6); break; #endif /* INET6 */ } @@ -4812,8 +5009,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, struct ip6_hdr h2_6; int terminal = 0; #endif /* INET6 */ - int ipoff2; - int off2; + int ipoff2 = 0; /* make the compiler happy */ + int off2 = 0; /* make the compiler happy */ pd2.af = pd->af; switch (pd->af) { @@ -4907,6 +5104,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, case IPPROTO_TCP: { struct tcphdr th; u_int32_t seq; + struct pf_state key; struct pf_state_peer *src, *dst; u_int8_t dws; int copyback = 0; @@ -5000,22 +5198,22 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, #ifdef INET case AF_INET: m_copyback(m, off, ICMP_MINLEN, - pd->hdr.icmp); + (caddr_t)pd->hdr.icmp); m_copyback(m, ipoff2, sizeof(h2), - &h2); + (caddr_t)&h2); break; #endif /* INET */ #ifdef INET6 case AF_INET6: m_copyback(m, off, sizeof(struct icmp6_hdr), - pd->hdr.icmp6); + (caddr_t)pd->hdr.icmp6); m_copyback(m, ipoff2, sizeof(h2_6), - &h2_6); + (caddr_t)&h2_6); break; #endif /* INET6 */ } - m_copyback(m, off2, 8, &th); + m_copyback(m, off2, 8, (caddr_t)&th); } return (PF_PASS); @@ -5023,6 +5221,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, } case IPPROTO_UDP: { struct udphdr uh; + struct pf_state key; if (!pf_pull_hdr(m, off2, &uh, sizeof(uh), NULL, reason, pd2.af)) { @@ -5066,21 +5265,23 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, #ifdef INET case AF_INET: m_copyback(m, off, ICMP_MINLEN, - pd->hdr.icmp); - m_copyback(m, ipoff2, sizeof(h2), &h2); + (caddr_t)pd->hdr.icmp); + m_copyback(m, ipoff2, sizeof(h2), + (caddr_t)&h2); break; #endif /* INET */ #ifdef INET6 case AF_INET6: m_copyback(m, off, sizeof(struct icmp6_hdr), - pd->hdr.icmp6); + (caddr_t)pd->hdr.icmp6); m_copyback(m, ipoff2, sizeof(h2_6), - &h2_6); + (caddr_t)&h2_6); break; #endif /* INET6 */ } - m_copyback(m, off2, sizeof(uh), &uh); + m_copyback(m, off2, sizeof(uh), + (caddr_t)&uh); } return (PF_PASS); @@ -5089,6 +5290,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, #ifdef INET case IPPROTO_ICMP: { struct icmp iih; + struct pf_state key; if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN, NULL, reason, pd2.af)) { @@ -5128,9 +5330,12 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, pd2.ip_sum, icmpsum, pd->ip_sum, 0, AF_INET); } - m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp); - m_copyback(m, ipoff2, sizeof(h2), &h2); - m_copyback(m, off2, ICMP_MINLEN, &iih); + m_copyback(m, off, ICMP_MINLEN, + (caddr_t)pd->hdr.icmp); + m_copyback(m, ipoff2, sizeof(h2), + (caddr_t)&h2); + m_copyback(m, off2, ICMP_MINLEN, + (caddr_t)&iih); } return (PF_PASS); @@ -5140,6 +5345,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, #ifdef INET6 case IPPROTO_ICMPV6: { struct icmp6_hdr iih; + struct pf_state key; if (!pf_pull_hdr(m, off2, &iih, sizeof(struct icmp6_hdr), NULL, reason, pd2.af)) { @@ -5180,10 +5386,11 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, pd->ip_sum, 0, AF_INET6); } m_copyback(m, off, sizeof(struct icmp6_hdr), - pd->hdr.icmp6); - m_copyback(m, ipoff2, sizeof(h2_6), &h2_6); + (caddr_t)pd->hdr.icmp6); + m_copyback(m, ipoff2, sizeof(h2_6), + (caddr_t)&h2_6); m_copyback(m, off2, sizeof(struct icmp6_hdr), - &iih); + (caddr_t)&iih); } return (PF_PASS); @@ -5191,6 +5398,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, } #endif /* INET6 */ default: { + struct pf_state key; + key.af = pd2.af; key.proto = pd2.proto; if (direction == PF_IN) { @@ -5225,17 +5434,18 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, #ifdef INET case AF_INET: m_copyback(m, off, ICMP_MINLEN, - pd->hdr.icmp); - m_copyback(m, ipoff2, sizeof(h2), &h2); + (caddr_t)pd->hdr.icmp); + m_copyback(m, ipoff2, sizeof(h2), + (caddr_t)&h2); break; #endif /* INET */ #ifdef INET6 case AF_INET6: m_copyback(m, off, sizeof(struct icmp6_hdr), - pd->hdr.icmp6); + (caddr_t)pd->hdr.icmp6); m_copyback(m, ipoff2, sizeof(h2_6), - &h2_6); + (caddr_t)&h2_6); break; #endif /* INET6 */ } @@ -5253,7 +5463,7 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif, struct pf_pdesc *pd) { struct pf_state_peer *src, *dst; - struct pf_state_cmp key; + struct pf_state key; key.af = pd->af; key.proto = pd->proto; @@ -5381,24 +5591,16 @@ pf_pull_hdr(struct mbuf *m, int off, void *p, int len, } int -pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif) +pf_routable(struct pf_addr *addr, sa_family_t af) { struct sockaddr_in *dst; - int ret = 1; - int check_mpath; - extern int ipmultipath; #ifdef INET6 - extern int ip6_multipath; struct sockaddr_in6 *dst6; struct route_in6 ro; #else struct route ro; #endif - struct radix_node *rn; - struct rtentry *rt; - struct ifnet *ifp; - check_mpath = 0; bzero(&ro, sizeof(ro)); switch (af) { case AF_INET: @@ -5406,8 +5608,6 @@ pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif) dst->sin_family = AF_INET; dst->sin_len = sizeof(*dst); dst->sin_addr = addr->v4; - if (ipmultipath) - check_mpath = 1; break; #ifdef INET6 case AF_INET6: @@ -5415,50 +5615,28 @@ pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif) dst6->sin6_family = AF_INET6; dst6->sin6_len = sizeof(*dst6); dst6->sin6_addr = addr->v6; - if (ip6_multipath) - check_mpath = 1; break; #endif /* INET6 */ default: return (0); } - /* Skip checks for ipsec interfaces */ - if (kif != NULL && kif->pfik_ifp->if_type == IFT_ENC) - goto out; - +#ifdef __FreeBSD__ +#ifdef RTF_PRCLONING + rtalloc_ign((struct route *)&ro, (RTF_CLONING | RTF_PRCLONING)); +#else /* !RTF_PRCLONING */ + rtalloc_ign((struct route *)&ro, RTF_CLONING); +#endif +#else /* ! __FreeBSD__ */ rtalloc_noclone((struct route *)&ro, NO_CLONING); +#endif if (ro.ro_rt != NULL) { - /* No interface given, this is a no-route check */ - if (kif == NULL) - goto out; - - if (kif->pfik_ifp == NULL) { - ret = 0; - goto out; - } - - /* Perform uRPF check if passed input interface */ - ret = 0; - rn = (struct radix_node *)ro.ro_rt; - do { - rt = (struct rtentry *)rn; - if (rt->rt_ifp->if_type == IFT_CARP) - ifp = rt->rt_ifp->if_carpdev; - else - ifp = rt->rt_ifp; - - if (kif->pfik_ifp == ifp) - ret = 1; - rn = rn_mpath_next(rn); - } while (check_mpath == 1 && rn != NULL && ret == 0); - } else - ret = 0; -out: - if (ro.ro_rt != NULL) RTFREE(ro.ro_rt); - return (ret); + return (1); + } + + return (0); } int @@ -5493,11 +5671,23 @@ pf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw) return (0); } +#ifdef __FreeBSD__ +# ifdef RTF_PRCLONING + rtalloc_ign((struct route *)&ro, (RTF_CLONING|RTF_PRCLONING)); +# else /* !RTF_PRCLONING */ + rtalloc_ign((struct route *)&ro, RTF_CLONING); +# endif +#else /* ! __FreeBSD__ */ rtalloc_noclone((struct route *)&ro, NO_CLONING); +#endif if (ro.ro_rt != NULL) { +#ifdef __FreeBSD__ + /* XXX_IMPORT: later */ +#else if (ro.ro_rt->rt_labelid == aw->v.rtlabel) ret = 1; +#endif RTFREE(ro.ro_rt); } @@ -5505,35 +5695,53 @@ pf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw) } #ifdef INET + void pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, - struct pf_state *s, struct pf_pdesc *pd) + struct pf_state *s) { struct mbuf *m0, *m1; + struct m_tag *mtag; struct route iproute; - struct route *ro = NULL; + struct route *ro = NULL; /* XXX: was uninitialized */ struct sockaddr_in *dst; struct ip *ip; struct ifnet *ifp = NULL; struct pf_addr naddr; struct pf_src_node *sn = NULL; int error = 0; -#ifdef IPSEC - struct m_tag *mtag; -#endif /* IPSEC */ +#ifdef __FreeBSD__ + int sw_csum; +#endif if (m == NULL || *m == NULL || r == NULL || (dir != PF_IN && dir != PF_OUT) || oifp == NULL) panic("pf_route: invalid parameters"); - if (pd->pf_mtag->routed++ > 3) { - m0 = *m; - *m = NULL; - goto bad; + 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; + } + *(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) { +#ifdef __FreeBSD__ + if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL) +#else if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL) +#endif return; } else { if ((r->rt == PF_REPLYTO) == (r->direction == dir)) @@ -5592,10 +5800,22 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, goto bad; if (oifp != ifp) { +#ifdef __FreeBSD__ + PF_UNLOCK(); + if (pf_test(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) { + PF_LOCK(); + goto bad; + } else if (m0 == NULL) { + PF_LOCK(); + goto done; + } + PF_LOCK(); +#else if (pf_test(PF_OUT, ifp, &m0, NULL) != PF_PASS) goto bad; else if (m0 == NULL) goto done; +#endif if (m0->m_len < sizeof(struct ip)) { DPFPRINTF(PF_DEBUG_URGENT, ("pf_route: m0->m_len < sizeof(struct ip)\n")); @@ -5604,6 +5824,47 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, ip = mtod(m0, struct ip *); } +#ifdef __FreeBSD__ + /* Copied from FreeBSD 5.1-CURRENT ip_output. */ + m0->m_pkthdr.csum_flags |= CSUM_IP; + sw_csum = m0->m_pkthdr.csum_flags & ~ifp->if_hwassist; + if (sw_csum & CSUM_DELAY_DATA) { + /* + * XXX: in_delayed_cksum assumes HBO for ip->ip_len (at least) + */ + NTOHS(ip->ip_len); + NTOHS(ip->ip_off); /* XXX: needed? */ + in_delayed_cksum(m0); + HTONS(ip->ip_len); + HTONS(ip->ip_off); + sw_csum &= ~CSUM_DELAY_DATA; + } + m0->m_pkthdr.csum_flags &= ifp->if_hwassist; + + if (ntohs(ip->ip_len) <= ifp->if_mtu || + (ifp->if_hwassist & CSUM_FRAGMENT && + ((ip->ip_off & htons(IP_DF)) == 0))) { + /* + * ip->ip_len = htons(ip->ip_len); + * ip->ip_off = htons(ip->ip_off); + */ + ip->ip_sum = 0; + if (sw_csum & CSUM_DELAY_IP) { + /* From KAME */ + if (ip->ip_v == IPVERSION && + (ip->ip_hl << 2) == sizeof(*ip)) { + ip->ip_sum = in_cksum_hdr(ip); + } else { + ip->ip_sum = in_cksum(m0, ip->ip_hl << 2); + } + } + PF_UNLOCK(); + error = (*ifp->if_output)(ifp, m0, sintosa(dst), ro->ro_rt); + PF_LOCK(); + goto done; + } + +#else /* Copied from ip_output. */ #ifdef IPSEC /* @@ -5619,38 +5880,38 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, #endif /* IPSEC */ /* Catch routing changes wrt. hardware checksumming for TCP or UDP. */ - if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT) { + if (m0->m_pkthdr.csum & M_TCPV4_CSUM_OUT) { if (!(ifp->if_capabilities & IFCAP_CSUM_TCPv4) || ifp->if_bridge != NULL) { in_delayed_cksum(m0); - m0->m_pkthdr.csum_flags &= ~M_TCPV4_CSUM_OUT; /* Clear */ + m0->m_pkthdr.csum &= ~M_TCPV4_CSUM_OUT; /* Clear */ } - } else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT) { + } else if (m0->m_pkthdr.csum & M_UDPV4_CSUM_OUT) { if (!(ifp->if_capabilities & IFCAP_CSUM_UDPv4) || ifp->if_bridge != NULL) { in_delayed_cksum(m0); - m0->m_pkthdr.csum_flags &= ~M_UDPV4_CSUM_OUT; /* Clear */ + m0->m_pkthdr.csum &= ~M_UDPV4_CSUM_OUT; /* Clear */ } } if (ntohs(ip->ip_len) <= ifp->if_mtu) { if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) && ifp->if_bridge == NULL) { - m0->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT; + m0->m_pkthdr.csum |= M_IPV4_CSUM_OUT; ipstat.ips_outhwcsum++; } else { ip->ip_sum = 0; ip->ip_sum = in_cksum(m0, ip->ip_hl << 2); } /* Update relevant hardware checksum stats for TCP/UDP */ - if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT) + if (m0->m_pkthdr.csum & M_TCPV4_CSUM_OUT) tcpstat.tcps_outhwcsum++; - else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT) + else if (m0->m_pkthdr.csum & M_UDPV4_CSUM_OUT) udpstat.udps_outhwcsum++; error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL); goto done; } - +#endif /* * Too large for interface; fragment if possible. * Must be able to put at least 8 bytes per fragment. @@ -5658,27 +5919,57 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, if (ip->ip_off & htons(IP_DF)) { ipstat.ips_cantfrag++; if (r->rt != PF_DUPTO) { +#ifdef __FreeBSD__ + /* icmp_error() expects host byte ordering */ + NTOHS(ip->ip_len); + NTOHS(ip->ip_off); + PF_UNLOCK(); icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0, ifp->if_mtu); + PF_LOCK(); +#else + icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0, + ifp); +#endif goto done; } else goto bad; } m1 = m0; +#ifdef __FreeBSD__ + /* + * XXX: is cheaper + less error prone than own function + */ + NTOHS(ip->ip_len); + NTOHS(ip->ip_off); + error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist, sw_csum); +#else error = ip_fragment(m0, ifp, ifp->if_mtu); +#endif if (error) { +#ifndef __FreeBSD__ /* ip_fragment does not do m_freem() on FreeBSD */ m0 = NULL; +#endif goto bad; } for (m0 = m1; m0; m0 = m1) { m1 = m0->m_nextpkt; m0->m_nextpkt = 0; +#ifdef __FreeBSD__ + if (error == 0) { + PF_UNLOCK(); + error = (*ifp->if_output)(ifp, m0, sintosa(dst), + NULL); + PF_LOCK(); + } else +#else if (error == 0) error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL); else +#endif m_freem(m0); } @@ -5701,9 +5992,10 @@ bad: #ifdef INET6 void pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, - struct pf_state *s, struct pf_pdesc *pd) + struct pf_state *s) { struct mbuf *m0; + struct m_tag *mtag; struct route_in6 ip6route; struct route_in6 *ro; struct sockaddr_in6 *dst; @@ -5717,14 +6009,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 (pd->pf_mtag->routed++ > 3) { - m0 = *m; - *m = NULL; - goto bad; + 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; + } + *(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) { +#ifdef __FreeBSD__ + if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL) +#else if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL) +#endif return; } else { if ((r->rt == PF_REPLYTO) == (r->direction == dir)) @@ -5746,10 +6054,20 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, dst->sin6_len = sizeof(*dst); dst->sin6_addr = ip6->ip6_dst; - /* Cheat. XXX why only in the v6 case??? */ + /* Cheat. */ if (r->rt == PF_FASTROUTE) { - pd->pf_mtag->flags |= PF_TAG_GENERATED; +#ifdef __FreeBSD__ + m0->m_flags |= M_SKIP_FIREWALL; + PF_UNLOCK(); + ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL); + PF_LOCK(); +#else + mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT); + if (mtag == NULL) + goto bad; + m_tag_prepend(m0, mtag); ip6_output(m0, NULL, NULL, 0, NULL, NULL); +#endif return; } @@ -5775,10 +6093,22 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, goto bad; if (oifp != ifp) { +#ifdef __FreeBSD__ + PF_UNLOCK(); + if (pf_test6(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) { + PF_LOCK(); + goto bad; + } else if (m0 == NULL) { + PF_LOCK(); + goto done; + } + PF_LOCK(); +#else if (pf_test6(PF_OUT, ifp, &m0, NULL) != PF_PASS) goto bad; else if (m0 == NULL) goto done; +#endif if (m0->m_len < sizeof(struct ip6_hdr)) { DPFPRINTF(PF_DEBUG_URGENT, ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n")); @@ -5791,15 +6121,29 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, * If the packet is too large for the outgoing interface, * send back an icmp6 error. */ - if (IN6_IS_SCOPE_EMBED(&dst->sin6_addr)) + if (IN6_IS_ADDR_LINKLOCAL(&dst->sin6_addr)) dst->sin6_addr.s6_addr16[1] = htons(ifp->if_index); if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) { +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif error = nd6_output(ifp, ifp, m0, dst, NULL); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif } else { in6_ifstat_inc(ifp, ifs6_in_toobig); +#ifdef __FreeBSD__ + if (r->rt != PF_DUPTO) { + PF_UNLOCK(); + icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu); + PF_LOCK(); + } else +#else if (r->rt != PF_DUPTO) icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu); else +#endif goto bad; } @@ -5815,6 +6159,131 @@ bad: #endif /* INET6 */ +#ifdef __FreeBSD__ +/* + * FreeBSD supports cksum offloads for the following drivers. + * em(4), fxp(4), ixgb(4), lge(4), ndis(4), nge(4), re(4), + * ti(4), txp(4), xl(4) + * + * CSUM_DATA_VALID | CSUM_PSEUDO_HDR : + * network driver performed cksum including pseudo header, need to verify + * csum_data + * CSUM_DATA_VALID : + * network driver performed cksum, needs to additional pseudo header + * cksum computation with partial csum_data(i.e. lack of H/W support for + * pseudo header, for instance hme(4), sk(4) and possibly gem(4)) + * + * After validating the cksum of packet, set both flag CSUM_DATA_VALID and + * CSUM_PSEUDO_HDR in order to avoid recomputation of the cksum in upper + * TCP/UDP layer. + * Also, set csum_data to 0xffff to force cksum validation. + */ +int +pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t af) +{ + u_int16_t sum = 0; + int hw_assist = 0; + struct ip *ip; + + if (off < sizeof(struct ip) || len < sizeof(struct udphdr)) + return (1); + if (m->m_pkthdr.len < off + len) + return (1); + + switch (p) { + case IPPROTO_TCP: + if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { + if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) { + sum = m->m_pkthdr.csum_data; + } else { + ip = mtod(m, struct ip *); + sum = in_pseudo(ip->ip_src.s_addr, + ip->ip_dst.s_addr, htonl((u_short)len + + m->m_pkthdr.csum_data + IPPROTO_TCP)); + } + sum ^= 0xffff; + ++hw_assist; + } + break; + case IPPROTO_UDP: + if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { + if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) { + sum = m->m_pkthdr.csum_data; + } else { + ip = mtod(m, struct ip *); + sum = in_pseudo(ip->ip_src.s_addr, + ip->ip_dst.s_addr, htonl((u_short)len + + m->m_pkthdr.csum_data + IPPROTO_UDP)); + } + sum ^= 0xffff; + ++hw_assist; + } + break; + case IPPROTO_ICMP: +#ifdef INET6 + case IPPROTO_ICMPV6: +#endif /* INET6 */ + break; + default: + return (1); + } + + if (!hw_assist) { + switch (af) { + case AF_INET: + if (p == IPPROTO_ICMP) { + if (m->m_len < off) + return (1); + m->m_data += off; + m->m_len -= off; + sum = in_cksum(m, len); + m->m_data -= off; + m->m_len += off; + } else { + if (m->m_len < sizeof(struct ip)) + return (1); + sum = in4_cksum(m, p, off, len); + } + break; +#ifdef INET6 + case AF_INET6: + if (m->m_len < sizeof(struct ip6_hdr)) + return (1); + sum = in6_cksum(m, p, off, len); + break; +#endif /* INET6 */ + default: + return (1); + } + } + if (sum) { + switch (p) { + case IPPROTO_TCP: + tcpstat.tcps_rcvbadsum++; + break; + case IPPROTO_UDP: + udpstat.udps_badsum++; + break; + case IPPROTO_ICMP: + icmpstat.icps_checksum++; + break; +#ifdef INET6 + case IPPROTO_ICMPV6: + icmp6stat.icp6s_checksum++; + break; +#endif /* INET6 */ + } + return (1); + } else { + if (p == IPPROTO_TCP || p == IPPROTO_UDP) { + m->m_pkthdr.csum_flags |= + (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); + m->m_pkthdr.csum_data = 0xffff; + } + } + return (0); +} +#else /* * check protocol (tcp/udp/icmp/icmp6) checksum and set mbuf flag * off is the offset where the protocol header starts @@ -5846,9 +6315,9 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, default: return (1); } - if (m->m_pkthdr.csum_flags & flag_ok) + if (m->m_pkthdr.csum & flag_ok) return (0); - if (m->m_pkthdr.csum_flags & flag_bad) + if (m->m_pkthdr.csum & flag_bad) return (1); if (off < sizeof(struct ip) || len < sizeof(struct udphdr)) return (1); @@ -5883,7 +6352,7 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, return (1); } if (sum) { - m->m_pkthdr.csum_flags |= flag_bad; + m->m_pkthdr.csum |= flag_bad; switch (p) { case IPPROTO_TCP: tcpstat.tcps_rcvbadsum++; @@ -5902,54 +6371,91 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, } return (1); } - m->m_pkthdr.csum_flags |= flag_ok; + m->m_pkthdr.csum |= flag_ok; + return (0); +} +#endif + +static int +pf_add_mbuf_tag(struct mbuf *m, u_int tag) +{ + struct m_tag *mtag; + + if (m_tag_find(m, tag, NULL) != NULL) + return (0); + mtag = m_tag_get(tag, 0, M_NOWAIT); + if (mtag == NULL) + return (1); + m_tag_prepend(m, mtag); return (0); } #ifdef INET int +#ifdef __FreeBSD__ +pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, + struct ether_header *eh, struct inpcb *inp) +#else pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct ether_header *eh) +#endif { struct pfi_kif *kif; u_short action, reason = 0, log = 0; struct mbuf *m = *m0; - struct ip *h; + struct ip *h = NULL; /* make the compiler happy */ struct pf_rule *a = NULL, *r = &pf_default_rule, *tr, *nr; struct pf_state *s = NULL; struct pf_ruleset *ruleset = NULL; struct pf_pdesc pd; int off, dirndx, pqid = 0; - if (!pf_status.running) - return (PF_PASS); - - memset(&pd, 0, sizeof(pd)); - if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) { - DPFPRINTF(PF_DEBUG_URGENT, - ("pf_test: pf_get_mtag returned NULL\n")); - return (PF_DROP); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif + if (!pf_status.running || +#ifdef __FreeBSD__ + (m->m_flags & M_SKIP_FIREWALL)) { + PF_UNLOCK(); +#else + (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) { +#endif + return (PF_PASS); } - if (pd.pf_mtag->flags & PF_TAG_GENERATED) - return (PF_PASS); +#ifdef __FreeBSD__ + /* XXX_IMPORT: later */ +#else if (ifp->if_type == IFT_CARP && ifp->if_carpdev) ifp = ifp->if_carpdev; +#endif - kif = (struct pfi_kif *)ifp->if_pf_kif; + kif = pfi_index2kif[ifp->if_index]; if (kif == NULL) { +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif DPFPRINTF(PF_DEBUG_URGENT, ("pf_test: kif == NULL, if_xname %s\n", ifp->if_xname)); return (PF_DROP); } - if (kif->pfik_flags & PFI_IFLAG_SKIP) + if (kif->pfik_flags & PFI_IFLAG_SKIP) { +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif return (PF_PASS); + } +#ifdef __FreeBSD__ + M_ASSERTPKTHDR(m); +#else #ifdef DIAGNOSTIC if ((m->m_flags & M_PKTHDR) == 0) panic("non-M_PKTHDR is passed to pf_test"); #endif /* DIAGNOSTIC */ +#endif /* __FreeBSD__ */ + memset(&pd, 0, sizeof(pd)); if (m->m_pkthdr.len < (int)sizeof(*h)) { action = PF_DROP; REASON_SET(&reason, PFRES_SHORT); @@ -6003,7 +6509,6 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, } if (dir == PF_IN && pf_check_proto_cksum(m, off, ntohs(h->ip_len) - off, IPPROTO_TCP, AF_INET)) { - REASON_SET(&reason, PFRES_PROTCKSUM); action = PF_DROP; goto done; } @@ -6023,8 +6528,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, a = s->anchor.ptr; log = s->log; } else if (s == NULL) +#ifdef __FreeBSD__ + action = pf_test_tcp(&r, &s, dir, kif, + m, off, h, &pd, &a, &ruleset, NULL, inp); +#else action = pf_test_tcp(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ipintrq); +#endif break; } @@ -6040,14 +6550,12 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m, off, ntohs(h->ip_len) - off, IPPROTO_UDP, AF_INET)) { action = PF_DROP; - REASON_SET(&reason, PFRES_PROTCKSUM); goto done; } if (uh.uh_dport == 0 || ntohs(uh.uh_ulen) > m->m_pkthdr.len - off || ntohs(uh.uh_ulen) < sizeof(struct udphdr)) { action = PF_DROP; - REASON_SET(&reason, PFRES_SHORT); goto done; } action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd); @@ -6059,8 +6567,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, a = s->anchor.ptr; log = s->log; } else if (s == NULL) +#ifdef __FreeBSD__ + action = pf_test_udp(&r, &s, dir, kif, + m, off, h, &pd, &a, &ruleset, NULL, inp); +#else action = pf_test_udp(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ipintrq); +#endif break; } @@ -6076,7 +6589,6 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, if (dir == PF_IN && pf_check_proto_cksum(m, off, ntohs(h->ip_len) - off, IPPROTO_ICMP, AF_INET)) { action = PF_DROP; - REASON_SET(&reason, PFRES_PROTCKSUM); goto done; } action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd, @@ -6089,8 +6601,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, a = s->anchor.ptr; log = s->log; } else if (s == NULL) +#ifdef __FreeBSD__ + action = pf_test_icmp(&r, &s, dir, kif, + m, off, h, &pd, &a, &ruleset, NULL); +#else action = pf_test_icmp(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ipintrq); +#endif break; } @@ -6104,8 +6621,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, a = s->anchor.ptr; log = s->log; } else if (s == NULL) +#ifdef __FreeBSD__ + action = pf_test_other(&r, &s, dir, kif, m, off, h, + &pd, &a, &ruleset, NULL); +#else action = pf_test_other(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ipintrq); +#endif break; } @@ -6119,18 +6641,26 @@ done: ("pf: dropping packet with ip options\n")); } - if ((s && s->tag) || r->rtableid) - pf_tag_packet(m, pd.pf_mtag, s ? s->tag : 0, r->rtableid); + if (s && s->tag) + pf_tag_packet(m, pf_get_tag(m), s->tag); #ifdef ALTQ if (action == PF_PASS && r->qid) { - if (pqid || (pd.tos & IPTOS_LOWDELAY)) - pd.pf_mtag->qid = r->pqid; - else - pd.pf_mtag->qid = r->qid; - /* add hints for ecn */ - pd.pf_mtag->af = AF_INET; - pd.pf_mtag->hdr = h; + struct m_tag *mtag; + struct altq_tag *atag; + + mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT); + if (mtag != NULL) { + atag = (struct altq_tag *)(mtag + 1); + if (pqid || pd.tos == IPTOS_LOWDELAY) + atag->qid = r->pqid; + else + atag->qid = r->qid; + /* add hints for ecn */ + atag->af = AF_INET; + atag->hdr = h; + m_tag_prepend(m, mtag); + } } #endif /* ALTQ */ @@ -6143,48 +6673,41 @@ done: pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL && (s->nat_rule.ptr->action == PF_RDR || s->nat_rule.ptr->action == PF_BINAT) && - (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) - pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST; - - if (log) { - struct pf_rule *lr; - - if (s != NULL && s->nat_rule.ptr != NULL && - s->nat_rule.ptr->log & PF_LOG_ALL) - lr = s->nat_rule.ptr; - else - lr = r; - PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, lr, a, ruleset, - &pd); + (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET && + pf_add_mbuf_tag(m, PACKET_TAG_PF_TRANSLATE_LOCALHOST)) { + action = PF_DROP; + REASON_SET(&reason, PFRES_MEMORY); } + if (log) + PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, r, a, ruleset); + kif->pfik_bytes[0][dir == PF_OUT][action != PF_PASS] += pd.tot_len; kif->pfik_packets[0][dir == PF_OUT][action != PF_PASS]++; if (action == PF_PASS || r->action == PF_DROP) { - dirndx = (dir == PF_OUT); - r->packets[dirndx]++; - r->bytes[dirndx] += pd.tot_len; + r->packets++; + r->bytes += pd.tot_len; if (a != NULL) { - a->packets[dirndx]++; - a->bytes[dirndx] += pd.tot_len; + a->packets++; + a->bytes += pd.tot_len; } if (s != NULL) { + dirndx = (dir == s->direction) ? 0 : 1; + s->packets[dirndx]++; + s->bytes[dirndx] += pd.tot_len; if (s->nat_rule.ptr != NULL) { - s->nat_rule.ptr->packets[dirndx]++; - s->nat_rule.ptr->bytes[dirndx] += pd.tot_len; + s->nat_rule.ptr->packets++; + s->nat_rule.ptr->bytes += pd.tot_len; } if (s->src_node != NULL) { - s->src_node->packets[dirndx]++; - s->src_node->bytes[dirndx] += pd.tot_len; + s->src_node->packets++; + s->src_node->bytes += pd.tot_len; } if (s->nat_src_node != NULL) { - s->nat_src_node->packets[dirndx]++; - s->nat_src_node->bytes[dirndx] += pd.tot_len; + s->nat_src_node->packets++; + s->nat_src_node->bytes += pd.tot_len; } - dirndx = (dir == s->direction) ? 0 : 1; - s->packets[dirndx]++; - s->bytes[dirndx] += pd.tot_len; } tr = r; nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule; @@ -6229,7 +6752,11 @@ done: action = PF_PASS; } else if (r->rt) /* pf_route can free the mbuf causing *m0 to become NULL */ - pf_route(m0, r, dir, ifp, s, &pd); + pf_route(m0, r, dir, ifp, s); + +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif return (action); } @@ -6237,48 +6764,71 @@ done: #ifdef INET6 int +#ifdef __FreeBSD__ +pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, + struct ether_header *eh, struct inpcb *inp) +#else pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct ether_header *eh) +#endif { struct pfi_kif *kif; u_short action, reason = 0, log = 0; - struct mbuf *m = *m0, *n = NULL; - struct ip6_hdr *h; + struct mbuf *m = *m0; + struct ip6_hdr *h = NULL; /* make the compiler happy */ struct pf_rule *a = NULL, *r = &pf_default_rule, *tr, *nr; struct pf_state *s = NULL; struct pf_ruleset *ruleset = NULL; struct pf_pdesc pd; - int off, terminal = 0, dirndx; + int off, terminal = 0, dirndx, rh_cnt = 0; - if (!pf_status.running) - return (PF_PASS); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif - memset(&pd, 0, sizeof(pd)); - if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) { - DPFPRINTF(PF_DEBUG_URGENT, - ("pf_test6: pf_get_mtag returned NULL\n")); - return (PF_DROP); - } - if (pd.pf_mtag->flags & PF_TAG_GENERATED) + if (!pf_status.running || +#ifdef __FreeBSD__ + (m->m_flags & M_SKIP_FIREWALL)) { + PF_UNLOCK(); +#else + (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) { +#endif return (PF_PASS); + } +#ifdef __FreeBSD__ + /* XXX_IMPORT: later */ +#else if (ifp->if_type == IFT_CARP && ifp->if_carpdev) ifp = ifp->if_carpdev; +#endif - kif = (struct pfi_kif *)ifp->if_pf_kif; + kif = pfi_index2kif[ifp->if_index]; if (kif == NULL) { +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif DPFPRINTF(PF_DEBUG_URGENT, ("pf_test6: kif == NULL, if_xname %s\n", ifp->if_xname)); return (PF_DROP); } - if (kif->pfik_flags & PFI_IFLAG_SKIP) + if (kif->pfik_flags & PFI_IFLAG_SKIP) { +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif return (PF_PASS); + } +#ifdef __FreeBSD__ + M_ASSERTPKTHDR(m); +#else #ifdef DIAGNOSTIC if ((m->m_flags & M_PKTHDR) == 0) panic("non-M_PKTHDR is passed to pf_test6"); #endif /* DIAGNOSTIC */ +#endif + memset(&pd, 0, sizeof(pd)); if (m->m_pkthdr.len < (int)sizeof(*h)) { action = PF_DROP; REASON_SET(&reason, PFRES_SHORT); @@ -6327,62 +6877,33 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, goto done; case IPPROTO_ROUTING: { struct ip6_rthdr rthdr; - struct ip6_rthdr0 rthdr0; - struct in6_addr finaldst; - struct ip6_hdr *ip6; + if (rh_cnt++) { + DPFPRINTF(PF_DEBUG_MISC, + ("pf: IPv6 more than one rthdr\n")); + action = PF_DROP; + REASON_SET(&reason, PFRES_IPOPTIONS); + log = 1; + goto done; + } if (!pf_pull_hdr(m, off, &rthdr, sizeof(rthdr), NULL, &reason, pd.af)) { DPFPRINTF(PF_DEBUG_MISC, ("pf: IPv6 short rthdr\n")); action = PF_DROP; + REASON_SET(&reason, PFRES_SHORT); log = 1; goto done; } if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) { - if (!pf_pull_hdr(m, off, &rthdr0, - sizeof(rthdr0), NULL, &reason, pd.af)) { - DPFPRINTF(PF_DEBUG_MISC, - ("pf: IPv6 short rthdr0\n")); - action = PF_DROP; - log = 1; - goto done; - } - if (rthdr0.ip6r0_segleft != 0) { - if (!pf_pull_hdr(m, off + - sizeof(rthdr0) + - rthdr0.ip6r0_len * 8 - - sizeof(finaldst), &finaldst, - sizeof(finaldst), NULL, - &reason, pd.af)) { - DPFPRINTF(PF_DEBUG_MISC, - ("pf: IPv6 short rthdr0\n")); - action = PF_DROP; - log = 1; - goto done; - } - - n = m_copym(m, 0, M_COPYALL, M_DONTWAIT); - if (!n) { - DPFPRINTF(PF_DEBUG_MISC, - ("pf: mbuf shortage\n")); - action = PF_DROP; - log = 1; - goto done; - } - n = m_pullup(n, sizeof(struct ip6_hdr)); - if (!n) { - DPFPRINTF(PF_DEBUG_MISC, - ("pf: mbuf shortage\n")); - action = PF_DROP; - log = 1; - goto done; - } - ip6 = mtod(n, struct ip6_hdr *); - ip6->ip6_dst = finaldst; - } + DPFPRINTF(PF_DEBUG_MISC, + ("pf: IPv6 rthdr0\n")); + action = PF_DROP; + REASON_SET(&reason, PFRES_IPOPTIONS); + log = 1; + goto done; } - /* FALLTHROUGH */ + /* fallthrough */ } case IPPROTO_AH: case IPPROTO_HOPOPTS: @@ -6412,10 +6933,6 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, } } while (!terminal); - /* if there's no routing header, use unmodified mbuf for checksumming */ - if (!n) - n = m; - switch (pd.proto) { case IPPROTO_TCP: { @@ -6427,7 +6944,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, log = action != PF_PASS; goto done; } - if (dir == PF_IN && pf_check_proto_cksum(n, off, + if (dir == PF_IN && pf_check_proto_cksum(m, off, ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)), IPPROTO_TCP, AF_INET6)) { action = PF_DROP; @@ -6448,8 +6965,13 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, a = s->anchor.ptr; log = s->log; } else if (s == NULL) +#ifdef __FreeBSD__ + action = pf_test_tcp(&r, &s, dir, kif, + m, off, h, &pd, &a, &ruleset, NULL, inp); +#else action = pf_test_tcp(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ip6intrq); +#endif break; } @@ -6462,7 +6984,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, log = action != PF_PASS; goto done; } - if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(n, + if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m, off, ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)), IPPROTO_UDP, AF_INET6)) { action = PF_DROP; @@ -6473,7 +6995,6 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, ntohs(uh.uh_ulen) > m->m_pkthdr.len - off || ntohs(uh.uh_ulen) < sizeof(struct udphdr)) { action = PF_DROP; - REASON_SET(&reason, PFRES_SHORT); goto done; } action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd); @@ -6485,8 +7006,13 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, a = s->anchor.ptr; log = s->log; } else if (s == NULL) +#ifdef __FreeBSD__ + action = pf_test_udp(&r, &s, dir, kif, + m, off, h, &pd, &a, &ruleset, NULL, inp); +#else action = pf_test_udp(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ip6intrq); +#endif break; } @@ -6499,7 +7025,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, log = action != PF_PASS; goto done; } - if (dir == PF_IN && pf_check_proto_cksum(n, off, + if (dir == PF_IN && pf_check_proto_cksum(m, off, ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)), IPPROTO_ICMPV6, AF_INET6)) { action = PF_DROP; @@ -6516,8 +7042,13 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, a = s->anchor.ptr; log = s->log; } else if (s == NULL) +#ifdef __FreeBSD__ + action = pf_test_icmp(&r, &s, dir, kif, + m, off, h, &pd, &a, &ruleset, NULL); +#else action = pf_test_icmp(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ip6intrq); +#endif break; } @@ -6531,31 +7062,47 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, a = s->anchor.ptr; log = s->log; } else if (s == NULL) +#ifdef __FreeBSD__ + action = pf_test_other(&r, &s, dir, kif, m, off, h, + &pd, &a, &ruleset, NULL); +#else action = pf_test_other(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ip6intrq); +#endif break; } done: - if (n != m) { - m_freem(n); - n = NULL; + /* handle dangerous IPv6 extension headers. */ + if (action == PF_PASS && rh_cnt && + !((s && s->allow_opts) || r->allow_opts)) { + action = PF_DROP; + REASON_SET(&reason, PFRES_IPOPTIONS); + log = 1; + DPFPRINTF(PF_DEBUG_MISC, + ("pf: dropping packet with dangerous v6 headers\n")); } - /* XXX handle IPv6 options, if not allowed. not implemented. */ - - if ((s && s->tag) || r->rtableid) - pf_tag_packet(m, pd.pf_mtag, s ? s->tag : 0, r->rtableid); + if (s && s->tag) + pf_tag_packet(m, pf_get_tag(m), s->tag); #ifdef ALTQ if (action == PF_PASS && r->qid) { - if (pd.tos & IPTOS_LOWDELAY) - pd.pf_mtag->qid = r->pqid; - else - pd.pf_mtag->qid = r->qid; - /* add hints for ecn */ - pd.pf_mtag->af = AF_INET6; - pd.pf_mtag->hdr = h; + struct m_tag *mtag; + struct altq_tag *atag; + + mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT); + if (mtag != NULL) { + atag = (struct altq_tag *)(mtag + 1); + if (pd.tos == IPTOS_LOWDELAY) + atag->qid = r->pqid; + else + atag->qid = r->qid; + /* add hints for ecn */ + atag->af = AF_INET6; + atag->hdr = h; + m_tag_prepend(m, mtag); + } } #endif /* ALTQ */ @@ -6563,48 +7110,41 @@ done: pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL && (s->nat_rule.ptr->action == PF_RDR || s->nat_rule.ptr->action == PF_BINAT) && - IN6_IS_ADDR_LOOPBACK(&pd.dst->v6)) - pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST; - - if (log) { - struct pf_rule *lr; - - if (s != NULL && s->nat_rule.ptr != NULL && - s->nat_rule.ptr->log & PF_LOG_ALL) - lr = s->nat_rule.ptr; - else - lr = r; - PFLOG_PACKET(kif, h, m, AF_INET6, dir, reason, lr, a, ruleset, - &pd); + IN6_IS_ADDR_LOOPBACK(&pd.dst->v6) && + pf_add_mbuf_tag(m, PACKET_TAG_PF_TRANSLATE_LOCALHOST)) { + action = PF_DROP; + REASON_SET(&reason, PFRES_MEMORY); } + if (log) + PFLOG_PACKET(kif, h, m, AF_INET6, dir, reason, r, a, ruleset); + kif->pfik_bytes[1][dir == PF_OUT][action != PF_PASS] += pd.tot_len; kif->pfik_packets[1][dir == PF_OUT][action != PF_PASS]++; if (action == PF_PASS || r->action == PF_DROP) { - dirndx = (dir == PF_OUT); - r->packets[dirndx]++; - r->bytes[dirndx] += pd.tot_len; + r->packets++; + r->bytes += pd.tot_len; if (a != NULL) { - a->packets[dirndx]++; - a->bytes[dirndx] += pd.tot_len; + a->packets++; + a->bytes += pd.tot_len; } if (s != NULL) { + dirndx = (dir == s->direction) ? 0 : 1; + s->packets[dirndx]++; + s->bytes[dirndx] += pd.tot_len; if (s->nat_rule.ptr != NULL) { - s->nat_rule.ptr->packets[dirndx]++; - s->nat_rule.ptr->bytes[dirndx] += pd.tot_len; + s->nat_rule.ptr->packets++; + s->nat_rule.ptr->bytes += pd.tot_len; } if (s->src_node != NULL) { - s->src_node->packets[dirndx]++; - s->src_node->bytes[dirndx] += pd.tot_len; + s->src_node->packets++; + s->src_node->bytes += pd.tot_len; } if (s->nat_src_node != NULL) { - s->nat_src_node->packets[dirndx]++; - s->nat_src_node->bytes[dirndx] += pd.tot_len; + s->nat_src_node->packets++; + s->nat_src_node->bytes += pd.tot_len; } - dirndx = (dir == s->direction) ? 0 : 1; - s->packets[dirndx]++; - s->bytes[dirndx] += pd.tot_len; } tr = r; nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule; @@ -6649,8 +7189,11 @@ done: action = PF_PASS; } else if (r->rt) /* pf_route6 can free the mbuf causing *m0 to become NULL */ - pf_route6(m0, r, dir, ifp, s, &pd); + pf_route6(m0, r, dir, ifp, s); +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif return (action); } #endif /* INET6 */ @@ -6658,8 +7201,13 @@ done: int pf_check_congestion(struct ifqueue *ifq) { +#ifdef __FreeBSD__ + /* XXX_IMPORT: later */ + return (0); +#else if (ifq->ifq_congestion) return (1); else return (0); +#endif } |