Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/pf/pf.c
Show First 20 Lines • Show All 2,201 Lines • ▼ Show 20 Lines | pf_intr(void *v) | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
STAILQ_FOREACH_SAFE(pfse, &queue, pfse_next, next) { | STAILQ_FOREACH_SAFE(pfse, &queue, pfse_next, next) { | ||||
switch (pfse->pfse_type) { | switch (pfse->pfse_type) { | ||||
#ifdef INET | #ifdef INET | ||||
case PFSE_IP: { | case PFSE_IP: { | ||||
if (pf_isforlocal(pfse->pfse_m, AF_INET)) { | if (pf_isforlocal(pfse->pfse_m, AF_INET)) { | ||||
KASSERT(pfse->pfse_m->m_pkthdr.rcvif == V_loif, | |||||
("%s: rcvif != loif", __func__)); | |||||
pfse->pfse_m->m_flags |= M_SKIP_FIREWALL; | pfse->pfse_m->m_flags |= M_SKIP_FIREWALL; | ||||
kp: The IPv4 stack doesn't check for it, but we may as well set M_LOOP here too, to be consistent… | |||||
pfse->pfse_m->m_pkthdr.csum_flags |= | pfse->pfse_m->m_pkthdr.csum_flags |= | ||||
CSUM_IP_VALID | CSUM_IP_CHECKED; | CSUM_IP_VALID | CSUM_IP_CHECKED; | ||||
ip_input(pfse->pfse_m); | ip_input(pfse->pfse_m); | ||||
} else { | } else { | ||||
ip_output(pfse->pfse_m, NULL, NULL, 0, NULL, | ip_output(pfse->pfse_m, NULL, NULL, 0, NULL, | ||||
NULL); | NULL); | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
case PFSE_ICMP: | case PFSE_ICMP: | ||||
icmp_error(pfse->pfse_m, pfse->icmpopts.type, | icmp_error(pfse->pfse_m, pfse->icmpopts.type, | ||||
pfse->icmpopts.code, 0, pfse->icmpopts.mtu); | pfse->icmpopts.code, 0, pfse->icmpopts.mtu); | ||||
break; | break; | ||||
#endif /* INET */ | #endif /* INET */ | ||||
#ifdef INET6 | #ifdef INET6 | ||||
case PFSE_IP6: | case PFSE_IP6: | ||||
if (pf_isforlocal(pfse->pfse_m, AF_INET6)) { | if (pf_isforlocal(pfse->pfse_m, AF_INET6)) { | ||||
pfse->pfse_m->m_flags |= M_SKIP_FIREWALL; | KASSERT(pfse->pfse_m->m_pkthdr.rcvif == V_loif, | ||||
("%s: rcvif != loif", __func__)); | |||||
pfse->pfse_m->m_flags |= M_SKIP_FIREWALL | | |||||
M_LOOP; | |||||
Not Done Inline ActionsI wonder if we should MPASS(pfse->pfse_m->m_pkthdr.rcvif == V_loif); here. kp: I wonder if we should `MPASS(pfse->pfse_m->m_pkthdr.rcvif == V_loif);` here. | |||||
ip6_input(pfse->pfse_m); | ip6_input(pfse->pfse_m); | ||||
} else { | } else { | ||||
ip6_output(pfse->pfse_m, NULL, NULL, 0, NULL, | ip6_output(pfse->pfse_m, NULL, NULL, 0, NULL, | ||||
NULL, NULL); | NULL, NULL); | ||||
} | } | ||||
break; | break; | ||||
case PFSE_ICMP6: | case PFSE_ICMP6: | ||||
icmp6_error(pfse->pfse_m, pfse->icmpopts.type, | icmp6_error(pfse->pfse_m, pfse->icmpopts.type, | ||||
▲ Show 20 Lines • Show All 332 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, s->key[PF_SK_WIRE]->af, | pf_send_tcp(s->rule, 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, true, s->tag, 0, s->act.rtableid); | TH_RST|TH_ACK, 0, 0, 0, M_SKIP_FIREWALL, s->tag, 0, | ||||
s->act.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 20 Lines • Show All 743 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 tcp_flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, | u_int8_t tcp_flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, | ||||
bool skip_firewall, u_int16_t mtag_tag, u_int16_t mtag_flags, int rtableid) | int mbuf_flags, u_int16_t mtag_tag, u_int16_t mtag_flags, 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 29 Lines | |||||
#ifdef MAC | #ifdef MAC | ||||
mac_netinet_firewall_send(m); | mac_netinet_firewall_send(m); | ||||
#endif | #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 (skip_firewall) | m->m_flags |= mbuf_flags; | ||||
m->m_flags |= M_SKIP_FIREWALL; | |||||
pf_mtag->tag = mtag_tag; | pf_mtag->tag = mtag_tag; | ||||
pf_mtag->flags = mtag_flags; | pf_mtag->flags = mtag_flags; | ||||
if (rtableid >= 0) | if (rtableid >= 0) | ||||
M_SETFIB(m, rtableid); | M_SETFIB(m, rtableid); | ||||
#ifdef ALTQ | #ifdef ALTQ | ||||
if (r != NULL && r->qid) { | if (r != NULL && r->qid) { | ||||
▲ Show 20 Lines • Show All 200 Lines • ▼ Show 20 Lines | #endif /* INET6 */ | ||||
pf_send(pfse); | pf_send(pfse); | ||||
} | } | ||||
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 tcp_flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, | u_int8_t tcp_flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, | ||||
bool skip_firewall, u_int16_t mtag_tag, u_int16_t mtag_flags, int rtableid) | int mbuf_flags, u_int16_t mtag_tag, u_int16_t mtag_flags, 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, tcp_flags, | m = pf_build_tcp(r, af, saddr, daddr, sport, dport, seq, ack, tcp_flags, | ||||
win, mss, ttl, skip_firewall, mtag_tag, mtag_flags, rtableid); | win, mss, ttl, mbuf_flags, mtag_tag, mtag_flags, 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 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | if (pd->proto == IPPROTO_TCP && | ||||
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, pd->af, pd->dst, | pf_send_tcp(r, pd->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, true, 0, 0, rtableid); | r->return_ttl, M_SKIP_FIREWALL, 0, 0, rtableid); | ||||
} | } | ||||
} else if (pd->proto == IPPROTO_SCTP && | } else if (pd->proto == IPPROTO_SCTP && | ||||
(r->rule_flag & PFRULE_RETURN)) { | (r->rule_flag & PFRULE_RETURN)) { | ||||
pf_send_sctp_abort(pd->af, pd, r->return_ttl, rtableid); | pf_send_sctp_abort(pd->af, pd, r->return_ttl, rtableid); | ||||
} else if (pd->proto != IPPROTO_ICMP && pd->af == AF_INET && | } else if (pd->proto != IPPROTO_ICMP && pd->af == AF_INET && | ||||
r->return_icmp) | r->return_icmp) | ||||
pf_send_icmp(pd->m, r->return_icmp >> 8, | pf_send_icmp(pd->m, r->return_icmp >> 8, | ||||
r->return_icmp & 255, pd->af, r, rtableid); | r->return_icmp & 255, pd->af, r, rtableid); | ||||
▲ Show 20 Lines • Show All 1,848 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(pd->m); | int rtid = M_GETFIB(pd->m); | ||||
mss = pf_get_mss(pd); | mss = pf_get_mss(pd); | ||||
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, true, 0, 0, | TH_SYN|TH_ACK, 0, s->src.mss, 0, M_SKIP_FIREWALL, 0, 0, | ||||
pd->act.rtableid); | pd->act.rtableid); | ||||
REASON_SET(&reason, PFRES_SYNPROXY); | REASON_SET(&reason, PFRES_SYNPROXY); | ||||
return (PF_SYNPROXY_DROP); | return (PF_SYNPROXY_DROP); | ||||
} | } | ||||
s->udp_mapping = udp_mapping; | s->udp_mapping = udp_mapping; | ||||
return (PF_PASS); | return (PF_PASS); | ||||
▲ Show 20 Lines • Show All 344 Lines • ▼ Show 20 Lines | if (SEQ_GEQ(src->seqhi, data_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, pd->af, | pf_send_tcp((*state)->rule, 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->return_ttl, true, 0, 0, | (*state)->rule->return_ttl, M_SKIP_FIREWALL, | ||||
(*state)->act.rtableid); | 0, 0, (*state)->act.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, pd->af, pd->dst, | pf_send_tcp((*state)->rule, 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, true, 0, 0, | TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, | ||||
(*state)->act.rtableid); | M_SKIP_FIREWALL, 0, 0, (*state)->act.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, pd->af, | pf_send_tcp((*state)->rule, 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, false, (*state)->tag, 0, | (*state)->src.mss, 0, | ||||
(*state)->act.rtableid); | (*state)->orig_kif->pfik_ifp == V_loif ? M_LOOP : 0, | ||||
(*state)->tag, 0, (*state)->act.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, pd->af, pd->dst, | pf_send_tcp((*state)->rule, 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, false, | TH_ACK, (*state)->src.max_win, 0, 0, 0, | ||||
(*state)->tag, 0, (*state)->act.rtableid); | (*state)->tag, 0, (*state)->act.rtableid); | ||||
pf_send_tcp((*state)->rule, pd->af, | pf_send_tcp((*state)->rule, 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, true, 0, 0, | TH_ACK, (*state)->dst.max_win, 0, 0, | ||||
(*state)->act.rtableid); | M_SKIP_FIREWALL, 0, 0, (*state)->act.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 3,325 Lines • Show Last 20 Lines |
The IPv4 stack doesn't check for it, but we may as well set M_LOOP here too, to be consistent with the IPv6 case.