Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/pf/pf.c
Show First 20 Lines • Show All 175 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Queue for pf_overload_task() tasks. | * Queue for pf_overload_task() tasks. | ||||
*/ | */ | ||||
struct pf_overload_entry { | struct pf_overload_entry { | ||||
SLIST_ENTRY(pf_overload_entry) next; | SLIST_ENTRY(pf_overload_entry) next; | ||||
struct pf_addr addr; | struct pf_addr addr; | ||||
sa_family_t af; | sa_family_t af; | ||||
uint8_t dir; | uint8_t dir; | ||||
struct pf_rule *rule; | struct pf_krule *rule; | ||||
}; | }; | ||||
SLIST_HEAD(pf_overload_head, pf_overload_entry); | SLIST_HEAD(pf_overload_head, pf_overload_entry); | ||||
VNET_DEFINE_STATIC(struct pf_overload_head, pf_overloadqueue); | VNET_DEFINE_STATIC(struct pf_overload_head, pf_overloadqueue); | ||||
#define V_pf_overloadqueue VNET(pf_overloadqueue) | #define V_pf_overloadqueue VNET(pf_overloadqueue) | ||||
VNET_DEFINE_STATIC(struct task, pf_overloadtask); | VNET_DEFINE_STATIC(struct task, pf_overloadtask); | ||||
#define V_pf_overloadtask VNET(pf_overloadtask) | #define V_pf_overloadtask VNET(pf_overloadtask) | ||||
static struct mtx pf_overloadqueue_mtx; | static struct mtx pf_overloadqueue_mtx; | ||||
MTX_SYSINIT(pf_overloadqueue_mtx, &pf_overloadqueue_mtx, | MTX_SYSINIT(pf_overloadqueue_mtx, &pf_overloadqueue_mtx, | ||||
"pf overload/flush queue", MTX_DEF); | "pf overload/flush queue", MTX_DEF); | ||||
#define PF_OVERLOADQ_LOCK() mtx_lock(&pf_overloadqueue_mtx) | #define PF_OVERLOADQ_LOCK() mtx_lock(&pf_overloadqueue_mtx) | ||||
#define PF_OVERLOADQ_UNLOCK() mtx_unlock(&pf_overloadqueue_mtx) | #define PF_OVERLOADQ_UNLOCK() mtx_unlock(&pf_overloadqueue_mtx) | ||||
VNET_DEFINE(struct pf_rulequeue, pf_unlinked_rules); | VNET_DEFINE(struct pf_krulequeue, pf_unlinked_rules); | ||||
struct mtx pf_unlnkdrules_mtx; | struct mtx pf_unlnkdrules_mtx; | ||||
MTX_SYSINIT(pf_unlnkdrules_mtx, &pf_unlnkdrules_mtx, "pf unlinked rules", | MTX_SYSINIT(pf_unlnkdrules_mtx, &pf_unlnkdrules_mtx, "pf unlinked rules", | ||||
MTX_DEF); | MTX_DEF); | ||||
VNET_DEFINE_STATIC(uma_zone_t, pf_sources_z); | VNET_DEFINE_STATIC(uma_zone_t, pf_sources_z); | ||||
#define V_pf_sources_z VNET(pf_sources_z) | #define V_pf_sources_z VNET(pf_sources_z) | ||||
uma_zone_t pf_mtag_z; | uma_zone_t pf_mtag_z; | ||||
VNET_DEFINE(uma_zone_t, pf_state_z); | VNET_DEFINE(uma_zone_t, pf_state_z); | ||||
Show All 17 Lines | static void pf_change_ap(struct mbuf *, struct pf_addr *, u_int16_t *, | ||||
u_int16_t, u_int8_t, sa_family_t); | u_int16_t, u_int8_t, sa_family_t); | ||||
static int pf_modulate_sack(struct mbuf *, int, struct pf_pdesc *, | static int pf_modulate_sack(struct mbuf *, int, struct pf_pdesc *, | ||||
struct tcphdr *, struct pf_state_peer *); | struct tcphdr *, struct pf_state_peer *); | ||||
static void pf_change_icmp(struct pf_addr *, u_int16_t *, | static void pf_change_icmp(struct pf_addr *, u_int16_t *, | ||||
struct pf_addr *, 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_int16_t *, u_int16_t *, | ||||
u_int16_t *, u_int8_t, sa_family_t); | u_int16_t *, u_int8_t, sa_family_t); | ||||
static void pf_send_tcp(struct mbuf *, | static void pf_send_tcp(struct mbuf *, | ||||
const struct pf_rule *, sa_family_t, | const struct pf_krule *, sa_family_t, | ||||
const struct pf_addr *, const struct pf_addr *, | const struct pf_addr *, const struct pf_addr *, | ||||
u_int16_t, u_int16_t, u_int32_t, u_int32_t, | 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_int8_t, u_int16_t, u_int16_t, u_int8_t, int, | ||||
u_int16_t, struct ifnet *); | u_int16_t, struct ifnet *); | ||||
static void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t, | static void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t, | ||||
sa_family_t, struct pf_rule *); | sa_family_t, struct pf_krule *); | ||||
static void pf_detach_state(struct pf_state *); | static void pf_detach_state(struct pf_state *); | ||||
static int pf_state_key_attach(struct pf_state_key *, | static int pf_state_key_attach(struct pf_state_key *, | ||||
struct pf_state_key *, struct pf_state *); | struct pf_state_key *, struct pf_state *); | ||||
static void pf_state_key_detach(struct pf_state *, int); | static void pf_state_key_detach(struct pf_state *, int); | ||||
static int pf_state_key_ctor(void *, int, void *, int); | static int pf_state_key_ctor(void *, int, void *, int); | ||||
static u_int32_t pf_tcp_iss(struct pf_pdesc *); | static u_int32_t pf_tcp_iss(struct pf_pdesc *); | ||||
static int pf_test_rule(struct pf_rule **, struct pf_state **, | static int pf_test_rule(struct pf_krule **, struct pf_state **, | ||||
int, struct pfi_kif *, struct mbuf *, int, | int, struct pfi_kif *, struct mbuf *, int, | ||||
struct pf_pdesc *, struct pf_rule **, | struct pf_pdesc *, struct pf_krule **, | ||||
struct pf_ruleset **, struct inpcb *); | struct pf_kruleset **, struct inpcb *); | ||||
static int pf_create_state(struct pf_rule *, struct pf_rule *, | static int pf_create_state(struct pf_krule *, struct pf_krule *, | ||||
struct pf_rule *, struct pf_pdesc *, | struct pf_krule *, struct pf_pdesc *, | ||||
struct pf_ksrc_node *, struct pf_state_key *, | struct pf_ksrc_node *, struct pf_state_key *, | ||||
struct pf_state_key *, struct mbuf *, int, | struct pf_state_key *, struct mbuf *, int, | ||||
u_int16_t, u_int16_t, int *, struct pfi_kif *, | u_int16_t, u_int16_t, int *, struct pfi_kif *, | ||||
struct pf_state **, int, u_int16_t, u_int16_t, | struct pf_state **, int, u_int16_t, u_int16_t, | ||||
int); | int); | ||||
static int pf_test_fragment(struct pf_rule **, int, | static int pf_test_fragment(struct pf_krule **, int, | ||||
struct pfi_kif *, struct mbuf *, void *, | struct pfi_kif *, struct mbuf *, void *, | ||||
struct pf_pdesc *, struct pf_rule **, | struct pf_pdesc *, struct pf_krule **, | ||||
struct pf_ruleset **); | struct pf_kruleset **); | ||||
static int pf_tcp_track_full(struct pf_state_peer *, | static int pf_tcp_track_full(struct pf_state_peer *, | ||||
struct pf_state_peer *, struct pf_state **, | struct pf_state_peer *, struct pf_state **, | ||||
struct pfi_kif *, struct mbuf *, int, | struct pfi_kif *, struct mbuf *, int, | ||||
struct pf_pdesc *, u_short *, int *); | struct pf_pdesc *, u_short *, int *); | ||||
static int pf_tcp_track_sloppy(struct pf_state_peer *, | static int pf_tcp_track_sloppy(struct pf_state_peer *, | ||||
struct pf_state_peer *, struct pf_state **, | struct pf_state_peer *, struct pf_state **, | ||||
struct pf_pdesc *, u_short *); | struct pf_pdesc *, u_short *); | ||||
static int pf_test_state_tcp(struct pf_state **, int, | static int pf_test_state_tcp(struct pf_state **, int, | ||||
Show All 21 Lines | static int pf_addr_wrap_neq(struct pf_addr_wrap *, | ||||
struct pf_addr_wrap *); | struct pf_addr_wrap *); | ||||
static void pf_patch_8(struct mbuf *, u_int16_t *, u_int8_t *, u_int8_t, | static void pf_patch_8(struct mbuf *, u_int16_t *, u_int8_t *, u_int8_t, | ||||
bool, u_int8_t); | bool, u_int8_t); | ||||
static struct pf_state *pf_find_state(struct pfi_kif *, | static struct pf_state *pf_find_state(struct pfi_kif *, | ||||
struct pf_state_key_cmp *, u_int); | struct pf_state_key_cmp *, u_int); | ||||
static int pf_src_connlimit(struct pf_state **); | static int pf_src_connlimit(struct pf_state **); | ||||
static void pf_overload_task(void *v, int pending); | static void pf_overload_task(void *v, int pending); | ||||
static int pf_insert_src_node(struct pf_ksrc_node **, | static int pf_insert_src_node(struct pf_ksrc_node **, | ||||
struct pf_rule *, struct pf_addr *, sa_family_t); | struct pf_krule *, struct pf_addr *, sa_family_t); | ||||
static u_int pf_purge_expired_states(u_int, int); | static u_int pf_purge_expired_states(u_int, int); | ||||
static void pf_purge_unlinked_rules(void); | static void pf_purge_unlinked_rules(void); | ||||
static int pf_mtag_uminit(void *, int, int); | static int pf_mtag_uminit(void *, int, int); | ||||
static void pf_mtag_free(struct m_tag *); | static void pf_mtag_free(struct m_tag *); | ||||
#ifdef INET | #ifdef INET | ||||
static void pf_route(struct mbuf **, struct pf_rule *, int, | static void pf_route(struct mbuf **, struct pf_krule *, int, | ||||
struct ifnet *, struct pf_state *, | struct ifnet *, struct pf_state *, | ||||
struct pf_pdesc *, struct inpcb *); | struct pf_pdesc *, struct inpcb *); | ||||
#endif /* INET */ | #endif /* INET */ | ||||
#ifdef INET6 | #ifdef INET6 | ||||
static void pf_change_a6(struct pf_addr *, u_int16_t *, | static void pf_change_a6(struct pf_addr *, u_int16_t *, | ||||
struct pf_addr *, u_int8_t); | struct pf_addr *, u_int8_t); | ||||
static void pf_route6(struct mbuf **, struct pf_rule *, int, | static void pf_route6(struct mbuf **, struct pf_krule *, int, | ||||
struct ifnet *, struct pf_state *, | struct ifnet *, struct pf_state *, | ||||
struct pf_pdesc *, struct inpcb *); | struct pf_pdesc *, struct inpcb *); | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
int in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len); | int in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len); | ||||
extern int pf_end_threads; | extern int pf_end_threads; | ||||
extern struct proc *pf_purge_proc; | extern struct proc *pf_purge_proc; | ||||
▲ Show 20 Lines • Show All 353 Lines • ▼ Show 20 Lines | #endif | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
} | } | ||||
/* | /* | ||||
* Can return locked on failure, so that we can consistently | * Can return locked on failure, so that we can consistently | ||||
* allocate and insert a new one. | * allocate and insert a new one. | ||||
*/ | */ | ||||
struct pf_ksrc_node * | struct pf_ksrc_node * | ||||
pf_find_src_node(struct pf_addr *src, struct pf_rule *rule, sa_family_t af, | pf_find_src_node(struct pf_addr *src, struct pf_krule *rule, sa_family_t af, | ||||
int returnlocked) | int returnlocked) | ||||
{ | { | ||||
struct pf_srchash *sh; | struct pf_srchash *sh; | ||||
struct pf_ksrc_node *n; | struct pf_ksrc_node *n; | ||||
counter_u64_add(V_pf_status.scounters[SCNT_SRC_NODE_SEARCH], 1); | counter_u64_add(V_pf_status.scounters[SCNT_SRC_NODE_SEARCH], 1); | ||||
sh = &V_pf_srchash[pf_hashsrc(src, af)]; | sh = &V_pf_srchash[pf_hashsrc(src, af)]; | ||||
Show All 21 Lines | if (sn->bytes[i]) | ||||
counter_u64_free(sn->bytes[i]); | counter_u64_free(sn->bytes[i]); | ||||
if (sn->packets[i]) | if (sn->packets[i]) | ||||
counter_u64_free(sn->packets[i]); | counter_u64_free(sn->packets[i]); | ||||
} | } | ||||
uma_zfree(V_pf_sources_z, sn); | uma_zfree(V_pf_sources_z, sn); | ||||
} | } | ||||
static int | static int | ||||
pf_insert_src_node(struct pf_ksrc_node **sn, struct pf_rule *rule, | pf_insert_src_node(struct pf_ksrc_node **sn, struct pf_krule *rule, | ||||
struct pf_addr *src, sa_family_t af) | struct pf_addr *src, sa_family_t af) | ||||
{ | { | ||||
KASSERT((rule->rule_flag & PFRULE_SRCTRACK || | KASSERT((rule->rule_flag & PFRULE_SRCTRACK || | ||||
rule->rpool.opts & PF_POOL_STICKYADDR), | rule->rpool.opts & PF_POOL_STICKYADDR), | ||||
("%s for non-tracking rule %p", __func__, rule)); | ("%s for non-tracking rule %p", __func__, rule)); | ||||
if (*sn == NULL) | if (*sn == NULL) | ||||
▲ Show 20 Lines • Show All 1,073 Lines • ▼ Show 20 Lines | relock: | ||||
V_pf_status.states = uma_zone_get_cur(V_pf_state_z); | V_pf_status.states = uma_zone_get_cur(V_pf_state_z); | ||||
return (i); | return (i); | ||||
} | } | ||||
static void | static void | ||||
pf_purge_unlinked_rules() | pf_purge_unlinked_rules() | ||||
{ | { | ||||
struct pf_rulequeue tmpq; | struct pf_krulequeue tmpq; | ||||
struct pf_rule *r, *r1; | struct pf_krule *r, *r1; | ||||
/* | /* | ||||
* If we have overloading task pending, then we'd | * If we have overloading task pending, then we'd | ||||
* better skip purging this time. There is a tiny | * better skip purging this time. There is a tiny | ||||
* probability that overloading task references | * probability that overloading task references | ||||
* an already unlinked rule. | * an already unlinked rule. | ||||
*/ | */ | ||||
PF_OVERLOADQ_LOCK(); | PF_OVERLOADQ_LOCK(); | ||||
▲ Show 20 Lines • Show All 208 Lines • ▼ Show 20 Lines | #define PF_SET_SKIP_STEPS(i) \ | ||||
do { \ | do { \ | ||||
while (head[i] != cur) { \ | while (head[i] != cur) { \ | ||||
head[i]->skip[i].ptr = cur; \ | head[i]->skip[i].ptr = cur; \ | ||||
head[i] = TAILQ_NEXT(head[i], entries); \ | head[i] = TAILQ_NEXT(head[i], entries); \ | ||||
} \ | } \ | ||||
} while (0) | } while (0) | ||||
void | void | ||||
pf_calc_skip_steps(struct pf_rulequeue *rules) | pf_calc_skip_steps(struct pf_krulequeue *rules) | ||||
{ | { | ||||
struct pf_rule *cur, *prev, *head[PF_SKIP_COUNT]; | struct pf_krule *cur, *prev, *head[PF_SKIP_COUNT]; | ||||
int i; | int i; | ||||
cur = TAILQ_FIRST(rules); | cur = TAILQ_FIRST(rules); | ||||
prev = cur; | prev = cur; | ||||
for (i = 0; i < PF_SKIP_COUNT; ++i) | for (i = 0; i < PF_SKIP_COUNT; ++i) | ||||
head[i] = cur; | head[i] = cur; | ||||
while (cur != NULL) { | while (cur != NULL) { | ||||
if (cur->kif != prev->kif || cur->ifnot != prev->ifnot) | if (cur->kif != prev->kif || cur->ifnot != prev->ifnot) | ||||
▲ Show 20 Lines • Show All 389 Lines • ▼ Show 20 Lines | #define TCPOLEN_SACKLEN (TCPOLEN_SACK + 2) | ||||
} | } | ||||
if (copyback) | if (copyback) | ||||
m_copyback(m, off + sizeof(*th), thoptlen, (caddr_t)opts); | m_copyback(m, off + sizeof(*th), thoptlen, (caddr_t)opts); | ||||
return (copyback); | return (copyback); | ||||
} | } | ||||
static void | static void | ||||
pf_send_tcp(struct mbuf *replyto, const struct pf_rule *r, sa_family_t af, | pf_send_tcp(struct mbuf *replyto, const struct pf_krule *r, sa_family_t af, | ||||
const struct pf_addr *saddr, const struct pf_addr *daddr, | 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_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_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, int tag, | ||||
u_int16_t rtag, struct ifnet *ifp) | u_int16_t rtag, struct ifnet *ifp) | ||||
{ | { | ||||
struct pf_send_entry *pfse; | struct pf_send_entry *pfse; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
int len, tlen; | int len, tlen; | ||||
▲ Show 20 Lines • Show All 143 Lines • ▼ Show 20 Lines | case AF_INET6: | ||||
break; | break; | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
} | } | ||||
pfse->pfse_m = m; | pfse->pfse_m = m; | ||||
pf_send(pfse); | pf_send(pfse); | ||||
} | } | ||||
static void | static void | ||||
pf_return(struct pf_rule *r, struct pf_rule *nr, struct pf_pdesc *pd, | pf_return(struct pf_krule *r, struct pf_krule *nr, struct pf_pdesc *pd, | ||||
struct pf_state_key *sk, int off, struct mbuf *m, struct tcphdr *th, | struct pf_state_key *sk, int off, struct mbuf *m, struct tcphdr *th, | ||||
struct pfi_kif *kif, u_int16_t bproto_sum, u_int16_t bip_sum, int hdrlen, | struct pfi_kif *kif, u_int16_t bproto_sum, u_int16_t bip_sum, int hdrlen, | ||||
u_short *reason) | u_short *reason) | ||||
{ | { | ||||
struct pf_addr * const saddr = pd->src; | struct pf_addr * const saddr = pd->src; | ||||
struct pf_addr * const daddr = pd->dst; | struct pf_addr * const daddr = pd->dst; | ||||
sa_family_t af = pd->af; | sa_family_t af = pd->af; | ||||
▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | pf_match_ieee8021q_pcp(u_int8_t prio, struct mbuf *m) | ||||
mpcp = *(uint8_t *)(mtag + 1); | mpcp = *(uint8_t *)(mtag + 1); | ||||
return (mpcp == prio); | return (mpcp == prio); | ||||
} | } | ||||
static void | static void | ||||
pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af, | pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af, | ||||
struct pf_rule *r) | struct pf_krule *r) | ||||
{ | { | ||||
struct pf_send_entry *pfse; | struct pf_send_entry *pfse; | ||||
struct mbuf *m0; | struct mbuf *m0; | ||||
struct pf_mtag *pf_mtag; | struct pf_mtag *pf_mtag; | ||||
/* Allocate outgoing queue entry, mbuf and mbuf tag. */ | /* Allocate outgoing queue entry, mbuf and mbuf tag. */ | ||||
pfse = malloc(sizeof(*pfse), M_PFTEMP, M_NOWAIT); | pfse = malloc(sizeof(*pfse), M_PFTEMP, M_NOWAIT); | ||||
if (pfse == NULL) | if (pfse == NULL) | ||||
▲ Show 20 Lines • Show All 171 Lines • ▼ Show 20 Lines | |||||
pf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g) | pf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g) | ||||
{ | { | ||||
if (g == GID_MAX && op != PF_OP_EQ && op != PF_OP_NE) | if (g == GID_MAX && op != PF_OP_EQ && op != PF_OP_NE) | ||||
return (0); | return (0); | ||||
return (pf_match(op, a1, a2, g)); | return (pf_match(op, a1, a2, g)); | ||||
} | } | ||||
int | int | ||||
pf_match_tag(struct mbuf *m, struct pf_rule *r, int *tag, int mtag) | pf_match_tag(struct mbuf *m, struct pf_krule *r, int *tag, int mtag) | ||||
{ | { | ||||
if (*tag == -1) | if (*tag == -1) | ||||
*tag = mtag; | *tag = mtag; | ||||
return ((!r->match_tag_not && r->match_tag == *tag) || | return ((!r->match_tag_not && r->match_tag == *tag) || | ||||
(r->match_tag_not && r->match_tag != *tag)); | (r->match_tag_not && r->match_tag != *tag)); | ||||
} | } | ||||
int | int | ||||
pf_tag_packet(struct mbuf *m, struct pf_pdesc *pd, int tag) | pf_tag_packet(struct mbuf *m, struct pf_pdesc *pd, int tag) | ||||
{ | { | ||||
KASSERT(tag > 0, ("%s: tag %d", __func__, tag)); | KASSERT(tag > 0, ("%s: tag %d", __func__, tag)); | ||||
if (pd->pf_mtag == NULL && ((pd->pf_mtag = pf_get_mtag(m)) == NULL)) | if (pd->pf_mtag == NULL && ((pd->pf_mtag = pf_get_mtag(m)) == NULL)) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
pd->pf_mtag->tag = tag; | pd->pf_mtag->tag = tag; | ||||
return (0); | return (0); | ||||
} | } | ||||
#define PF_ANCHOR_STACKSIZE 32 | #define PF_ANCHOR_STACKSIZE 32 | ||||
struct pf_anchor_stackframe { | struct pf_kanchor_stackframe { | ||||
struct pf_ruleset *rs; | struct pf_kruleset *rs; | ||||
struct pf_rule *r; /* XXX: + match bit */ | struct pf_krule *r; /* XXX: + match bit */ | ||||
struct pf_anchor *child; | struct pf_kanchor *child; | ||||
}; | }; | ||||
/* | /* | ||||
* XXX: We rely on malloc(9) returning pointer aligned addresses. | * XXX: We rely on malloc(9) returning pointer aligned addresses. | ||||
*/ | */ | ||||
#define PF_ANCHORSTACK_MATCH 0x00000001 | #define PF_ANCHORSTACK_MATCH 0x00000001 | ||||
#define PF_ANCHORSTACK_MASK (PF_ANCHORSTACK_MATCH) | #define PF_ANCHORSTACK_MASK (PF_ANCHORSTACK_MATCH) | ||||
#define PF_ANCHOR_MATCH(f) ((uintptr_t)(f)->r & PF_ANCHORSTACK_MATCH) | #define PF_ANCHOR_MATCH(f) ((uintptr_t)(f)->r & PF_ANCHORSTACK_MATCH) | ||||
#define PF_ANCHOR_RULE(f) (struct pf_rule *) \ | #define PF_ANCHOR_RULE(f) (struct pf_krule *) \ | ||||
((uintptr_t)(f)->r & ~PF_ANCHORSTACK_MASK) | ((uintptr_t)(f)->r & ~PF_ANCHORSTACK_MASK) | ||||
#define PF_ANCHOR_SET_MATCH(f) do { (f)->r = (void *) \ | #define PF_ANCHOR_SET_MATCH(f) do { (f)->r = (void *) \ | ||||
((uintptr_t)(f)->r | PF_ANCHORSTACK_MATCH); \ | ((uintptr_t)(f)->r | PF_ANCHORSTACK_MATCH); \ | ||||
} while (0) | } while (0) | ||||
void | void | ||||
pf_step_into_anchor(struct pf_anchor_stackframe *stack, int *depth, | pf_step_into_anchor(struct pf_kanchor_stackframe *stack, int *depth, | ||||
struct pf_ruleset **rs, int n, struct pf_rule **r, struct pf_rule **a, | struct pf_kruleset **rs, int n, struct pf_krule **r, struct pf_krule **a, | ||||
int *match) | int *match) | ||||
{ | { | ||||
struct pf_anchor_stackframe *f; | struct pf_kanchor_stackframe *f; | ||||
PF_RULES_RASSERT(); | PF_RULES_RASSERT(); | ||||
if (match) | if (match) | ||||
*match = 0; | *match = 0; | ||||
if (*depth >= PF_ANCHOR_STACKSIZE) { | if (*depth >= PF_ANCHOR_STACKSIZE) { | ||||
printf("%s: anchor stack overflow on %s\n", | printf("%s: anchor stack overflow on %s\n", | ||||
__func__, (*r)->anchor->name); | __func__, (*r)->anchor->name); | ||||
*r = TAILQ_NEXT(*r, entries); | *r = TAILQ_NEXT(*r, entries); | ||||
return; | return; | ||||
} else if (*depth == 0 && a != NULL) | } else if (*depth == 0 && a != NULL) | ||||
*a = *r; | *a = *r; | ||||
f = stack + (*depth)++; | f = stack + (*depth)++; | ||||
f->rs = *rs; | f->rs = *rs; | ||||
f->r = *r; | f->r = *r; | ||||
if ((*r)->anchor_wildcard) { | if ((*r)->anchor_wildcard) { | ||||
struct pf_anchor_node *parent = &(*r)->anchor->children; | struct pf_kanchor_node *parent = &(*r)->anchor->children; | ||||
if ((f->child = RB_MIN(pf_anchor_node, parent)) == NULL) { | if ((f->child = RB_MIN(pf_kanchor_node, parent)) == NULL) { | ||||
*r = NULL; | *r = NULL; | ||||
return; | return; | ||||
} | } | ||||
*rs = &f->child->ruleset; | *rs = &f->child->ruleset; | ||||
} else { | } else { | ||||
f->child = NULL; | f->child = NULL; | ||||
*rs = &(*r)->anchor->ruleset; | *rs = &(*r)->anchor->ruleset; | ||||
} | } | ||||
*r = TAILQ_FIRST((*rs)->rules[n].active.ptr); | *r = TAILQ_FIRST((*rs)->rules[n].active.ptr); | ||||
} | } | ||||
int | int | ||||
pf_step_out_of_anchor(struct pf_anchor_stackframe *stack, int *depth, | pf_step_out_of_anchor(struct pf_kanchor_stackframe *stack, int *depth, | ||||
struct pf_ruleset **rs, int n, struct pf_rule **r, struct pf_rule **a, | struct pf_kruleset **rs, int n, struct pf_krule **r, struct pf_krule **a, | ||||
int *match) | int *match) | ||||
{ | { | ||||
struct pf_anchor_stackframe *f; | struct pf_kanchor_stackframe *f; | ||||
struct pf_rule *fr; | struct pf_krule *fr; | ||||
int quick = 0; | int quick = 0; | ||||
PF_RULES_RASSERT(); | PF_RULES_RASSERT(); | ||||
do { | do { | ||||
if (*depth <= 0) | if (*depth <= 0) | ||||
break; | break; | ||||
f = stack + *depth - 1; | f = stack + *depth - 1; | ||||
fr = PF_ANCHOR_RULE(f); | fr = PF_ANCHOR_RULE(f); | ||||
if (f->child != NULL) { | if (f->child != NULL) { | ||||
struct pf_anchor_node *parent; | struct pf_kanchor_node *parent; | ||||
/* | /* | ||||
* This block traverses through | * This block traverses through | ||||
* a wildcard anchor. | * a wildcard anchor. | ||||
*/ | */ | ||||
parent = &fr->anchor->children; | parent = &fr->anchor->children; | ||||
if (match != NULL && *match) { | if (match != NULL && *match) { | ||||
/* | /* | ||||
* If any of "*" matched, then | * If any of "*" matched, then | ||||
* "foo/ *" matched, mark frame | * "foo/ *" matched, mark frame | ||||
* appropriately. | * appropriately. | ||||
*/ | */ | ||||
PF_ANCHOR_SET_MATCH(f); | PF_ANCHOR_SET_MATCH(f); | ||||
*match = 0; | *match = 0; | ||||
} | } | ||||
f->child = RB_NEXT(pf_anchor_node, parent, f->child); | f->child = RB_NEXT(pf_kanchor_node, parent, f->child); | ||||
if (f->child != NULL) { | if (f->child != NULL) { | ||||
*rs = &f->child->ruleset; | *rs = &f->child->ruleset; | ||||
*r = TAILQ_FIRST((*rs)->rules[n].active.ptr); | *r = TAILQ_FIRST((*rs)->rules[n].active.ptr); | ||||
if (*r == NULL) | if (*r == NULL) | ||||
continue; | continue; | ||||
else | else | ||||
break; | break; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 293 Lines • ▼ Show 20 Lines | pf_tcp_iss(struct pf_pdesc *pd) | ||||
V_pf_tcp_iss_off += 4096; | V_pf_tcp_iss_off += 4096; | ||||
#define ISN_RANDOM_INCREMENT (4096 - 1) | #define ISN_RANDOM_INCREMENT (4096 - 1) | ||||
return (digest[0] + (arc4random() & ISN_RANDOM_INCREMENT) + | return (digest[0] + (arc4random() & ISN_RANDOM_INCREMENT) + | ||||
V_pf_tcp_iss_off); | V_pf_tcp_iss_off); | ||||
#undef ISN_RANDOM_INCREMENT | #undef ISN_RANDOM_INCREMENT | ||||
} | } | ||||
static int | static int | ||||
pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, | pf_test_rule(struct pf_krule **rm, struct pf_state **sm, int direction, | ||||
struct pfi_kif *kif, struct mbuf *m, int off, struct pf_pdesc *pd, | struct pfi_kif *kif, struct mbuf *m, int off, struct pf_pdesc *pd, | ||||
struct pf_rule **am, struct pf_ruleset **rsm, struct inpcb *inp) | struct pf_krule **am, struct pf_kruleset **rsm, struct inpcb *inp) | ||||
{ | { | ||||
struct pf_rule *nr = NULL; | struct pf_krule *nr = NULL; | ||||
struct pf_addr * const saddr = pd->src; | struct pf_addr * const saddr = pd->src; | ||||
struct pf_addr * const daddr = pd->dst; | struct pf_addr * const daddr = pd->dst; | ||||
sa_family_t af = pd->af; | sa_family_t af = pd->af; | ||||
struct pf_rule *r, *a = NULL; | struct pf_krule *r, *a = NULL; | ||||
struct pf_ruleset *ruleset = NULL; | struct pf_kruleset *ruleset = NULL; | ||||
struct pf_ksrc_node *nsn = NULL; | struct pf_ksrc_node *nsn = NULL; | ||||
struct tcphdr *th = pd->hdr.tcp; | struct tcphdr *th = pd->hdr.tcp; | ||||
struct pf_state_key *sk = NULL, *nk = NULL; | struct pf_state_key *sk = NULL, *nk = NULL; | ||||
u_short reason; | u_short reason; | ||||
int rewrite = 0, hdrlen = 0; | int rewrite = 0, hdrlen = 0; | ||||
int tag = -1, rtableid = -1; | int tag = -1, rtableid = -1; | ||||
int asd = 0; | int asd = 0; | ||||
int match = 0; | int match = 0; | ||||
int state_icmp = 0; | int state_icmp = 0; | ||||
u_int16_t sport = 0, dport = 0; | u_int16_t sport = 0, dport = 0; | ||||
u_int16_t bproto_sum = 0, bip_sum = 0; | u_int16_t bproto_sum = 0, bip_sum = 0; | ||||
u_int8_t icmptype = 0, icmpcode = 0; | u_int8_t icmptype = 0, icmpcode = 0; | ||||
struct pf_anchor_stackframe anchor_stack[PF_ANCHOR_STACKSIZE]; | struct pf_kanchor_stackframe anchor_stack[PF_ANCHOR_STACKSIZE]; | ||||
PF_RULES_RASSERT(); | PF_RULES_RASSERT(); | ||||
if (inp != NULL) { | if (inp != NULL) { | ||||
INP_LOCK_ASSERT(inp); | INP_LOCK_ASSERT(inp); | ||||
pd->lookup.uid = inp->inp_cred->cr_uid; | pd->lookup.uid = inp->inp_cred->cr_uid; | ||||
pd->lookup.gid = inp->inp_cred->cr_groups[0]; | pd->lookup.gid = inp->inp_cred->cr_groups[0]; | ||||
pd->lookup.done = 1; | pd->lookup.done = 1; | ||||
▲ Show 20 Lines • Show All 335 Lines • ▼ Show 20 Lines | cleanup: | ||||
if (sk != NULL) | if (sk != NULL) | ||||
uma_zfree(V_pf_state_key_z, sk); | uma_zfree(V_pf_state_key_z, sk); | ||||
if (nk != NULL) | if (nk != NULL) | ||||
uma_zfree(V_pf_state_key_z, nk); | uma_zfree(V_pf_state_key_z, nk); | ||||
return (PF_DROP); | return (PF_DROP); | ||||
} | } | ||||
static int | static int | ||||
pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, | pf_create_state(struct pf_krule *r, struct pf_krule *nr, struct pf_krule *a, | ||||
struct pf_pdesc *pd, struct pf_ksrc_node *nsn, struct pf_state_key *nk, | struct pf_pdesc *pd, struct pf_ksrc_node *nsn, struct pf_state_key *nk, | ||||
struct pf_state_key *sk, struct mbuf *m, int off, u_int16_t sport, | struct pf_state_key *sk, struct mbuf *m, int off, u_int16_t sport, | ||||
u_int16_t dport, int *rewrite, struct pfi_kif *kif, struct pf_state **sm, | u_int16_t dport, int *rewrite, struct pfi_kif *kif, struct pf_state **sm, | ||||
int tag, u_int16_t bproto_sum, u_int16_t bip_sum, int hdrlen) | int tag, u_int16_t bproto_sum, u_int16_t bip_sum, int hdrlen) | ||||
{ | { | ||||
struct pf_state *s = NULL; | struct pf_state *s = NULL; | ||||
struct pf_ksrc_node *sn = NULL; | struct pf_ksrc_node *sn = NULL; | ||||
struct tcphdr *th = pd->hdr.tcp; | struct tcphdr *th = pd->hdr.tcp; | ||||
▲ Show 20 Lines • Show All 245 Lines • ▼ Show 20 Lines | if (nsn != sn && nsn != NULL) { | ||||
} | } | ||||
PF_HASHROW_UNLOCK(sh); | PF_HASHROW_UNLOCK(sh); | ||||
} | } | ||||
return (PF_DROP); | return (PF_DROP); | ||||
} | } | ||||
static int | static int | ||||
pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, | pf_test_fragment(struct pf_krule **rm, int direction, struct pfi_kif *kif, | ||||
struct mbuf *m, void *h, struct pf_pdesc *pd, struct pf_rule **am, | struct mbuf *m, void *h, struct pf_pdesc *pd, struct pf_krule **am, | ||||
struct pf_ruleset **rsm) | struct pf_kruleset **rsm) | ||||
{ | { | ||||
struct pf_rule *r, *a = NULL; | struct pf_krule *r, *a = NULL; | ||||
struct pf_ruleset *ruleset = NULL; | struct pf_kruleset *ruleset = NULL; | ||||
sa_family_t af = pd->af; | sa_family_t af = pd->af; | ||||
u_short reason; | u_short reason; | ||||
int tag = -1; | int tag = -1; | ||||
int asd = 0; | int asd = 0; | ||||
int match = 0; | int match = 0; | ||||
struct pf_anchor_stackframe anchor_stack[PF_ANCHOR_STACKSIZE]; | struct pf_kanchor_stackframe anchor_stack[PF_ANCHOR_STACKSIZE]; | ||||
PF_RULES_RASSERT(); | PF_RULES_RASSERT(); | ||||
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); | r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); | ||||
while (r != NULL) { | while (r != NULL) { | ||||
r->evaluations++; | r->evaluations++; | ||||
if (pfi_kif_match(r->kif, kif) == r->ifnot) | if (pfi_kif_match(r->kif, kif) == r->ifnot) | ||||
r = r->skip[PF_SKIP_IFP].ptr; | r = r->skip[PF_SKIP_IFP].ptr; | ||||
▲ Show 20 Lines • Show All 1,475 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
#ifdef INET | #ifdef INET | ||||
static void | static void | ||||
pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, | pf_route(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp, | ||||
struct pf_state *s, struct pf_pdesc *pd, struct inpcb *inp) | struct pf_state *s, struct pf_pdesc *pd, struct inpcb *inp) | ||||
{ | { | ||||
struct mbuf *m0, *m1; | struct mbuf *m0, *m1; | ||||
struct sockaddr_in dst; | struct sockaddr_in dst; | ||||
struct ip *ip; | struct ip *ip; | ||||
struct ifnet *ifp = NULL; | struct ifnet *ifp = NULL; | ||||
struct pf_addr naddr; | struct pf_addr naddr; | ||||
struct pf_ksrc_node *sn = NULL; | struct pf_ksrc_node *sn = NULL; | ||||
▲ Show 20 Lines • Show All 146 Lines • ▼ Show 20 Lines | |||||
bad: | bad: | ||||
m_freem(m0); | m_freem(m0); | ||||
goto done; | goto done; | ||||
} | } | ||||
#endif /* INET */ | #endif /* INET */ | ||||
#ifdef INET6 | #ifdef INET6 | ||||
static void | static void | ||||
pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, | pf_route6(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp, | ||||
struct pf_state *s, struct pf_pdesc *pd, struct inpcb *inp) | struct pf_state *s, struct pf_pdesc *pd, struct inpcb *inp) | ||||
{ | { | ||||
struct mbuf *m0; | struct mbuf *m0; | ||||
struct sockaddr_in6 dst; | struct sockaddr_in6 dst; | ||||
struct ip6_hdr *ip6; | struct ip6_hdr *ip6; | ||||
struct ifnet *ifp = NULL; | struct ifnet *ifp = NULL; | ||||
struct pf_addr naddr; | struct pf_addr naddr; | ||||
struct pf_ksrc_node *sn = NULL; | struct pf_ksrc_node *sn = NULL; | ||||
▲ Show 20 Lines • Show All 250 Lines • ▼ Show 20 Lines | |||||
int | int | ||||
pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp) | pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp) | ||||
{ | { | ||||
struct pfi_kif *kif; | struct pfi_kif *kif; | ||||
u_short action, reason = 0, log = 0; | u_short action, reason = 0, log = 0; | ||||
struct mbuf *m = *m0; | struct mbuf *m = *m0; | ||||
struct ip *h = NULL; | struct ip *h = NULL; | ||||
struct m_tag *ipfwtag; | struct m_tag *ipfwtag; | ||||
struct pf_rule *a = NULL, *r = &V_pf_default_rule, *tr, *nr; | struct pf_krule *a = NULL, *r = &V_pf_default_rule, *tr, *nr; | ||||
struct pf_state *s = NULL; | struct pf_state *s = NULL; | ||||
struct pf_ruleset *ruleset = NULL; | struct pf_kruleset *ruleset = NULL; | ||||
struct pf_pdesc pd; | struct pf_pdesc pd; | ||||
int off, dirndx, pqid = 0; | int off, dirndx, pqid = 0; | ||||
PF_RULES_RLOCK_TRACKER; | PF_RULES_RLOCK_TRACKER; | ||||
M_ASSERTPKTHDR(m); | M_ASSERTPKTHDR(m); | ||||
if (!V_pf_status.running) | if (!V_pf_status.running) | ||||
▲ Show 20 Lines • Show All 273 Lines • ▼ Show 20 Lines | if (ipfwtag != NULL) { | ||||
REASON_SET(&reason, PFRES_MEMORY); | REASON_SET(&reason, PFRES_MEMORY); | ||||
log = 1; | log = 1; | ||||
DPFPRINTF(PF_DEBUG_MISC, | DPFPRINTF(PF_DEBUG_MISC, | ||||
("pf: failed to allocate divert tag\n")); | ("pf: failed to allocate divert tag\n")); | ||||
} | } | ||||
} | } | ||||
if (log) { | if (log) { | ||||
struct pf_rule *lr; | struct pf_krule *lr; | ||||
if (s != NULL && s->nat_rule.ptr != NULL && | if (s != NULL && s->nat_rule.ptr != NULL && | ||||
s->nat_rule.ptr->log & PF_LOG_ALL) | s->nat_rule.ptr->log & PF_LOG_ALL) | ||||
lr = s->nat_rule.ptr; | lr = s->nat_rule.ptr; | ||||
else | else | ||||
lr = r; | lr = r; | ||||
PFLOG_PACKET(kif, m, AF_INET, dir, reason, lr, a, ruleset, &pd, | PFLOG_PACKET(kif, m, AF_INET, dir, reason, lr, a, ruleset, &pd, | ||||
(s == NULL)); | (s == NULL)); | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | |||||
int | int | ||||
pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp) | pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp) | ||||
{ | { | ||||
struct pfi_kif *kif; | struct pfi_kif *kif; | ||||
u_short action, reason = 0, log = 0; | u_short action, reason = 0, log = 0; | ||||
struct mbuf *m = *m0, *n = NULL; | struct mbuf *m = *m0, *n = NULL; | ||||
struct m_tag *mtag; | struct m_tag *mtag; | ||||
struct ip6_hdr *h = NULL; | struct ip6_hdr *h = NULL; | ||||
struct pf_rule *a = NULL, *r = &V_pf_default_rule, *tr, *nr; | struct pf_krule *a = NULL, *r = &V_pf_default_rule, *tr, *nr; | ||||
struct pf_state *s = NULL; | struct pf_state *s = NULL; | ||||
struct pf_ruleset *ruleset = NULL; | struct pf_kruleset *ruleset = NULL; | ||||
struct pf_pdesc pd; | struct pf_pdesc pd; | ||||
int off, terminal = 0, dirndx, rh_cnt = 0, pqid = 0; | int off, terminal = 0, dirndx, rh_cnt = 0, pqid = 0; | ||||
PF_RULES_RLOCK_TRACKER; | PF_RULES_RLOCK_TRACKER; | ||||
M_ASSERTPKTHDR(m); | M_ASSERTPKTHDR(m); | ||||
if (!V_pf_status.running) | if (!V_pf_status.running) | ||||
return (PF_PASS); | return (PF_PASS); | ||||
▲ Show 20 Lines • Show All 283 Lines • ▼ Show 20 Lines | if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP || | ||||
IN6_IS_ADDR_LOOPBACK(&pd.dst->v6)) | IN6_IS_ADDR_LOOPBACK(&pd.dst->v6)) | ||||
m->m_flags |= M_SKIP_FIREWALL; | m->m_flags |= M_SKIP_FIREWALL; | ||||
/* XXX: Anybody working on it?! */ | /* XXX: Anybody working on it?! */ | ||||
if (r->divert.port) | if (r->divert.port) | ||||
printf("pf: divert(9) is not supported for IPv6\n"); | printf("pf: divert(9) is not supported for IPv6\n"); | ||||
if (log) { | if (log) { | ||||
struct pf_rule *lr; | struct pf_krule *lr; | ||||
if (s != NULL && s->nat_rule.ptr != NULL && | if (s != NULL && s->nat_rule.ptr != NULL && | ||||
s->nat_rule.ptr->log & PF_LOG_ALL) | s->nat_rule.ptr->log & PF_LOG_ALL) | ||||
lr = s->nat_rule.ptr; | lr = s->nat_rule.ptr; | ||||
else | else | ||||
lr = r; | lr = r; | ||||
PFLOG_PACKET(kif, m, AF_INET6, dir, reason, lr, a, ruleset, | PFLOG_PACKET(kif, m, AF_INET6, dir, reason, lr, a, ruleset, | ||||
&pd, (s == NULL)); | &pd, (s == NULL)); | ||||
▲ Show 20 Lines • Show All 83 Lines • Show Last 20 Lines |