Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/pf/pf.c
Show First 20 Lines • Show All 262 Lines • ▼ Show 20 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_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_krule *); | sa_family_t, struct pf_krule *, int); | ||||
static void pf_detach_state(struct pf_kstate *); | static void pf_detach_state(struct pf_kstate *); | ||||
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_kstate *); | struct pf_state_key *, struct pf_kstate *); | ||||
static void pf_state_key_detach(struct pf_kstate *, int); | static void pf_state_key_detach(struct pf_kstate *, 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 *); | ||||
void pf_rule_to_actions(struct pf_krule *, | void pf_rule_to_actions(struct pf_krule *, | ||||
struct pf_rule_actions *); | struct pf_rule_actions *); | ||||
Show All 9 Lines | static int pf_test_rule(struct pf_krule **, struct pf_kstate **, | ||||
struct pf_pdesc *, struct pf_krule **, | struct pf_pdesc *, struct pf_krule **, | ||||
struct pf_kruleset **, struct inpcb *); | struct pf_kruleset **, struct inpcb *); | ||||
static int pf_create_state(struct pf_krule *, struct pf_krule *, | static int pf_create_state(struct pf_krule *, struct pf_krule *, | ||||
struct pf_krule *, 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_kkif *, | u_int16_t, u_int16_t, int *, struct pfi_kkif *, | ||||
struct pf_kstate **, int, u_int16_t, u_int16_t, | struct pf_kstate **, int, u_int16_t, u_int16_t, | ||||
int); | int, struct pf_krule_slist *); | ||||
static int pf_test_fragment(struct pf_krule **, int, | static int pf_test_fragment(struct pf_krule **, int, | ||||
struct pfi_kkif *, struct mbuf *, void *, | struct pfi_kkif *, struct mbuf *, void *, | ||||
struct pf_pdesc *, struct pf_krule **, | struct pf_pdesc *, struct pf_krule **, | ||||
struct pf_kruleset **); | struct pf_kruleset **); | ||||
static int pf_tcp_track_full(struct pf_kstate **, | static int pf_tcp_track_full(struct pf_kstate **, | ||||
struct pfi_kkif *, struct mbuf *, int, | struct pfi_kkif *, struct mbuf *, int, | ||||
struct pf_pdesc *, u_short *, int *); | struct pf_pdesc *, u_short *, int *); | ||||
static int pf_tcp_track_sloppy(struct pf_kstate **, | static int pf_tcp_track_sloppy(struct pf_kstate **, | ||||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | if (PACKET_LOOPED(pd)) \ | ||||
return (PF_PASS); \ | return (PF_PASS); \ | ||||
} while (0) | } while (0) | ||||
#define BOUND_IFACE(r, k) \ | #define BOUND_IFACE(r, k) \ | ||||
((r)->rule_flag & PFRULE_IFBOUND) ? (k) : V_pfi_all | ((r)->rule_flag & PFRULE_IFBOUND) ? (k) : V_pfi_all | ||||
#define STATE_INC_COUNTERS(s) \ | #define STATE_INC_COUNTERS(s) \ | ||||
do { \ | do { \ | ||||
struct pf_krule_item *mrm; \ | |||||
counter_u64_add(s->rule.ptr->states_cur, 1); \ | counter_u64_add(s->rule.ptr->states_cur, 1); \ | ||||
counter_u64_add(s->rule.ptr->states_tot, 1); \ | counter_u64_add(s->rule.ptr->states_tot, 1); \ | ||||
if (s->anchor.ptr != NULL) { \ | if (s->anchor.ptr != NULL) { \ | ||||
counter_u64_add(s->anchor.ptr->states_cur, 1); \ | counter_u64_add(s->anchor.ptr->states_cur, 1); \ | ||||
counter_u64_add(s->anchor.ptr->states_tot, 1); \ | counter_u64_add(s->anchor.ptr->states_tot, 1); \ | ||||
} \ | } \ | ||||
if (s->nat_rule.ptr != NULL) { \ | if (s->nat_rule.ptr != NULL) { \ | ||||
counter_u64_add(s->nat_rule.ptr->states_cur, 1);\ | counter_u64_add(s->nat_rule.ptr->states_cur, 1);\ | ||||
counter_u64_add(s->nat_rule.ptr->states_tot, 1);\ | counter_u64_add(s->nat_rule.ptr->states_tot, 1);\ | ||||
} \ | } \ | ||||
SLIST_FOREACH(mrm, &s->match_rules, entry) { \ | |||||
counter_u64_add(mrm->r->states_cur, 1); \ | |||||
counter_u64_add(mrm->r->states_tot, 1); \ | |||||
} \ | |||||
} while (0) | } while (0) | ||||
#define STATE_DEC_COUNTERS(s) \ | #define STATE_DEC_COUNTERS(s) \ | ||||
do { \ | do { \ | ||||
struct pf_krule_item *mrm; \ | |||||
if (s->nat_rule.ptr != NULL) \ | if (s->nat_rule.ptr != NULL) \ | ||||
counter_u64_add(s->nat_rule.ptr->states_cur, -1);\ | counter_u64_add(s->nat_rule.ptr->states_cur, -1);\ | ||||
if (s->anchor.ptr != NULL) \ | if (s->anchor.ptr != NULL) \ | ||||
counter_u64_add(s->anchor.ptr->states_cur, -1); \ | counter_u64_add(s->anchor.ptr->states_cur, -1); \ | ||||
counter_u64_add(s->rule.ptr->states_cur, -1); \ | counter_u64_add(s->rule.ptr->states_cur, -1); \ | ||||
SLIST_FOREACH(mrm, &s->match_rules, entry) \ | |||||
counter_u64_add(mrm->r->states_cur, -1); \ | |||||
} while (0) | } while (0) | ||||
MALLOC_DEFINE(M_PFHASH, "pf_hash", "pf(4) hash header structures"); | MALLOC_DEFINE(M_PFHASH, "pf_hash", "pf(4) hash header structures"); | ||||
MALLOC_DEFINE(M_PF_RULE_ITEM, "pf_krule_item", "pf(4) rule items"); | |||||
VNET_DEFINE(struct pf_keyhash *, pf_keyhash); | VNET_DEFINE(struct pf_keyhash *, pf_keyhash); | ||||
VNET_DEFINE(struct pf_idhash *, pf_idhash); | VNET_DEFINE(struct pf_idhash *, pf_idhash); | ||||
VNET_DEFINE(struct pf_srchash *, pf_srchash); | VNET_DEFINE(struct pf_srchash *, pf_srchash); | ||||
SYSCTL_NODE(_net, OID_AUTO, pf, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, | SYSCTL_NODE(_net, OID_AUTO, pf, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, | ||||
"pf(4)"); | "pf(4)"); | ||||
u_long pf_hashmask; | u_long pf_hashmask; | ||||
▲ Show 20 Lines • Show All 1,607 Lines • ▼ Show 20 Lines | pf_unlink_state(struct pf_kstate *s) | ||||
if (s->src.state == PF_TCPS_PROXY_DST) { | if (s->src.state == PF_TCPS_PROXY_DST) { | ||||
/* XXX wire key the right one? */ | /* XXX wire key the right one? */ | ||||
pf_send_tcp(s->rule.ptr, s->key[PF_SK_WIRE]->af, | pf_send_tcp(s->rule.ptr, s->key[PF_SK_WIRE]->af, | ||||
&s->key[PF_SK_WIRE]->addr[1], | &s->key[PF_SK_WIRE]->addr[1], | ||||
&s->key[PF_SK_WIRE]->addr[0], | &s->key[PF_SK_WIRE]->addr[0], | ||||
s->key[PF_SK_WIRE]->port[1], | s->key[PF_SK_WIRE]->port[1], | ||||
s->key[PF_SK_WIRE]->port[0], | s->key[PF_SK_WIRE]->port[0], | ||||
s->src.seqhi, s->src.seqlo + 1, | s->src.seqhi, s->src.seqlo + 1, | ||||
TH_RST|TH_ACK, 0, 0, 0, 1, s->tag); | TH_RST|TH_ACK, 0, 0, 0, 1, s->tag, s->rtableid); | ||||
} | } | ||||
LIST_REMOVE(s, entry); | LIST_REMOVE(s, entry); | ||||
pf_src_tree_remove_state(s); | pf_src_tree_remove_state(s); | ||||
if (V_pfsync_delete_state_ptr != NULL) | if (V_pfsync_delete_state_ptr != NULL) | ||||
V_pfsync_delete_state_ptr(s); | V_pfsync_delete_state_ptr(s); | ||||
Show All 18 Lines | |||||
{ | { | ||||
return (uma_zalloc(V_pf_state_z, flags | M_ZERO)); | return (uma_zalloc(V_pf_state_z, flags | M_ZERO)); | ||||
} | } | ||||
void | void | ||||
pf_free_state(struct pf_kstate *cur) | pf_free_state(struct pf_kstate *cur) | ||||
{ | { | ||||
struct pf_krule_item *ri; | |||||
KASSERT(cur->refs == 0, ("%s: %p has refs", __func__, cur)); | KASSERT(cur->refs == 0, ("%s: %p has refs", __func__, cur)); | ||||
KASSERT(cur->timeout == PFTM_UNLINKED, ("%s: timeout %u", __func__, | KASSERT(cur->timeout == PFTM_UNLINKED, ("%s: timeout %u", __func__, | ||||
cur->timeout)); | cur->timeout)); | ||||
while ((ri = SLIST_FIRST(&cur->match_rules))) { | |||||
SLIST_REMOVE_HEAD(&cur->match_rules, entry); | |||||
free(ri, M_PF_RULE_ITEM); | |||||
} | |||||
pf_normalize_tcp_cleanup(cur); | pf_normalize_tcp_cleanup(cur); | ||||
uma_zfree(V_pf_state_z, cur); | uma_zfree(V_pf_state_z, cur); | ||||
pf_counter_u64_add(&V_pf_status.fcounters[FCNT_STATE_REMOVALS], 1); | pf_counter_u64_add(&V_pf_status.fcounters[FCNT_STATE_REMOVALS], 1); | ||||
} | } | ||||
/* | /* | ||||
* Called only from pf_purge_thread(), thus serialized. | * Called only from pf_purge_thread(), thus serialized. | ||||
*/ | */ | ||||
static u_int | static u_int | ||||
pf_purge_expired_states(u_int i, int maxcheck) | pf_purge_expired_states(u_int i, int maxcheck) | ||||
{ | { | ||||
struct pf_idhash *ih; | struct pf_idhash *ih; | ||||
struct pf_kstate *s; | struct pf_kstate *s; | ||||
struct pf_krule_item *mrm; | |||||
V_pf_status.states = uma_zone_get_cur(V_pf_state_z); | V_pf_status.states = uma_zone_get_cur(V_pf_state_z); | ||||
/* | /* | ||||
* Go through hash and unlink states that expire now. | * Go through hash and unlink states that expire now. | ||||
*/ | */ | ||||
while (maxcheck > 0) { | while (maxcheck > 0) { | ||||
ih = &V_pf_idhash[i]; | ih = &V_pf_idhash[i]; | ||||
Show All 9 Lines | relock: | ||||
goto relock; | goto relock; | ||||
} | } | ||||
s->rule.ptr->rule_ref |= PFRULE_REFS; | s->rule.ptr->rule_ref |= PFRULE_REFS; | ||||
if (s->nat_rule.ptr != NULL) | if (s->nat_rule.ptr != NULL) | ||||
s->nat_rule.ptr->rule_ref |= PFRULE_REFS; | s->nat_rule.ptr->rule_ref |= PFRULE_REFS; | ||||
if (s->anchor.ptr != NULL) | if (s->anchor.ptr != NULL) | ||||
s->anchor.ptr->rule_ref |= PFRULE_REFS; | s->anchor.ptr->rule_ref |= PFRULE_REFS; | ||||
s->kif->pfik_flags |= PFI_IFLAG_REFS; | s->kif->pfik_flags |= PFI_IFLAG_REFS; | ||||
SLIST_FOREACH(mrm, &s->match_rules, entry) | |||||
mrm->r->rule_ref |= PFRULE_REFS; | |||||
if (s->rt_kif) | if (s->rt_kif) | ||||
s->rt_kif->pfik_flags |= PFI_IFLAG_REFS; | s->rt_kif->pfik_flags |= PFI_IFLAG_REFS; | ||||
} | } | ||||
PF_HASHROW_UNLOCK(ih); | PF_HASHROW_UNLOCK(ih); | ||||
} | } | ||||
/* Return when we hit end of hash. */ | /* Return when we hit end of hash. */ | ||||
if (++i > pf_hashmask) { | if (++i > pf_hashmask) { | ||||
▲ Show 20 Lines • Show All 647 Lines • ▼ Show 20 Lines | #define TCPOLEN_SACKLEN (TCPOLEN_SACK + 2) | ||||
return (copyback); | return (copyback); | ||||
} | } | ||||
struct mbuf * | struct mbuf * | ||||
pf_build_tcp(const struct pf_krule *r, sa_family_t af, | pf_build_tcp(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) | u_int16_t rtag, int rtableid) | ||||
{ | { | ||||
struct mbuf *m; | struct mbuf *m; | ||||
int len, tlen; | int len, tlen; | ||||
#ifdef INET | #ifdef INET | ||||
struct ip *h = NULL; | struct ip *h = NULL; | ||||
#endif /* INET */ | #endif /* INET */ | ||||
#ifdef INET6 | #ifdef INET6 | ||||
struct ip6_hdr *h6 = NULL; | struct ip6_hdr *h6 = NULL; | ||||
Show All 35 Lines | #endif | ||||
if ((pf_mtag = pf_get_mtag(m)) == NULL) { | if ((pf_mtag = pf_get_mtag(m)) == NULL) { | ||||
m_freem(m); | m_freem(m); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
if (tag) | if (tag) | ||||
m->m_flags |= M_SKIP_FIREWALL; | m->m_flags |= M_SKIP_FIREWALL; | ||||
pf_mtag->tag = rtag; | pf_mtag->tag = rtag; | ||||
if (r != NULL && r->rtableid >= 0) | if (rtableid >= 0) | ||||
M_SETFIB(m, r->rtableid); | M_SETFIB(m, rtableid); | ||||
#ifdef ALTQ | #ifdef ALTQ | ||||
if (r != NULL && r->qid) { | if (r != NULL && r->qid) { | ||||
pf_mtag->qid = r->qid; | pf_mtag->qid = r->qid; | ||||
/* add hints for ecn */ | /* add hints for ecn */ | ||||
pf_mtag->hdr = mtod(m, struct ip *); | pf_mtag->hdr = mtod(m, struct ip *); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | #endif /* INET6 */ | ||||
return (m); | return (m); | ||||
} | } | ||||
void | void | ||||
pf_send_tcp(const struct pf_krule *r, sa_family_t af, | pf_send_tcp(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) | u_int16_t rtag, int rtableid) | ||||
{ | { | ||||
struct pf_send_entry *pfse; | struct pf_send_entry *pfse; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
m = pf_build_tcp(r, af, saddr, daddr, sport, dport, seq, ack, flags, | m = pf_build_tcp(r, af, saddr, daddr, sport, dport, seq, ack, flags, | ||||
win, mss, ttl, tag, rtag); | win, mss, ttl, tag, rtag, rtableid); | ||||
if (m == NULL) | if (m == NULL) | ||||
return; | return; | ||||
/* 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) { | ||||
m_freem(m); | m_freem(m); | ||||
return; | return; | ||||
Show All 15 Lines | #endif /* INET6 */ | ||||
pfse->pfse_m = m; | pfse->pfse_m = m; | ||||
pf_send(pfse); | pf_send(pfse); | ||||
} | } | ||||
static void | static void | ||||
pf_return(struct pf_krule *r, struct pf_krule *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_kkif *kif, u_int16_t bproto_sum, u_int16_t bip_sum, int hdrlen, | struct pfi_kkif *kif, u_int16_t bproto_sum, u_int16_t bip_sum, int hdrlen, | ||||
u_short *reason) | u_short *reason, int rtableid) | ||||
{ | { | ||||
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; | ||||
/* undo NAT changes, if they have taken place */ | /* undo NAT changes, if they have taken place */ | ||||
if (nr != NULL) { | if (nr != NULL) { | ||||
PF_ACPY(saddr, &sk->addr[pd->sidx], af); | PF_ACPY(saddr, &sk->addr[pd->sidx], af); | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | #endif | ||||
else { | else { | ||||
if (th->th_flags & TH_SYN) | if (th->th_flags & TH_SYN) | ||||
ack++; | ack++; | ||||
if (th->th_flags & TH_FIN) | if (th->th_flags & TH_FIN) | ||||
ack++; | ack++; | ||||
pf_send_tcp(r, af, pd->dst, | pf_send_tcp(r, af, pd->dst, | ||||
pd->src, th->th_dport, th->th_sport, | pd->src, th->th_dport, th->th_sport, | ||||
ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0, | ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0, | ||||
r->return_ttl, 1, 0); | r->return_ttl, 1, 0, rtableid); | ||||
} | } | ||||
} else if (pd->proto != IPPROTO_ICMP && af == AF_INET && | } else if (pd->proto != IPPROTO_ICMP && af == AF_INET && | ||||
r->return_icmp) | r->return_icmp) | ||||
pf_send_icmp(m, r->return_icmp >> 8, | pf_send_icmp(m, r->return_icmp >> 8, | ||||
r->return_icmp & 255, af, r); | r->return_icmp & 255, af, r, rtableid); | ||||
else if (pd->proto != IPPROTO_ICMPV6 && af == AF_INET6 && | else if (pd->proto != IPPROTO_ICMPV6 && af == AF_INET6 && | ||||
r->return_icmp6) | r->return_icmp6) | ||||
pf_send_icmp(m, r->return_icmp6 >> 8, | pf_send_icmp(m, r->return_icmp6 >> 8, | ||||
r->return_icmp6 & 255, af, r); | r->return_icmp6 & 255, af, r, rtableid); | ||||
} | } | ||||
static int | static int | ||||
pf_match_ieee8021q_pcp(u_int8_t prio, struct mbuf *m) | pf_match_ieee8021q_pcp(u_int8_t prio, struct mbuf *m) | ||||
{ | { | ||||
struct m_tag *mtag; | struct m_tag *mtag; | ||||
u_int8_t mpcp; | u_int8_t mpcp; | ||||
Show All 22 Lines | switch (type) { | ||||
case ICMP_UNREACH: | case ICMP_UNREACH: | ||||
default: | default: | ||||
return (BANDLIM_ICMP_UNREACH); | return (BANDLIM_ICMP_UNREACH); | ||||
} | } | ||||
} | } | ||||
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_krule *r) | struct pf_krule *r, int rtableid) | ||||
{ | { | ||||
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; | ||||
/* ICMP packet rate limitation. */ | /* ICMP packet rate limitation. */ | ||||
#ifdef INET6 | #ifdef INET6 | ||||
if (af == AF_INET6) { | if (af == AF_INET6) { | ||||
Show All 20 Lines | #endif | ||||
if ((pf_mtag = pf_get_mtag(m0)) == NULL) { | if ((pf_mtag = pf_get_mtag(m0)) == NULL) { | ||||
free(pfse, M_PFTEMP); | free(pfse, M_PFTEMP); | ||||
return; | return; | ||||
} | } | ||||
/* XXX: revisit */ | /* XXX: revisit */ | ||||
m0->m_flags |= M_SKIP_FIREWALL; | m0->m_flags |= M_SKIP_FIREWALL; | ||||
if (r->rtableid >= 0) | if (rtableid >= 0) | ||||
M_SETFIB(m0, r->rtableid); | M_SETFIB(m0, rtableid); | ||||
#ifdef ALTQ | #ifdef ALTQ | ||||
if (r->qid) { | if (r->qid) { | ||||
pf_mtag->qid = r->qid; | pf_mtag->qid = r->qid; | ||||
/* add hints for ecn */ | /* add hints for ecn */ | ||||
pf_mtag->hdr = mtod(m0, struct ip *); | pf_mtag->hdr = mtod(m0, struct ip *); | ||||
} | } | ||||
#endif /* ALTQ */ | #endif /* ALTQ */ | ||||
▲ Show 20 Lines • Show All 445 Lines • ▼ Show 20 Lines | |||||
void | void | ||||
pf_rule_to_actions(struct pf_krule *r, struct pf_rule_actions *a) | pf_rule_to_actions(struct pf_krule *r, struct pf_rule_actions *a) | ||||
{ | { | ||||
if (r->qid) | if (r->qid) | ||||
a->qid = r->qid; | a->qid = r->qid; | ||||
if (r->pqid) | if (r->pqid) | ||||
a->pqid = r->pqid; | a->pqid = r->pqid; | ||||
if (r->rtableid >= 0) | |||||
a->rtableid = r->rtableid; | |||||
a->log |= r->log; | |||||
if (r->scrub_flags & PFSTATE_SETTOS) | |||||
a->set_tos = r->set_tos; | |||||
if (r->min_ttl) | |||||
a->min_ttl = r->min_ttl; | |||||
if (r->max_mss) | |||||
a->max_mss = r->max_mss; | |||||
a->flags |= (r->scrub_flags & (PFSTATE_NODF|PFSTATE_RANDOMID| | |||||
PFSTATE_SETTOS|PFSTATE_SCRUB_TCP|PFSTATE_SETPRIO)); | |||||
if (r->dnpipe) | if (r->dnpipe) | ||||
a->dnpipe = r->dnpipe; | a->dnpipe = r->dnpipe; | ||||
if (r->dnrpipe) | if (r->dnrpipe) | ||||
a->dnrpipe = r->dnrpipe; | a->dnrpipe = r->dnrpipe; | ||||
if (r->dnpipe || r->dnrpipe) { | if (r->dnpipe || r->dnrpipe) { | ||||
if (r->free_flags & PFRULE_DN_IS_PIPE) | if (r->free_flags & PFRULE_DN_IS_PIPE) | ||||
a->flags |= PFRULE_DN_IS_PIPE; | a->dnflags |= PFRULE_DN_IS_PIPE; | ||||
else | else | ||||
a->flags &= ~PFRULE_DN_IS_PIPE; | a->dnflags &= ~PFRULE_DN_IS_PIPE; | ||||
} | } | ||||
} | } | ||||
int | int | ||||
pf_socket_lookup(int direction, struct pf_pdesc *pd, struct mbuf *m) | pf_socket_lookup(int direction, struct pf_pdesc *pd, struct mbuf *m) | ||||
{ | { | ||||
struct pf_addr *saddr, *daddr; | struct pf_addr *saddr, *daddr; | ||||
u_int16_t sport, dport; | u_int16_t sport, dport; | ||||
▲ Show 20 Lines • Show All 548 Lines • ▼ Show 20 Lines | pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm, int direction, | ||||
struct pf_krule **am, struct pf_kruleset **rsm, struct inpcb *inp) | struct pf_krule **am, struct pf_kruleset **rsm, struct inpcb *inp) | ||||
{ | { | ||||
struct pf_krule *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_krule *r, *a = NULL; | struct pf_krule *r, *a = NULL; | ||||
struct pf_kruleset *ruleset = NULL; | struct pf_kruleset *ruleset = NULL; | ||||
struct pf_krule_slist match_rules; | |||||
struct pf_krule_item *ri; | |||||
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; | ||||
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_kanchor_stackframe anchor_stack[PF_ANCHOR_STACKSIZE]; | struct pf_kanchor_stackframe anchor_stack[PF_ANCHOR_STACKSIZE]; | ||||
▲ Show 20 Lines • Show All 185 Lines • ▼ Show 20 Lines | #endif /* INET */ | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
if (nr->natpass) | if (nr->natpass) | ||||
r = NULL; | r = NULL; | ||||
pd->nat_rule = nr; | pd->nat_rule = nr; | ||||
} | } | ||||
SLIST_INIT(&match_rules); | |||||
while (r != NULL) { | while (r != NULL) { | ||||
pf_counter_u64_add(&r->evaluations, 1); | pf_counter_u64_add(&r->evaluations, 1); | ||||
if (pfi_kkif_match(r->kif, kif) == r->ifnot) | if (pfi_kkif_match(r->kif, kif) == r->ifnot) | ||||
r = r->skip[PF_SKIP_IFP].ptr; | r = r->skip[PF_SKIP_IFP].ptr; | ||||
else if (r->direction && r->direction != direction) | else if (r->direction && r->direction != direction) | ||||
r = r->skip[PF_SKIP_DIR].ptr; | r = r->skip[PF_SKIP_DIR].ptr; | ||||
else if (r->af && r->af != af) | else if (r->af && r->af != af) | ||||
r = r->skip[PF_SKIP_AF].ptr; | r = r->skip[PF_SKIP_AF].ptr; | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | while (r != NULL) { | ||||
else if (r->os_fingerprint != PF_OSFP_ANY && | else if (r->os_fingerprint != PF_OSFP_ANY && | ||||
(pd->proto != IPPROTO_TCP || !pf_osfp_match( | (pd->proto != IPPROTO_TCP || !pf_osfp_match( | ||||
pf_osfp_fingerprint(pd, m, off, th), | pf_osfp_fingerprint(pd, m, off, th), | ||||
r->os_fingerprint))) | r->os_fingerprint))) | ||||
r = TAILQ_NEXT(r, entries); | r = TAILQ_NEXT(r, entries); | ||||
else { | else { | ||||
if (r->tag) | if (r->tag) | ||||
tag = r->tag; | tag = r->tag; | ||||
if (r->rtableid >= 0) | |||||
rtableid = r->rtableid; | |||||
if (r->anchor == NULL) { | if (r->anchor == NULL) { | ||||
if (r->action == PF_MATCH) { | if (r->action == PF_MATCH) { | ||||
ri = malloc(sizeof(struct pf_krule_item), M_PF_RULE_ITEM, M_NOWAIT | M_ZERO); | |||||
if (ri == NULL) { | |||||
REASON_SET(&reason, PFRES_MEMORY); | |||||
goto cleanup; | |||||
} | |||||
ri->r = r; | |||||
SLIST_INSERT_HEAD(&match_rules, ri, entry); | |||||
pf_counter_u64_critical_enter(); | pf_counter_u64_critical_enter(); | ||||
pf_counter_u64_add_protected(&r->packets[direction == PF_OUT], 1); | pf_counter_u64_add_protected(&r->packets[direction == PF_OUT], 1); | ||||
pf_counter_u64_add_protected(&r->bytes[direction == PF_OUT], pd->tot_len); | pf_counter_u64_add_protected(&r->bytes[direction == PF_OUT], pd->tot_len); | ||||
pf_counter_u64_critical_exit(); | pf_counter_u64_critical_exit(); | ||||
pf_rule_to_actions(r, &pd->act); | pf_rule_to_actions(r, &pd->act); | ||||
if (r->log) | if (r->log) | ||||
PFLOG_PACKET(kif, m, af, | PFLOG_PACKET(kif, m, af, | ||||
direction, PFRES_MATCH, r, | direction, PFRES_MATCH, r, | ||||
Show All 32 Lines | PFLOG_PACKET(kif, m, af, direction, reason, r, a, | ||||
ruleset, pd, 1); | ruleset, pd, 1); | ||||
} | } | ||||
if ((r->action == PF_DROP) && | if ((r->action == PF_DROP) && | ||||
((r->rule_flag & PFRULE_RETURNRST) || | ((r->rule_flag & PFRULE_RETURNRST) || | ||||
(r->rule_flag & PFRULE_RETURNICMP) || | (r->rule_flag & PFRULE_RETURNICMP) || | ||||
(r->rule_flag & PFRULE_RETURN))) { | (r->rule_flag & PFRULE_RETURN))) { | ||||
pf_return(r, nr, pd, sk, off, m, th, kif, bproto_sum, | pf_return(r, nr, pd, sk, off, m, th, kif, bproto_sum, | ||||
bip_sum, hdrlen, &reason); | bip_sum, hdrlen, &reason, r->rtableid); | ||||
} | } | ||||
if (r->action == PF_DROP) | if (r->action == PF_DROP) | ||||
goto cleanup; | goto cleanup; | ||||
if (tag > 0 && pf_tag_packet(m, pd, tag)) { | if (tag > 0 && pf_tag_packet(m, pd, tag)) { | ||||
REASON_SET(&reason, PFRES_MEMORY); | REASON_SET(&reason, PFRES_MEMORY); | ||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
if (rtableid >= 0) | if (pd->act.rtableid >= 0) | ||||
M_SETFIB(m, rtableid); | M_SETFIB(m, pd->act.rtableid); | ||||
if (!state_icmp && (r->keep_state || nr != NULL || | if (!state_icmp && (r->keep_state || nr != NULL || | ||||
(pd->flags & PFDESC_TCP_NORM))) { | (pd->flags & PFDESC_TCP_NORM))) { | ||||
int action; | int action; | ||||
action = pf_create_state(r, nr, a, pd, nsn, nk, sk, m, off, | action = pf_create_state(r, nr, a, pd, nsn, nk, sk, m, off, | ||||
sport, dport, &rewrite, kif, sm, tag, bproto_sum, bip_sum, | sport, dport, &rewrite, kif, sm, tag, bproto_sum, bip_sum, | ||||
hdrlen); | hdrlen, &match_rules); | ||||
if (action != PF_PASS) { | if (action != PF_PASS) { | ||||
if (action == PF_DROP && | if (action == PF_DROP && | ||||
(r->rule_flag & PFRULE_RETURN)) | (r->rule_flag & PFRULE_RETURN)) | ||||
pf_return(r, nr, pd, sk, off, m, th, kif, | pf_return(r, nr, pd, sk, off, m, th, kif, | ||||
bproto_sum, bip_sum, hdrlen, &reason); | bproto_sum, bip_sum, hdrlen, &reason, | ||||
pd->act.rtableid); | |||||
return (action); | return (action); | ||||
} | } | ||||
} else { | } else { | ||||
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); | ||||
} | } | ||||
Show All 11 Lines | if (*sm != NULL && !((*sm)->state_flags & PFSTATE_NOSYNC) && | ||||
* firewall has to know about it to allow | * firewall has to know about it to allow | ||||
* replies through it. | * replies through it. | ||||
*/ | */ | ||||
return (PF_DEFER); | return (PF_DEFER); | ||||
return (PF_PASS); | return (PF_PASS); | ||||
cleanup: | cleanup: | ||||
while ((ri = SLIST_FIRST(&match_rules))) { | |||||
SLIST_REMOVE_HEAD(&match_rules, entry); | |||||
free(ri, M_PF_RULE_ITEM); | |||||
} | |||||
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_krule *r, struct pf_krule *nr, struct pf_krule *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_kkif *kif, struct pf_kstate **sm, | u_int16_t dport, int *rewrite, struct pfi_kkif *kif, struct pf_kstate **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_krule_slist *match_rules) | |||||
{ | { | ||||
struct pf_kstate *s = NULL; | struct pf_kstate *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; | ||||
u_int16_t mss = V_tcp_mssdflt; | u_int16_t mss = V_tcp_mssdflt; | ||||
u_short reason; | u_short reason; | ||||
/* check maximums */ | /* check maximums */ | ||||
Show All 19 Lines | pf_create_state(struct pf_krule *r, struct pf_krule *nr, struct pf_krule *a, | ||||
s = pf_alloc_state(M_NOWAIT); | s = pf_alloc_state(M_NOWAIT); | ||||
if (s == NULL) { | if (s == NULL) { | ||||
REASON_SET(&reason, PFRES_MEMORY); | REASON_SET(&reason, PFRES_MEMORY); | ||||
goto csfailed; | goto csfailed; | ||||
} | } | ||||
s->rule.ptr = r; | s->rule.ptr = r; | ||||
s->nat_rule.ptr = nr; | s->nat_rule.ptr = nr; | ||||
s->anchor.ptr = a; | s->anchor.ptr = a; | ||||
bcopy(match_rules, &s->match_rules, sizeof(s->match_rules)); | |||||
STATE_INC_COUNTERS(s); | STATE_INC_COUNTERS(s); | ||||
if (r->allow_opts) | if (r->allow_opts) | ||||
s->state_flags |= PFSTATE_ALLOWOPTS; | s->state_flags |= PFSTATE_ALLOWOPTS; | ||||
if (r->rule_flag & PFRULE_STATESLOPPY) | if (r->rule_flag & PFRULE_STATESLOPPY) | ||||
s->state_flags |= PFSTATE_SLOPPY; | s->state_flags |= PFSTATE_SLOPPY; | ||||
s->log = r->log & PF_LOG_ALL; | if (pd->flags & PFDESC_TCP_NORM) /* Set by old-style scrub rules */ | ||||
s->state_flags |= PFSTATE_SCRUB_TCP; | |||||
s->log = pd->act.log & PF_LOG_ALL; | |||||
s->qid = pd->act.qid; | |||||
s->pqid = pd->act.pqid; | |||||
s->rtableid = pd->act.rtableid; | |||||
s->min_ttl = pd->act.min_ttl; | |||||
s->set_tos = pd->act.set_tos; | |||||
s->max_mss = pd->act.max_mss; | |||||
s->sync_state = PFSYNC_S_NONE; | s->sync_state = PFSYNC_S_NONE; | ||||
s->qid = pd->act.qid; | s->qid = pd->act.qid; | ||||
s->pqid = pd->act.pqid; | s->pqid = pd->act.pqid; | ||||
s->dnpipe = pd->act.dnpipe; | s->dnpipe = pd->act.dnpipe; | ||||
s->dnrpipe = pd->act.dnrpipe; | s->dnrpipe = pd->act.dnrpipe; | ||||
s->state_flags |= pd->act.flags; | s->state_flags |= pd->act.flags; | ||||
if (nr != NULL) | if (nr != NULL) | ||||
s->log |= nr->log & PF_LOG_ALL; | s->log |= nr->log & PF_LOG_ALL; | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | #endif | ||||
if (sn != NULL) | if (sn != NULL) | ||||
s->src_node = sn; | s->src_node = sn; | ||||
if (nsn != NULL) { | if (nsn != NULL) { | ||||
/* XXX We only modify one side for now. */ | /* XXX We only modify one side for now. */ | ||||
PF_ACPY(&nsn->raddr, &nk->addr[1], pd->af); | PF_ACPY(&nsn->raddr, &nk->addr[1], pd->af); | ||||
s->nat_src_node = nsn; | s->nat_src_node = nsn; | ||||
} | } | ||||
if (pd->proto == IPPROTO_TCP) { | if (pd->proto == IPPROTO_TCP) { | ||||
if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m, | if (s->state_flags & PFSTATE_SCRUB_TCP && | ||||
off, pd, th, &s->src, &s->dst)) { | pf_normalize_tcp_init(m, off, pd, th, &s->src, &s->dst)) { | ||||
REASON_SET(&reason, PFRES_MEMORY); | REASON_SET(&reason, PFRES_MEMORY); | ||||
pf_src_tree_remove_state(s); | pf_src_tree_remove_state(s); | ||||
s->timeout = PFTM_UNLINKED; | s->timeout = PFTM_UNLINKED; | ||||
STATE_DEC_COUNTERS(s); | STATE_DEC_COUNTERS(s); | ||||
pf_free_state(s); | pf_free_state(s); | ||||
return (PF_DROP); | return (PF_DROP); | ||||
} | } | ||||
if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub && | if (s->state_flags & PFSTATE_SCRUB_TCP && s->src.scrub && | ||||
pf_normalize_tcp_stateful(m, off, pd, &reason, th, s, | pf_normalize_tcp_stateful(m, off, pd, &reason, th, s, | ||||
&s->src, &s->dst, rewrite)) { | &s->src, &s->dst, rewrite)) { | ||||
/* This really shouldn't happen!!! */ | /* This really shouldn't happen!!! */ | ||||
DPFPRINTF(PF_DEBUG_URGENT, | DPFPRINTF(PF_DEBUG_URGENT, | ||||
("pf_normalize_tcp_stateful failed on first " | ("pf_normalize_tcp_stateful failed on first " | ||||
"pkt\n")); | "pkt\n")); | ||||
pf_src_tree_remove_state(s); | pf_src_tree_remove_state(s); | ||||
s->timeout = PFTM_UNLINKED; | s->timeout = PFTM_UNLINKED; | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | if (pd->proto == IPPROTO_TCP && (th->th_flags & (TH_SYN|TH_ACK)) == | ||||
/* Find mss option */ | /* Find mss option */ | ||||
int rtid = M_GETFIB(m); | int rtid = M_GETFIB(m); | ||||
mss = pf_get_mss(m, off, th->th_off, pd->af); | mss = pf_get_mss(m, off, th->th_off, pd->af); | ||||
mss = pf_calc_mss(pd->src, pd->af, rtid, mss); | mss = pf_calc_mss(pd->src, pd->af, rtid, mss); | ||||
mss = pf_calc_mss(pd->dst, pd->af, rtid, mss); | mss = pf_calc_mss(pd->dst, pd->af, rtid, mss); | ||||
s->src.mss = mss; | s->src.mss = mss; | ||||
pf_send_tcp(r, pd->af, pd->dst, pd->src, th->th_dport, | pf_send_tcp(r, pd->af, pd->dst, pd->src, th->th_dport, | ||||
th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1, | th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1, | ||||
TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0); | TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, pd->act.rtableid); | ||||
REASON_SET(&reason, PFRES_SYNPROXY); | REASON_SET(&reason, PFRES_SYNPROXY); | ||||
return (PF_SYNPROXY_DROP); | return (PF_SYNPROXY_DROP); | ||||
} | } | ||||
return (PF_PASS); | return (PF_PASS); | ||||
csfailed: | csfailed: | ||||
if (sk != NULL) | if (sk != NULL) | ||||
Show All 34 Lines | |||||
static int | static int | ||||
pf_test_fragment(struct pf_krule **rm, int direction, struct pfi_kkif *kif, | pf_test_fragment(struct pf_krule **rm, int direction, struct pfi_kkif *kif, | ||||
struct mbuf *m, void *h, struct pf_pdesc *pd, struct pf_krule **am, | struct mbuf *m, void *h, struct pf_pdesc *pd, struct pf_krule **am, | ||||
struct pf_kruleset **rsm) | struct pf_kruleset **rsm) | ||||
{ | { | ||||
struct pf_krule *r, *a = NULL; | struct pf_krule *r, *a = NULL; | ||||
struct pf_kruleset *ruleset = NULL; | struct pf_kruleset *ruleset = NULL; | ||||
struct pf_krule_slist match_rules; | |||||
struct pf_krule_item *ri; | |||||
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_kanchor_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); | ||||
SLIST_INIT(&match_rules); | |||||
while (r != NULL) { | while (r != NULL) { | ||||
pf_counter_u64_add(&r->evaluations, 1); | pf_counter_u64_add(&r->evaluations, 1); | ||||
if (pfi_kkif_match(r->kif, kif) == r->ifnot) | if (pfi_kkif_match(r->kif, kif) == r->ifnot) | ||||
r = r->skip[PF_SKIP_IFP].ptr; | r = r->skip[PF_SKIP_IFP].ptr; | ||||
else if (r->direction && r->direction != direction) | else if (r->direction && r->direction != direction) | ||||
r = r->skip[PF_SKIP_DIR].ptr; | r = r->skip[PF_SKIP_DIR].ptr; | ||||
else if (r->af && r->af != af) | else if (r->af && r->af != af) | ||||
r = r->skip[PF_SKIP_AF].ptr; | r = r->skip[PF_SKIP_AF].ptr; | ||||
Show All 26 Lines | else if (r->prob && r->prob <= | ||||
(arc4random() % (UINT_MAX - 1) + 1)) | (arc4random() % (UINT_MAX - 1) + 1)) | ||||
r = TAILQ_NEXT(r, entries); | r = TAILQ_NEXT(r, entries); | ||||
else if (r->match_tag && !pf_match_tag(m, r, &tag, | else if (r->match_tag && !pf_match_tag(m, r, &tag, | ||||
pd->pf_mtag ? pd->pf_mtag->tag : 0)) | pd->pf_mtag ? pd->pf_mtag->tag : 0)) | ||||
r = TAILQ_NEXT(r, entries); | r = TAILQ_NEXT(r, entries); | ||||
else { | else { | ||||
if (r->anchor == NULL) { | if (r->anchor == NULL) { | ||||
if (r->action == PF_MATCH) { | if (r->action == PF_MATCH) { | ||||
ri = malloc(sizeof(struct pf_krule_item), M_PF_RULE_ITEM, M_NOWAIT | M_ZERO); | |||||
if (ri == NULL) { | |||||
kp: M_NOWAIT can fail allocation. We need to deal with the ri == NULL case here. | |||||
Done Inline ActionsFixed. vegeta_tuxpowered.net: Fixed. | |||||
REASON_SET(&reason, PFRES_MEMORY); | |||||
goto cleanup; | |||||
} | |||||
ri->r = r; | |||||
SLIST_INSERT_HEAD(&match_rules, ri, entry); | |||||
pf_counter_u64_critical_enter(); | pf_counter_u64_critical_enter(); | ||||
pf_counter_u64_add_protected(&r->packets[direction == PF_OUT], 1); | pf_counter_u64_add_protected(&r->packets[direction == PF_OUT], 1); | ||||
pf_counter_u64_add_protected(&r->bytes[direction == PF_OUT], pd->tot_len); | pf_counter_u64_add_protected(&r->bytes[direction == PF_OUT], pd->tot_len); | ||||
pf_counter_u64_critical_exit(); | pf_counter_u64_critical_exit(); | ||||
pf_rule_to_actions(r, &pd->act); | pf_rule_to_actions(r, &pd->act); | ||||
if (r->log) | if (r->log) | ||||
PFLOG_PACKET(kif, m, af, | PFLOG_PACKET(kif, m, af, | ||||
direction, PFRES_MATCH, r, | direction, PFRES_MATCH, r, | ||||
Show All 21 Lines | pf_test_fragment(struct pf_krule **rm, int direction, struct pfi_kkif *kif, | ||||
ruleset = *rsm; | ruleset = *rsm; | ||||
REASON_SET(&reason, PFRES_MATCH); | REASON_SET(&reason, PFRES_MATCH); | ||||
/* apply actions for last matching pass/block rule */ | /* apply actions for last matching pass/block rule */ | ||||
pf_rule_to_actions(r, &pd->act); | pf_rule_to_actions(r, &pd->act); | ||||
if (r->log) | if (r->log) | ||||
PFLOG_PACKET(kif, m, af, direction, reason, r, a, ruleset, pd, | PFLOG_PACKET(kif, m, af, direction, reason, r, a, | ||||
1); | ruleset, pd, 1); | ||||
Done Inline Actionsif (r->log && pd->act.log) ? kp: if (r->log && pd->act.log) ?
Also, given the pf_rule_to_actions() above, is it even possible… | |||||
Done Inline ActionsIndeed that was wrong. With logging of "match" rules directly when matching happens, and the same for the NAT rule, there is no need for those complicated checks. In fact this is what OpenBSD did too later. I've updated the code to match that of OpenBSD right before introduction of PF_LOG_MATCHES. vegeta_tuxpowered.net: Indeed that was wrong. With logging of "match" rules directly when matching happens, and the… | |||||
if (r->action != PF_PASS) | if (r->action != PF_PASS) | ||||
return (PF_DROP); | return (PF_DROP); | ||||
if (tag > 0 && pf_tag_packet(m, pd, tag)) { | if (tag > 0 && pf_tag_packet(m, pd, tag)) { | ||||
REASON_SET(&reason, PFRES_MEMORY); | REASON_SET(&reason, PFRES_MEMORY); | ||||
return (PF_DROP); | goto cleanup; | ||||
} | } | ||||
return (PF_PASS); | return (PF_PASS); | ||||
cleanup: | |||||
while ((ri = SLIST_FIRST(&match_rules))) { | |||||
SLIST_REMOVE_HEAD(&match_rules, entry); | |||||
free(ri, M_PF_RULE_ITEM); | |||||
} | } | ||||
return (PF_DROP); | |||||
} | |||||
static int | static int | ||||
pf_tcp_track_full(struct pf_kstate **state, struct pfi_kkif *kif, | pf_tcp_track_full(struct pf_kstate **state, struct pfi_kkif *kif, | ||||
struct mbuf *m, int off, struct pf_pdesc *pd, u_short *reason, | struct mbuf *m, int off, struct pf_pdesc *pd, u_short *reason, | ||||
int *copyback) | int *copyback) | ||||
{ | { | ||||
struct tcphdr *th = &pd->hdr.tcp; | struct tcphdr *th = &pd->hdr.tcp; | ||||
struct pf_state_peer *src, *dst; | struct pf_state_peer *src, *dst; | ||||
u_int16_t win = ntohs(th->th_win); | u_int16_t win = ntohs(th->th_win); | ||||
Show All 24 Lines | pf_tcp_track_full(struct pf_kstate **state, struct pfi_kkif *kif, | ||||
* http://www.madison-gurkha.com/publications/tcp_filtering/ | * http://www.madison-gurkha.com/publications/tcp_filtering/ | ||||
* tcp_filtering.ps | * tcp_filtering.ps | ||||
*/ | */ | ||||
orig_seq = seq = ntohl(th->th_seq); | orig_seq = seq = ntohl(th->th_seq); | ||||
if (src->seqlo == 0) { | if (src->seqlo == 0) { | ||||
/* First packet from this end. Set its state */ | /* First packet from this end. Set its state */ | ||||
if ((pd->flags & PFDESC_TCP_NORM || dst->scrub) && | if (((*state)->state_flags & PFSTATE_SCRUB_TCP || dst->scrub) && | ||||
src->scrub == NULL) { | src->scrub == NULL) { | ||||
if (pf_normalize_tcp_init(m, off, pd, th, src, dst)) { | if (pf_normalize_tcp_init(m, off, pd, th, src, dst)) { | ||||
REASON_SET(reason, PFRES_MEMORY); | REASON_SET(reason, PFRES_MEMORY); | ||||
return (PF_DROP); | return (PF_DROP); | ||||
} | } | ||||
} | } | ||||
/* Deferred generation of sequence number modulator */ | /* Deferred generation of sequence number modulator */ | ||||
▲ Show 20 Lines • Show All 252 Lines • ▼ Show 20 Lines | if (SEQ_GEQ(src->seqhi, end) && | ||||
if ((*state)->dst.state == TCPS_SYN_SENT && | if ((*state)->dst.state == TCPS_SYN_SENT && | ||||
(*state)->src.state == TCPS_SYN_SENT) { | (*state)->src.state == TCPS_SYN_SENT) { | ||||
/* Send RST for state mismatches during handshake */ | /* Send RST for state mismatches during handshake */ | ||||
if (!(th->th_flags & TH_RST)) | if (!(th->th_flags & TH_RST)) | ||||
pf_send_tcp((*state)->rule.ptr, pd->af, | pf_send_tcp((*state)->rule.ptr, pd->af, | ||||
pd->dst, pd->src, th->th_dport, | pd->dst, pd->src, th->th_dport, | ||||
th->th_sport, ntohl(th->th_ack), 0, | th->th_sport, ntohl(th->th_ack), 0, | ||||
TH_RST, 0, 0, | TH_RST, 0, 0, | ||||
(*state)->rule.ptr->return_ttl, 1, 0); | (*state)->rule.ptr->return_ttl, 1, 0, | ||||
(*state)->rtableid); | |||||
src->seqlo = 0; | src->seqlo = 0; | ||||
src->seqhi = 1; | src->seqhi = 1; | ||||
src->max_win = 1; | src->max_win = 1; | ||||
} else if (V_pf_status.debug >= PF_DEBUG_MISC) { | } else if (V_pf_status.debug >= PF_DEBUG_MISC) { | ||||
printf("pf: BAD state: "); | printf("pf: BAD state: "); | ||||
pf_print_state(*state); | pf_print_state(*state); | ||||
pf_print_flags(th->th_flags); | pf_print_flags(th->th_flags); | ||||
printf(" seq=%u (%u) ack=%u len=%u ackskew=%d " | printf(" seq=%u (%u) ack=%u len=%u ackskew=%d " | ||||
▲ Show 20 Lines • Show All 119 Lines • ▼ Show 20 Lines | if ((*state)->src.state == PF_TCPS_PROXY_SRC) { | ||||
if (th->th_flags & TH_SYN) { | if (th->th_flags & TH_SYN) { | ||||
if (ntohl(th->th_seq) != (*state)->src.seqlo) { | if (ntohl(th->th_seq) != (*state)->src.seqlo) { | ||||
REASON_SET(reason, PFRES_SYNPROXY); | REASON_SET(reason, PFRES_SYNPROXY); | ||||
return (PF_DROP); | return (PF_DROP); | ||||
} | } | ||||
pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst, | pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst, | ||||
pd->src, th->th_dport, th->th_sport, | pd->src, th->th_dport, th->th_sport, | ||||
(*state)->src.seqhi, ntohl(th->th_seq) + 1, | (*state)->src.seqhi, ntohl(th->th_seq) + 1, | ||||
TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1, 0); | TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1, 0, | ||||
(*state)->rtableid); | |||||
REASON_SET(reason, PFRES_SYNPROXY); | REASON_SET(reason, PFRES_SYNPROXY); | ||||
return (PF_SYNPROXY_DROP); | return (PF_SYNPROXY_DROP); | ||||
} else if ((th->th_flags & (TH_ACK|TH_RST|TH_FIN)) != TH_ACK || | } else if ((th->th_flags & (TH_ACK|TH_RST|TH_FIN)) != TH_ACK || | ||||
(ntohl(th->th_ack) != (*state)->src.seqhi + 1) || | (ntohl(th->th_ack) != (*state)->src.seqhi + 1) || | ||||
(ntohl(th->th_seq) != (*state)->src.seqlo + 1)) { | (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) { | ||||
REASON_SET(reason, PFRES_SYNPROXY); | REASON_SET(reason, PFRES_SYNPROXY); | ||||
return (PF_DROP); | return (PF_DROP); | ||||
} else if ((*state)->src_node != NULL && | } else if ((*state)->src_node != NULL && | ||||
Show All 14 Lines | if (pd->dir == (*state)->direction) { | ||||
} | } | ||||
(*state)->src.max_win = MAX(ntohs(th->th_win), 1); | (*state)->src.max_win = MAX(ntohs(th->th_win), 1); | ||||
if ((*state)->dst.seqhi == 1) | if ((*state)->dst.seqhi == 1) | ||||
(*state)->dst.seqhi = htonl(arc4random()); | (*state)->dst.seqhi = htonl(arc4random()); | ||||
pf_send_tcp((*state)->rule.ptr, pd->af, | pf_send_tcp((*state)->rule.ptr, pd->af, | ||||
&sk->addr[pd->sidx], &sk->addr[pd->didx], | &sk->addr[pd->sidx], &sk->addr[pd->didx], | ||||
sk->port[pd->sidx], sk->port[pd->didx], | sk->port[pd->sidx], sk->port[pd->didx], | ||||
(*state)->dst.seqhi, 0, TH_SYN, 0, | (*state)->dst.seqhi, 0, TH_SYN, 0, | ||||
(*state)->src.mss, 0, 0, (*state)->tag); | (*state)->src.mss, 0, 0, (*state)->tag, | ||||
(*state)->rtableid); | |||||
REASON_SET(reason, PFRES_SYNPROXY); | REASON_SET(reason, PFRES_SYNPROXY); | ||||
return (PF_SYNPROXY_DROP); | return (PF_SYNPROXY_DROP); | ||||
} else if (((th->th_flags & (TH_SYN|TH_ACK)) != | } else if (((th->th_flags & (TH_SYN|TH_ACK)) != | ||||
(TH_SYN|TH_ACK)) || | (TH_SYN|TH_ACK)) || | ||||
(ntohl(th->th_ack) != (*state)->dst.seqhi + 1)) { | (ntohl(th->th_ack) != (*state)->dst.seqhi + 1)) { | ||||
REASON_SET(reason, PFRES_SYNPROXY); | REASON_SET(reason, PFRES_SYNPROXY); | ||||
return (PF_DROP); | return (PF_DROP); | ||||
} else { | } else { | ||||
(*state)->dst.max_win = MAX(ntohs(th->th_win), 1); | (*state)->dst.max_win = MAX(ntohs(th->th_win), 1); | ||||
(*state)->dst.seqlo = ntohl(th->th_seq); | (*state)->dst.seqlo = ntohl(th->th_seq); | ||||
pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst, | pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst, | ||||
pd->src, th->th_dport, th->th_sport, | pd->src, th->th_dport, th->th_sport, | ||||
ntohl(th->th_ack), ntohl(th->th_seq) + 1, | ntohl(th->th_ack), ntohl(th->th_seq) + 1, | ||||
TH_ACK, (*state)->src.max_win, 0, 0, 0, | TH_ACK, (*state)->src.max_win, 0, 0, 0, | ||||
(*state)->tag); | (*state)->tag, (*state)->rtableid); | ||||
pf_send_tcp((*state)->rule.ptr, pd->af, | pf_send_tcp((*state)->rule.ptr, pd->af, | ||||
&sk->addr[pd->sidx], &sk->addr[pd->didx], | &sk->addr[pd->sidx], &sk->addr[pd->didx], | ||||
sk->port[pd->sidx], sk->port[pd->didx], | sk->port[pd->sidx], sk->port[pd->didx], | ||||
(*state)->src.seqhi + 1, (*state)->src.seqlo + 1, | (*state)->src.seqhi + 1, (*state)->src.seqlo + 1, | ||||
TH_ACK, (*state)->dst.max_win, 0, 0, 1, 0); | TH_ACK, (*state)->dst.max_win, 0, 0, 1, 0, | ||||
(*state)->rtableid); | |||||
(*state)->src.seqdiff = (*state)->dst.seqhi - | (*state)->src.seqdiff = (*state)->dst.seqhi - | ||||
(*state)->src.seqlo; | (*state)->src.seqlo; | ||||
(*state)->dst.seqdiff = (*state)->src.seqhi - | (*state)->dst.seqdiff = (*state)->src.seqhi - | ||||
(*state)->dst.seqlo; | (*state)->dst.seqlo; | ||||
(*state)->src.seqhi = (*state)->src.seqlo + | (*state)->src.seqhi = (*state)->src.seqlo + | ||||
(*state)->dst.max_win; | (*state)->dst.max_win; | ||||
(*state)->dst.seqhi = (*state)->dst.seqlo + | (*state)->dst.seqhi = (*state)->dst.seqlo + | ||||
(*state)->src.max_win; | (*state)->src.max_win; | ||||
▲ Show 20 Lines • Show All 1,483 Lines • ▼ Show 20 Lines | pf_pdesc_to_dnflow(int dir, const struct pf_pdesc *pd, | ||||
else if (dir == dndir && pd->act.dnpipe) { | else if (dir == dndir && pd->act.dnpipe) { | ||||
dnflow->rule.info = pd->act.dnpipe; | dnflow->rule.info = pd->act.dnpipe; | ||||
} | } | ||||
else { | else { | ||||
return (false); | return (false); | ||||
} | } | ||||
dnflow->rule.info |= IPFW_IS_DUMMYNET; | dnflow->rule.info |= IPFW_IS_DUMMYNET; | ||||
if (r->free_flags & PFRULE_DN_IS_PIPE || pd->act.flags & PFRULE_DN_IS_PIPE) | if (r->free_flags & PFRULE_DN_IS_PIPE || pd->act.dnflags & PFRULE_DN_IS_PIPE) | ||||
dnflow->rule.info |= IPFW_IS_PIPE; | dnflow->rule.info |= IPFW_IS_PIPE; | ||||
dnflow->f_id.proto = pd->proto; | dnflow->f_id.proto = pd->proto; | ||||
dnflow->f_id.extra = dnflow->rule.info; | dnflow->f_id.extra = dnflow->rule.info; | ||||
switch (pd->af) { | switch (pd->af) { | ||||
case AF_INET: | case AF_INET: | ||||
dnflow->f_id.addr_type = 4; | dnflow->f_id.addr_type = 4; | ||||
dnflow->f_id.src_ip = ntohl(pd->src->v4.s_addr); | dnflow->f_id.src_ip = ntohl(pd->src->v4.s_addr); | ||||
▲ Show 20 Lines • Show All 213 Lines • ▼ Show 20 Lines | pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp) | ||||
} | } | ||||
m = *m0; /* pf_normalize messes with m0 */ | m = *m0; /* pf_normalize messes with m0 */ | ||||
h = mtod(m, struct ip *); | h = mtod(m, struct ip *); | ||||
off = h->ip_hl << 2; | off = h->ip_hl << 2; | ||||
if (off < (int)sizeof(struct ip)) { | if (off < (int)sizeof(struct ip)) { | ||||
action = PF_DROP; | action = PF_DROP; | ||||
REASON_SET(&reason, PFRES_SHORT); | REASON_SET(&reason, PFRES_SHORT); | ||||
log = 1; | log = PF_LOG_FORCE; | ||||
goto done; | goto done; | ||||
} | } | ||||
pd.src = (struct pf_addr *)&h->ip_src; | pd.src = (struct pf_addr *)&h->ip_src; | ||||
pd.dst = (struct pf_addr *)&h->ip_dst; | pd.dst = (struct pf_addr *)&h->ip_dst; | ||||
pd.sport = pd.dport = NULL; | pd.sport = pd.dport = NULL; | ||||
pd.ip_sum = &h->ip_sum; | pd.ip_sum = &h->ip_sum; | ||||
pd.proto_sum = NULL; | pd.proto_sum = NULL; | ||||
pd.proto = h->ip_p; | pd.proto = h->ip_p; | ||||
pd.dir = dir; | pd.dir = dir; | ||||
pd.sidx = (dir == PF_IN) ? 0 : 1; | pd.sidx = (dir == PF_IN) ? 0 : 1; | ||||
pd.didx = (dir == PF_IN) ? 1 : 0; | pd.didx = (dir == PF_IN) ? 1 : 0; | ||||
pd.af = AF_INET; | pd.af = AF_INET; | ||||
pd.tos = h->ip_tos & ~IPTOS_ECN_MASK; | pd.tos = h->ip_tos & ~IPTOS_ECN_MASK; | ||||
pd.tot_len = ntohs(h->ip_len); | pd.tot_len = ntohs(h->ip_len); | ||||
pd.act.rtableid = -1; | |||||
/* handle fragments that didn't get reassembled by normalization */ | /* handle fragments that didn't get reassembled by normalization */ | ||||
if (h->ip_off & htons(IP_MF | IP_OFFMASK)) { | if (h->ip_off & htons(IP_MF | IP_OFFMASK)) { | ||||
action = pf_test_fragment(&r, dir, kif, m, h, | action = pf_test_fragment(&r, dir, kif, m, h, | ||||
&pd, &a, &ruleset); | &pd, &a, &ruleset); | ||||
goto done; | goto done; | ||||
} | } | ||||
switch (h->ip_p) { | switch (h->ip_p) { | ||||
case IPPROTO_TCP: { | case IPPROTO_TCP: { | ||||
if (!pf_pull_hdr(m, off, &pd.hdr.tcp, sizeof(pd.hdr.tcp), | if (!pf_pull_hdr(m, off, &pd.hdr.tcp, sizeof(pd.hdr.tcp), | ||||
&action, &reason, AF_INET)) { | &action, &reason, AF_INET)) { | ||||
log = action != PF_PASS; | if (action != PF_PASS) | ||||
log = PF_LOG_FORCE; | |||||
goto done; | goto done; | ||||
} | } | ||||
pd.p_len = pd.tot_len - off - (pd.hdr.tcp.th_off << 2); | pd.p_len = pd.tot_len - off - (pd.hdr.tcp.th_off << 2); | ||||
pd.sport = &pd.hdr.tcp.th_sport; | pd.sport = &pd.hdr.tcp.th_sport; | ||||
pd.dport = &pd.hdr.tcp.th_dport; | pd.dport = &pd.hdr.tcp.th_dport; | ||||
/* Respond to SYN with a syncookie. */ | /* Respond to SYN with a syncookie. */ | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | if (action == PF_PASS) { | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
else { | else { | ||||
action = pf_test_rule(&r, &s, dir, kif, m, off, | action = pf_test_rule(&r, &s, dir, kif, m, off, | ||||
&pd, &a, &ruleset, inp); | &pd, &a, &ruleset, inp); | ||||
} | } | ||||
} | } | ||||
if (s) { | |||||
if (s->max_mss) | |||||
pf_normalize_mss(m, off, &pd, s->max_mss); | |||||
} else if (r->max_mss) | |||||
pf_normalize_mss(m, off, &pd, r->max_mss); | |||||
break; | break; | ||||
} | } | ||||
case IPPROTO_UDP: { | case IPPROTO_UDP: { | ||||
if (!pf_pull_hdr(m, off, &pd.hdr.udp, sizeof(pd.hdr.udp), | if (!pf_pull_hdr(m, off, &pd.hdr.udp, sizeof(pd.hdr.udp), | ||||
&action, &reason, AF_INET)) { | &action, &reason, AF_INET)) { | ||||
log = action != PF_PASS; | if (action != PF_PASS) | ||||
log = PF_LOG_FORCE; | |||||
goto done; | goto done; | ||||
} | } | ||||
pd.sport = &pd.hdr.udp.uh_sport; | pd.sport = &pd.hdr.udp.uh_sport; | ||||
pd.dport = &pd.hdr.udp.uh_dport; | pd.dport = &pd.hdr.udp.uh_dport; | ||||
if (pd.hdr.udp.uh_dport == 0 || | if (pd.hdr.udp.uh_dport == 0 || | ||||
ntohs(pd.hdr.udp.uh_ulen) > m->m_pkthdr.len - off || | ntohs(pd.hdr.udp.uh_ulen) > m->m_pkthdr.len - off || | ||||
ntohs(pd.hdr.udp.uh_ulen) < sizeof(struct udphdr)) { | ntohs(pd.hdr.udp.uh_ulen) < sizeof(struct udphdr)) { | ||||
action = PF_DROP; | action = PF_DROP; | ||||
Show All 11 Lines | if (action == PF_PASS) { | ||||
action = pf_test_rule(&r, &s, dir, kif, m, off, &pd, | action = pf_test_rule(&r, &s, dir, kif, m, off, &pd, | ||||
&a, &ruleset, inp); | &a, &ruleset, inp); | ||||
break; | break; | ||||
} | } | ||||
case IPPROTO_ICMP: { | case IPPROTO_ICMP: { | ||||
if (!pf_pull_hdr(m, off, &pd.hdr.icmp, ICMP_MINLEN, | if (!pf_pull_hdr(m, off, &pd.hdr.icmp, ICMP_MINLEN, | ||||
&action, &reason, AF_INET)) { | &action, &reason, AF_INET)) { | ||||
log = action != PF_PASS; | if (action != PF_PASS) | ||||
log = PF_LOG_FORCE; | |||||
goto done; | goto done; | ||||
} | } | ||||
action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd, | action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd, | ||||
&reason); | &reason); | ||||
if (action == PF_PASS) { | if (action == PF_PASS) { | ||||
if (V_pfsync_update_state_ptr != NULL) | if (V_pfsync_update_state_ptr != NULL) | ||||
V_pfsync_update_state_ptr(s); | V_pfsync_update_state_ptr(s); | ||||
r = s->rule.ptr; | r = s->rule.ptr; | ||||
Show All 29 Lines | #endif | ||||
} | } | ||||
done: | done: | ||||
PF_RULES_RUNLOCK(); | PF_RULES_RUNLOCK(); | ||||
if (action == PF_PASS && h->ip_hl > 5 && | if (action == PF_PASS && h->ip_hl > 5 && | ||||
!((s && s->state_flags & PFSTATE_ALLOWOPTS) || r->allow_opts)) { | !((s && s->state_flags & PFSTATE_ALLOWOPTS) || r->allow_opts)) { | ||||
action = PF_DROP; | action = PF_DROP; | ||||
REASON_SET(&reason, PFRES_IPOPTIONS); | REASON_SET(&reason, PFRES_IPOPTIONS); | ||||
log = r->log; | log = PF_LOG_FORCE; | ||||
DPFPRINTF(PF_DEBUG_MISC, | DPFPRINTF(PF_DEBUG_MISC, | ||||
("pf: dropping packet with ip options\n")); | ("pf: dropping packet with ip options\n")); | ||||
} | } | ||||
if (s) { | |||||
pf_scrub_ip(&m, s->state_flags, s->min_ttl, s->set_tos); | |||||
if (s->rtableid >= 0) | |||||
M_SETFIB(m, s->rtableid); | |||||
#ifdef ALTQ | |||||
if (s->qid) { | |||||
pd.act.pqid = s->pqid; | |||||
pd.act.qid = s->qid; | |||||
} | |||||
#endif | |||||
} else { | |||||
pf_scrub_ip(&m, r->scrub_flags, r->min_ttl, r->set_tos); | |||||
if (r->rtableid >= 0) | |||||
M_SETFIB(m, r->rtableid); | |||||
#ifdef ALTQ | |||||
if (r->qid) { | |||||
pd.act.pqid = r->pqid; | |||||
pd.act.qid = r->qid; | |||||
} | |||||
#endif | |||||
} | |||||
if (s && s->tag > 0 && pf_tag_packet(m, &pd, s->tag)) { | if (s && s->tag > 0 && pf_tag_packet(m, &pd, s->tag)) { | ||||
action = PF_DROP; | action = PF_DROP; | ||||
REASON_SET(&reason, PFRES_MEMORY); | REASON_SET(&reason, PFRES_MEMORY); | ||||
} | } | ||||
if (r->rtableid >= 0) | |||||
M_SETFIB(m, r->rtableid); | |||||
if (r->scrub_flags & PFSTATE_SETPRIO) { | if (r->scrub_flags & PFSTATE_SETPRIO) { | ||||
if (pd.tos & IPTOS_LOWDELAY) | if (pd.tos & IPTOS_LOWDELAY) | ||||
pqid = 1; | pqid = 1; | ||||
if (vlan_set_pcp(m, r->set_prio[pqid])) { | if (vlan_set_pcp(m, r->set_prio[pqid])) { | ||||
action = PF_DROP; | action = PF_DROP; | ||||
REASON_SET(&reason, PFRES_MEMORY); | REASON_SET(&reason, PFRES_MEMORY); | ||||
log = 1; | log = PF_LOG_FORCE; | ||||
DPFPRINTF(PF_DEBUG_MISC, | DPFPRINTF(PF_DEBUG_MISC, | ||||
("pf: failed to allocate 802.1q mtag\n")); | ("pf: failed to allocate 802.1q mtag\n")); | ||||
} | } | ||||
} | } | ||||
#ifdef ALTQ | #ifdef ALTQ | ||||
if (s && s->qid) { | |||||
pd.act.pqid = s->pqid; | |||||
pd.act.qid = s->qid; | |||||
} else if (r->qid) { | |||||
pd.act.pqid = r->pqid; | |||||
pd.act.qid = r->qid; | |||||
} | |||||
if (action == PF_PASS && pd.act.qid) { | if (action == PF_PASS && pd.act.qid) { | ||||
if (pd.pf_mtag == NULL && | if (pd.pf_mtag == NULL && | ||||
((pd.pf_mtag = pf_get_mtag(m)) == NULL)) { | ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) { | ||||
action = PF_DROP; | action = PF_DROP; | ||||
REASON_SET(&reason, PFRES_MEMORY); | REASON_SET(&reason, PFRES_MEMORY); | ||||
} else { | } else { | ||||
if (s != NULL) | if (s != NULL) | ||||
pd.pf_mtag->qid_hash = pf_state_hash(s); | pd.pf_mtag->qid_hash = pf_state_hash(s); | ||||
Show All 32 Lines | if (ipfwtag != NULL) { | ||||
PF_STATE_UNLOCK(s); | PF_STATE_UNLOCK(s); | ||||
m_tag_prepend(m, ipfwtag); | m_tag_prepend(m, ipfwtag); | ||||
if (m->m_flags & M_FASTFWD_OURS) { | if (m->m_flags & M_FASTFWD_OURS) { | ||||
if (pd.pf_mtag == NULL && | if (pd.pf_mtag == NULL && | ||||
((pd.pf_mtag = pf_get_mtag(m)) == NULL)) { | ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) { | ||||
action = PF_DROP; | action = PF_DROP; | ||||
REASON_SET(&reason, PFRES_MEMORY); | REASON_SET(&reason, PFRES_MEMORY); | ||||
log = 1; | log = PF_LOG_FORCE; | ||||
DPFPRINTF(PF_DEBUG_MISC, | DPFPRINTF(PF_DEBUG_MISC, | ||||
("pf: failed to allocate tag\n")); | ("pf: failed to allocate tag\n")); | ||||
} else { | } else { | ||||
pd.pf_mtag->flags |= | pd.pf_mtag->flags |= | ||||
PF_FASTFWD_OURS_PRESENT; | PF_FASTFWD_OURS_PRESENT; | ||||
m->m_flags &= ~M_FASTFWD_OURS; | m->m_flags &= ~M_FASTFWD_OURS; | ||||
} | } | ||||
} | } | ||||
ip_divert_ptr(*m0, dir == PF_IN); | ip_divert_ptr(*m0, dir == PF_IN); | ||||
*m0 = NULL; | *m0 = NULL; | ||||
return (action); | return (action); | ||||
} else { | } else { | ||||
/* XXX: ipfw has the same behaviour! */ | /* XXX: ipfw has the same behaviour! */ | ||||
action = PF_DROP; | action = PF_DROP; | ||||
REASON_SET(&reason, PFRES_MEMORY); | REASON_SET(&reason, PFRES_MEMORY); | ||||
log = 1; | log = PF_LOG_FORCE; | ||||
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_krule *lr; | struct pf_krule *lr; | ||||
struct pf_krule_item *ri; | |||||
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, | |||||
(s == NULL)); | if (log & PF_LOG_FORCE || lr->log & PF_LOG_ALL) | ||||
PFLOG_PACKET(kif, m, AF_INET, dir, reason, lr, a, | |||||
ruleset, &pd, (s == NULL)); | |||||
if (s) { | |||||
SLIST_FOREACH(ri, &s->match_rules, entry) | |||||
if (ri->r->log & PF_LOG_ALL) | |||||
PFLOG_PACKET(kif, m, AF_INET, dir, | |||||
reason, ri->r, a, ruleset, &pd, 0); | |||||
} | } | ||||
} | |||||
pf_counter_u64_critical_enter(); | pf_counter_u64_critical_enter(); | ||||
pf_counter_u64_add_protected(&kif->pfik_bytes[0][dir == PF_OUT][action != PF_PASS], | pf_counter_u64_add_protected(&kif->pfik_bytes[0][dir == PF_OUT][action != PF_PASS], | ||||
pd.tot_len); | pd.tot_len); | ||||
pf_counter_u64_add_protected(&kif->pfik_packets[0][dir == PF_OUT][action != PF_PASS], | pf_counter_u64_add_protected(&kif->pfik_packets[0][dir == PF_OUT][action != PF_PASS], | ||||
1); | 1); | ||||
if (action == PF_PASS || r->action == PF_DROP) { | if (action == PF_PASS || r->action == PF_DROP) { | ||||
dirndx = (dir == PF_OUT); | dirndx = (dir == PF_OUT); | ||||
pf_counter_u64_add_protected(&r->packets[dirndx], 1); | pf_counter_u64_add_protected(&r->packets[dirndx], 1); | ||||
pf_counter_u64_add_protected(&r->bytes[dirndx], pd.tot_len); | pf_counter_u64_add_protected(&r->bytes[dirndx], pd.tot_len); | ||||
pf_update_timestamp(r); | pf_update_timestamp(r); | ||||
if (a != NULL) { | if (a != NULL) { | ||||
pf_counter_u64_add_protected(&a->packets[dirndx], 1); | pf_counter_u64_add_protected(&a->packets[dirndx], 1); | ||||
pf_counter_u64_add_protected(&a->bytes[dirndx], pd.tot_len); | pf_counter_u64_add_protected(&a->bytes[dirndx], pd.tot_len); | ||||
} | } | ||||
if (s != NULL) { | if (s != NULL) { | ||||
struct pf_krule_item *ri; | |||||
if (s->nat_rule.ptr != NULL) { | if (s->nat_rule.ptr != NULL) { | ||||
pf_counter_u64_add_protected(&s->nat_rule.ptr->packets[dirndx], | pf_counter_u64_add_protected(&s->nat_rule.ptr->packets[dirndx], | ||||
1); | 1); | ||||
pf_counter_u64_add_protected(&s->nat_rule.ptr->bytes[dirndx], | pf_counter_u64_add_protected(&s->nat_rule.ptr->bytes[dirndx], | ||||
pd.tot_len); | pd.tot_len); | ||||
} | } | ||||
if (s->src_node != NULL) { | if (s->src_node != NULL) { | ||||
counter_u64_add(s->src_node->packets[dirndx], | counter_u64_add(s->src_node->packets[dirndx], | ||||
1); | 1); | ||||
counter_u64_add(s->src_node->bytes[dirndx], | counter_u64_add(s->src_node->bytes[dirndx], | ||||
pd.tot_len); | pd.tot_len); | ||||
} | } | ||||
if (s->nat_src_node != NULL) { | if (s->nat_src_node != NULL) { | ||||
counter_u64_add(s->nat_src_node->packets[dirndx], | counter_u64_add(s->nat_src_node->packets[dirndx], | ||||
1); | 1); | ||||
counter_u64_add(s->nat_src_node->bytes[dirndx], | counter_u64_add(s->nat_src_node->bytes[dirndx], | ||||
pd.tot_len); | pd.tot_len); | ||||
} | } | ||||
dirndx = (dir == s->direction) ? 0 : 1; | dirndx = (dir == s->direction) ? 0 : 1; | ||||
s->packets[dirndx]++; | s->packets[dirndx]++; | ||||
s->bytes[dirndx] += pd.tot_len; | s->bytes[dirndx] += pd.tot_len; | ||||
SLIST_FOREACH(ri, &s->match_rules, entry) { | |||||
pf_counter_u64_add_protected(&ri->r->packets[dirndx], 1); | |||||
pf_counter_u64_add_protected(&ri->r->bytes[dirndx], pd.tot_len); | |||||
} | } | ||||
} | |||||
tr = r; | tr = r; | ||||
nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule; | nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule; | ||||
if (nr != NULL && r == &V_pf_default_rule) | if (nr != NULL && r == &V_pf_default_rule) | ||||
tr = nr; | tr = nr; | ||||
if (tr->src.addr.type == PF_ADDR_TABLE) | if (tr->src.addr.type == PF_ADDR_TABLE) | ||||
pfr_update_stats(tr->src.addr.p.tbl, | pfr_update_stats(tr->src.addr.p.tbl, | ||||
(s == NULL) ? pd.src : | (s == NULL) ? pd.src : | ||||
&s->key[(s->direction == PF_IN)]-> | &s->key[(s->direction == PF_IN)]-> | ||||
▲ Show 20 Lines • Show All 144 Lines • ▼ Show 20 Lines | pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp) | ||||
pd.ip_sum = NULL; | pd.ip_sum = NULL; | ||||
pd.proto_sum = NULL; | pd.proto_sum = NULL; | ||||
pd.dir = dir; | pd.dir = dir; | ||||
pd.sidx = (dir == PF_IN) ? 0 : 1; | pd.sidx = (dir == PF_IN) ? 0 : 1; | ||||
pd.didx = (dir == PF_IN) ? 1 : 0; | pd.didx = (dir == PF_IN) ? 1 : 0; | ||||
pd.af = AF_INET6; | pd.af = AF_INET6; | ||||
pd.tos = IPV6_DSCP(h); | pd.tos = IPV6_DSCP(h); | ||||
pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr); | pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr); | ||||
pd.act.rtableid = -1; | |||||
off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr); | off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr); | ||||
pd.proto = h->ip6_nxt; | pd.proto = h->ip6_nxt; | ||||
do { | do { | ||||
switch (pd.proto) { | switch (pd.proto) { | ||||
case IPPROTO_FRAGMENT: | case IPPROTO_FRAGMENT: | ||||
action = pf_test_fragment(&r, dir, kif, m, h, | action = pf_test_fragment(&r, dir, kif, m, h, | ||||
&pd, &a, &ruleset); | &pd, &a, &ruleset); | ||||
if (action == PF_DROP) | if (action == PF_DROP) | ||||
REASON_SET(&reason, PFRES_FRAG); | REASON_SET(&reason, PFRES_FRAG); | ||||
goto done; | goto done; | ||||
case IPPROTO_ROUTING: { | case IPPROTO_ROUTING: { | ||||
struct ip6_rthdr rthdr; | struct ip6_rthdr rthdr; | ||||
if (rh_cnt++) { | if (rh_cnt++) { | ||||
DPFPRINTF(PF_DEBUG_MISC, | DPFPRINTF(PF_DEBUG_MISC, | ||||
("pf: IPv6 more than one rthdr\n")); | ("pf: IPv6 more than one rthdr\n")); | ||||
action = PF_DROP; | action = PF_DROP; | ||||
REASON_SET(&reason, PFRES_IPOPTIONS); | REASON_SET(&reason, PFRES_IPOPTIONS); | ||||
log = 1; | log = PF_LOG_FORCE; | ||||
goto done; | goto done; | ||||
} | } | ||||
if (!pf_pull_hdr(m, off, &rthdr, sizeof(rthdr), NULL, | if (!pf_pull_hdr(m, off, &rthdr, sizeof(rthdr), NULL, | ||||
&reason, pd.af)) { | &reason, pd.af)) { | ||||
DPFPRINTF(PF_DEBUG_MISC, | DPFPRINTF(PF_DEBUG_MISC, | ||||
("pf: IPv6 short rthdr\n")); | ("pf: IPv6 short rthdr\n")); | ||||
action = PF_DROP; | action = PF_DROP; | ||||
REASON_SET(&reason, PFRES_SHORT); | REASON_SET(&reason, PFRES_SHORT); | ||||
log = 1; | log = PF_LOG_FORCE; | ||||
goto done; | goto done; | ||||
} | } | ||||
if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) { | if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) { | ||||
DPFPRINTF(PF_DEBUG_MISC, | DPFPRINTF(PF_DEBUG_MISC, | ||||
("pf: IPv6 rthdr0\n")); | ("pf: IPv6 rthdr0\n")); | ||||
action = PF_DROP; | action = PF_DROP; | ||||
REASON_SET(&reason, PFRES_IPOPTIONS); | REASON_SET(&reason, PFRES_IPOPTIONS); | ||||
log = 1; | log = PF_LOG_FORCE; | ||||
goto done; | goto done; | ||||
} | } | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
} | } | ||||
case IPPROTO_AH: | case IPPROTO_AH: | ||||
case IPPROTO_HOPOPTS: | case IPPROTO_HOPOPTS: | ||||
case IPPROTO_DSTOPTS: { | case IPPROTO_DSTOPTS: { | ||||
/* get next header and header length */ | /* get next header and header length */ | ||||
struct ip6_ext opt6; | struct ip6_ext opt6; | ||||
if (!pf_pull_hdr(m, off, &opt6, sizeof(opt6), | if (!pf_pull_hdr(m, off, &opt6, sizeof(opt6), | ||||
NULL, &reason, pd.af)) { | NULL, &reason, pd.af)) { | ||||
DPFPRINTF(PF_DEBUG_MISC, | DPFPRINTF(PF_DEBUG_MISC, | ||||
("pf: IPv6 short opt\n")); | ("pf: IPv6 short opt\n")); | ||||
action = PF_DROP; | action = PF_DROP; | ||||
log = 1; | log = PF_LOG_FORCE; | ||||
goto done; | goto done; | ||||
} | } | ||||
if (pd.proto == IPPROTO_AH) | if (pd.proto == IPPROTO_AH) | ||||
off += (opt6.ip6e_len + 2) * 4; | off += (opt6.ip6e_len + 2) * 4; | ||||
else | else | ||||
off += (opt6.ip6e_len + 1) * 8; | off += (opt6.ip6e_len + 1) * 8; | ||||
pd.proto = opt6.ip6e_nxt; | pd.proto = opt6.ip6e_nxt; | ||||
/* goto the next header */ | /* goto the next header */ | ||||
break; | break; | ||||
} | } | ||||
default: | default: | ||||
terminal++; | terminal++; | ||||
break; | break; | ||||
} | } | ||||
} while (!terminal); | } while (!terminal); | ||||
/* if there's no routing header, use unmodified mbuf for checksumming */ | /* if there's no routing header, use unmodified mbuf for checksumming */ | ||||
if (!n) | if (!n) | ||||
n = m; | n = m; | ||||
switch (pd.proto) { | switch (pd.proto) { | ||||
case IPPROTO_TCP: { | case IPPROTO_TCP: { | ||||
if (!pf_pull_hdr(m, off, &pd.hdr.tcp, sizeof(pd.hdr.tcp), | if (!pf_pull_hdr(m, off, &pd.hdr.tcp, sizeof(pd.hdr.tcp), | ||||
&action, &reason, AF_INET6)) { | &action, &reason, AF_INET6)) { | ||||
log = action != PF_PASS; | if (action != PF_PASS) | ||||
log |= PF_LOG_FORCE; | |||||
goto done; | goto done; | ||||
} | } | ||||
pd.p_len = pd.tot_len - off - (pd.hdr.tcp.th_off << 2); | pd.p_len = pd.tot_len - off - (pd.hdr.tcp.th_off << 2); | ||||
pd.sport = &pd.hdr.tcp.th_sport; | pd.sport = &pd.hdr.tcp.th_sport; | ||||
pd.dport = &pd.hdr.tcp.th_dport; | pd.dport = &pd.hdr.tcp.th_dport; | ||||
action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd); | action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd); | ||||
if (action == PF_DROP) | if (action == PF_DROP) | ||||
goto done; | goto done; | ||||
action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd, | action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd, | ||||
&reason); | &reason); | ||||
if (action == PF_PASS) { | if (action == PF_PASS) { | ||||
if (V_pfsync_update_state_ptr != NULL) | if (V_pfsync_update_state_ptr != NULL) | ||||
V_pfsync_update_state_ptr(s); | V_pfsync_update_state_ptr(s); | ||||
r = s->rule.ptr; | r = s->rule.ptr; | ||||
a = s->anchor.ptr; | a = s->anchor.ptr; | ||||
log = s->log; | log = s->log; | ||||
} else if (s == NULL) | } else if (s == NULL) | ||||
action = pf_test_rule(&r, &s, dir, kif, m, off, &pd, | action = pf_test_rule(&r, &s, dir, kif, m, off, &pd, | ||||
&a, &ruleset, inp); | &a, &ruleset, inp); | ||||
if (s) { | |||||
if (s->max_mss) | |||||
pf_normalize_mss(m, off, &pd, s->max_mss); | |||||
} else if (r->max_mss) | |||||
pf_normalize_mss(m, off, &pd, r->max_mss); | |||||
break; | break; | ||||
} | } | ||||
case IPPROTO_UDP: { | case IPPROTO_UDP: { | ||||
if (!pf_pull_hdr(m, off, &pd.hdr.udp, sizeof(pd.hdr.udp), | if (!pf_pull_hdr(m, off, &pd.hdr.udp, sizeof(pd.hdr.udp), | ||||
&action, &reason, AF_INET6)) { | &action, &reason, AF_INET6)) { | ||||
log = action != PF_PASS; | if (action != PF_PASS) | ||||
log |= PF_LOG_FORCE; | |||||
goto done; | goto done; | ||||
} | } | ||||
pd.sport = &pd.hdr.udp.uh_sport; | pd.sport = &pd.hdr.udp.uh_sport; | ||||
pd.dport = &pd.hdr.udp.uh_dport; | pd.dport = &pd.hdr.udp.uh_dport; | ||||
if (pd.hdr.udp.uh_dport == 0 || | if (pd.hdr.udp.uh_dport == 0 || | ||||
ntohs(pd.hdr.udp.uh_ulen) > m->m_pkthdr.len - off || | ntohs(pd.hdr.udp.uh_ulen) > m->m_pkthdr.len - off || | ||||
ntohs(pd.hdr.udp.uh_ulen) < sizeof(struct udphdr)) { | ntohs(pd.hdr.udp.uh_ulen) < sizeof(struct udphdr)) { | ||||
action = PF_DROP; | action = PF_DROP; | ||||
Show All 18 Lines | case IPPROTO_ICMP: { | ||||
DPFPRINTF(PF_DEBUG_MISC, | DPFPRINTF(PF_DEBUG_MISC, | ||||
("pf: dropping IPv6 packet with ICMPv4 payload\n")); | ("pf: dropping IPv6 packet with ICMPv4 payload\n")); | ||||
goto done; | goto done; | ||||
} | } | ||||
case IPPROTO_ICMPV6: { | case IPPROTO_ICMPV6: { | ||||
if (!pf_pull_hdr(m, off, &pd.hdr.icmp6, sizeof(pd.hdr.icmp6), | if (!pf_pull_hdr(m, off, &pd.hdr.icmp6, sizeof(pd.hdr.icmp6), | ||||
&action, &reason, AF_INET6)) { | &action, &reason, AF_INET6)) { | ||||
log = action != PF_PASS; | if (action != PF_PASS) | ||||
log |= PF_LOG_FORCE; | |||||
goto done; | goto done; | ||||
} | } | ||||
action = pf_test_state_icmp(&s, dir, kif, | action = pf_test_state_icmp(&s, dir, kif, | ||||
m, off, h, &pd, &reason); | m, off, h, &pd, &reason); | ||||
if (action == PF_PASS) { | if (action == PF_PASS) { | ||||
if (V_pfsync_update_state_ptr != NULL) | if (V_pfsync_update_state_ptr != NULL) | ||||
V_pfsync_update_state_ptr(s); | V_pfsync_update_state_ptr(s); | ||||
r = s->rule.ptr; | r = s->rule.ptr; | ||||
Show All 35 Lines | if (action == PF_PASS && rh_cnt && | ||||
DPFPRINTF(PF_DEBUG_MISC, | DPFPRINTF(PF_DEBUG_MISC, | ||||
("pf: dropping packet with dangerous v6 headers\n")); | ("pf: dropping packet with dangerous v6 headers\n")); | ||||
} | } | ||||
if (s && s->tag > 0 && pf_tag_packet(m, &pd, s->tag)) { | if (s && s->tag > 0 && pf_tag_packet(m, &pd, s->tag)) { | ||||
action = PF_DROP; | action = PF_DROP; | ||||
REASON_SET(&reason, PFRES_MEMORY); | REASON_SET(&reason, PFRES_MEMORY); | ||||
} | } | ||||
if (s) { | |||||
pf_scrub_ip6(&m, s->state_flags, s->min_ttl, s->set_tos); | |||||
if (s->rtableid >= 0) | |||||
M_SETFIB(m, s->rtableid); | |||||
#ifdef ALTQ | |||||
if (s->qid) { | |||||
pd.act.pqid = s->pqid; | |||||
pd.act.qid = s->qid; | |||||
} | |||||
#endif | |||||
} else { | |||||
pf_scrub_ip6(&m, r->scrub_flags, r->min_ttl, r->set_tos); | |||||
if (r->rtableid >= 0) | if (r->rtableid >= 0) | ||||
M_SETFIB(m, r->rtableid); | M_SETFIB(m, r->rtableid); | ||||
#ifdef ALTQ | |||||
if (r->qid) { | |||||
pd.act.pqid = r->pqid; | |||||
pd.act.qid = r->qid; | |||||
} | |||||
#endif | |||||
} | |||||
if (r->scrub_flags & PFSTATE_SETPRIO) { | if (r->scrub_flags & PFSTATE_SETPRIO) { | ||||
if (pd.tos & IPTOS_LOWDELAY) | if (pd.tos & IPTOS_LOWDELAY) | ||||
pqid = 1; | pqid = 1; | ||||
if (vlan_set_pcp(m, r->set_prio[pqid])) { | if (vlan_set_pcp(m, r->set_prio[pqid])) { | ||||
action = PF_DROP; | action = PF_DROP; | ||||
REASON_SET(&reason, PFRES_MEMORY); | REASON_SET(&reason, PFRES_MEMORY); | ||||
log = 1; | log = PF_LOG_FORCE; | ||||
DPFPRINTF(PF_DEBUG_MISC, | DPFPRINTF(PF_DEBUG_MISC, | ||||
("pf: failed to allocate 802.1q mtag\n")); | ("pf: failed to allocate 802.1q mtag\n")); | ||||
} | } | ||||
} | } | ||||
#ifdef ALTQ | #ifdef ALTQ | ||||
if (s && s->qid) { | |||||
pd.act.pqid = s->pqid; | |||||
pd.act.qid = s->qid; | |||||
} else if (r->qid) { | |||||
pd.act.pqid = r->pqid; | |||||
pd.act.qid = r->qid; | |||||
} | |||||
if (action == PF_PASS && pd.act.qid) { | if (action == PF_PASS && pd.act.qid) { | ||||
if (pd.pf_mtag == NULL && | if (pd.pf_mtag == NULL && | ||||
((pd.pf_mtag = pf_get_mtag(m)) == NULL)) { | ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) { | ||||
action = PF_DROP; | action = PF_DROP; | ||||
REASON_SET(&reason, PFRES_MEMORY); | REASON_SET(&reason, PFRES_MEMORY); | ||||
} else { | } else { | ||||
if (s != NULL) | if (s != NULL) | ||||
pd.pf_mtag->qid_hash = pf_state_hash(s); | pd.pf_mtag->qid_hash = pf_state_hash(s); | ||||
Show All 14 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_krule *lr; | struct pf_krule *lr; | ||||
struct pf_krule_item *ri; | |||||
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, | |||||
&pd, (s == NULL)); | if (log & PF_LOG_FORCE || lr->log & PF_LOG_ALL) | ||||
PFLOG_PACKET(kif, m, AF_INET6, dir, reason, lr, a, | |||||
ruleset, &pd, (s == NULL)); | |||||
if (s) { | |||||
SLIST_FOREACH(ri, &s->match_rules, entry) | |||||
if (ri->r->log & PF_LOG_ALL) | |||||
PFLOG_PACKET(kif, m, AF_INET6, dir, | |||||
reason, ri->r, a, ruleset, &pd, 0); | |||||
} | |||||
} | } | ||||
pf_counter_u64_critical_enter(); | pf_counter_u64_critical_enter(); | ||||
pf_counter_u64_add_protected(&kif->pfik_bytes[1][dir == PF_OUT][action != PF_PASS], | pf_counter_u64_add_protected(&kif->pfik_bytes[1][dir == PF_OUT][action != PF_PASS], | ||||
pd.tot_len); | pd.tot_len); | ||||
pf_counter_u64_add_protected(&kif->pfik_packets[1][dir == PF_OUT][action != PF_PASS], | pf_counter_u64_add_protected(&kif->pfik_packets[1][dir == PF_OUT][action != PF_PASS], | ||||
1); | 1); | ||||
▲ Show 20 Lines • Show All 87 Lines • Show Last 20 Lines |
M_NOWAIT can fail allocation. We need to deal with the ri == NULL case here.