diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -2491,12 +2491,12 @@ struct mbuf *pf_build_tcp(const struct pf_krule *, sa_family_t, const struct pf_addr *, const struct pf_addr *, u_int16_t, u_int16_t, u_int32_t, u_int32_t, - u_int8_t, u_int16_t, u_int16_t, u_int8_t, bool, + u_int8_t, u_int16_t, u_int16_t, u_int8_t, int, u_int16_t, u_int16_t, int); void pf_send_tcp(const struct pf_krule *, sa_family_t, const struct pf_addr *, const struct pf_addr *, u_int16_t, u_int16_t, u_int32_t, u_int32_t, - u_int8_t, u_int16_t, u_int16_t, u_int8_t, bool, + u_int8_t, u_int16_t, u_int16_t, u_int8_t, int, u_int16_t, u_int16_t, int); void pf_syncookies_init(void); diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -2207,6 +2207,9 @@ #ifdef INET case PFSE_IP: { 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_pkthdr.csum_flags |= CSUM_IP_VALID | CSUM_IP_CHECKED; @@ -2225,7 +2228,11 @@ #ifdef INET6 case PFSE_IP6: 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; ip6_input(pfse->pfse_m); } else { ip6_output(pfse->pfse_m, NULL, NULL, 0, NULL, @@ -2574,7 +2581,8 @@ s->key[PF_SK_WIRE]->port[1], s->key[PF_SK_WIRE]->port[0], 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); @@ -3334,7 +3342,7 @@ const struct pf_addr *saddr, const struct pf_addr *daddr, u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack, u_int8_t 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; int len, tlen; @@ -3380,8 +3388,7 @@ m_freem(m); return (NULL); } - if (skip_firewall) - m->m_flags |= M_SKIP_FIREWALL; + m->m_flags |= mbuf_flags; pf_mtag->tag = mtag_tag; pf_mtag->flags = mtag_flags; @@ -3598,13 +3605,13 @@ const struct pf_addr *saddr, const struct pf_addr *daddr, u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack, u_int8_t 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 mbuf *m; 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) return; @@ -3672,7 +3679,7 @@ pf_send_tcp(r, pd->af, pd->dst, pd->src, th->th_dport, th->th_sport, ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0, - r->return_ttl, true, 0, 0, rtableid); + r->return_ttl, M_SKIP_FIREWALL, 0, 0, rtableid); } } else if (pd->proto == IPPROTO_SCTP && (r->rule_flag & PFRULE_RETURN)) { @@ -5537,7 +5544,7 @@ s->src.mss = mss; 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_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); REASON_SET(&reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); @@ -5898,8 +5905,8 @@ pd->dst, pd->src, th->th_dport, th->th_sport, ntohl(th->th_ack), 0, TH_RST, 0, 0, - (*state)->rule->return_ttl, true, 0, 0, - (*state)->act.rtableid); + (*state)->rule->return_ttl, M_SKIP_FIREWALL, + 0, 0, (*state)->act.rtableid); src->seqlo = 0; src->seqhi = 1; src->max_win = 1; @@ -6035,8 +6042,8 @@ pf_send_tcp((*state)->rule, pd->af, pd->dst, pd->src, th->th_dport, th->th_sport, (*state)->src.seqhi, ntohl(th->th_seq) + 1, - TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, true, 0, 0, - (*state)->act.rtableid); + TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, + M_SKIP_FIREWALL, 0, 0, (*state)->act.rtableid); REASON_SET(reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); } else if ((th->th_flags & (TH_ACK|TH_RST|TH_FIN)) != TH_ACK || @@ -6067,8 +6074,9 @@ &sk->addr[pd->sidx], &sk->addr[pd->didx], sk->port[pd->sidx], sk->port[pd->didx], (*state)->dst.seqhi, 0, TH_SYN, 0, - (*state)->src.mss, 0, false, (*state)->tag, 0, - (*state)->act.rtableid); + (*state)->src.mss, 0, + (*state)->orig_kif->pfik_ifp == V_loif ? M_LOOP : 0, + (*state)->tag, 0, (*state)->act.rtableid); REASON_SET(reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); } else if (((th->th_flags & (TH_SYN|TH_ACK)) != @@ -6082,14 +6090,14 @@ pf_send_tcp((*state)->rule, pd->af, pd->dst, pd->src, th->th_dport, th->th_sport, ntohl(th->th_ack), ntohl(th->th_seq) + 1, - TH_ACK, (*state)->src.max_win, 0, 0, false, + TH_ACK, (*state)->src.max_win, 0, 0, 0, (*state)->tag, 0, (*state)->act.rtableid); pf_send_tcp((*state)->rule, pd->af, &sk->addr[pd->sidx], &sk->addr[pd->didx], sk->port[pd->sidx], sk->port[pd->didx], (*state)->src.seqhi + 1, (*state)->src.seqlo + 1, - TH_ACK, (*state)->dst.max_win, 0, 0, true, 0, 0, - (*state)->act.rtableid); + TH_ACK, (*state)->dst.max_win, 0, 0, + M_SKIP_FIREWALL, 0, 0, (*state)->act.rtableid); (*state)->src.seqdiff = (*state)->dst.seqhi - (*state)->src.seqlo; (*state)->dst.seqdiff = (*state)->src.seqhi - diff --git a/sys/netpfil/pf/pf_syncookies.c b/sys/netpfil/pf/pf_syncookies.c --- a/sys/netpfil/pf/pf_syncookies.c +++ b/sys/netpfil/pf/pf_syncookies.c @@ -298,7 +298,8 @@ iss = pf_syncookie_generate(pd, mss); pf_send_tcp(NULL, pd->af, pd->dst, pd->src, *pd->dport, *pd->sport, iss, ntohl(pd->hdr.tcp.th_seq) + 1, TH_SYN|TH_ACK, 0, mss, - 0, true, 0, 0, pd->act.rtableid); + 0, M_SKIP_FIREWALL | (pd->m->m_flags & M_LOOP), 0, 0, + pd->act.rtableid); counter_u64_add(V_pf_status.lcounters[KLCNT_SYNCOOKIES_SENT], 1); /* XXX Maybe only in adaptive mode? */ atomic_add_64(&V_pf_status.syncookies_inflight[V_pf_syncookie_status.oddeven], @@ -515,6 +516,7 @@ wscale = pf_syncookie_wstab[cookie.flags.wscale_idx]; return (pf_build_tcp(NULL, pd->af, pd->src, pd->dst, *pd->sport, - *pd->dport, seq, 0, TH_SYN, wscale, mss, pd->ttl, false, 0, - PF_MTAG_FLAG_SYNCOOKIE_RECREATED, pd->act.rtableid)); + *pd->dport, seq, 0, TH_SYN, wscale, mss, pd->ttl, + (pd->m->m_flags & M_LOOP), 0, PF_MTAG_FLAG_SYNCOOKIE_RECREATED, + pd->act.rtableid)); } diff --git a/tests/sys/netpfil/pf/syncookie.sh b/tests/sys/netpfil/pf/syncookie.sh --- a/tests/sys/netpfil/pf/syncookie.sh +++ b/tests/sys/netpfil/pf/syncookie.sh @@ -233,6 +233,90 @@ pft_cleanup } +loopback_test() +{ + local addr port + + addr=$1 + port=$2 + + # syncookies don't work without state tracking enabled. + atf_check -e ignore pfctl -e + atf_check pfctl -f - <<__EOF__ +set syncookies always +pass all keep state +__EOF__ + + # Try to transmit data over a loopback connection. + cat <<__EOF__ >in +Creativity, no. +__EOF__ + nc -l $addr $port >out & + + atf_check nc -N $addr $port < in + + atf_check -o file:in cat out + + atf_check -e ignore pfctl -d +} + +atf_test_case "loopback" "cleanup" +loopback_head() +{ + atf_set descr 'Make sure that loopback v4 TCP connections work with syncookies on' + atf_set require.user root +} + +loopback_body() +{ + local epair + + pft_init + + atf_check ifconfig lo0 127.0.0.1/8 + atf_check ifconfig lo0 up + + loopback_test 127.0.0.1 8080 + + epair=$(vnet_mkepair) + atf_check ifconfig ${epair}a inet 192.0.2.1/24 + + loopback_test 192.0.2.1 8081 +} + +loopback_cleanup() +{ + pft_cleanup +} + +atf_test_case "loopback_v6" "cleanup" +loopback_v6_head() +{ + atf_set descr 'Make sure that loopback v6 TCP connections work with syncookies on' + atf_set require.user root +} + +loopback_v6_body() +{ + local epair + + pft_init + + atf_check ifconfig lo0 up + + loopback_test ::1 8080 + + epair=$(vnet_mkepair) + atf_check ifconfig ${epair}a inet6 2001:db8::1/64 + + loopback_test 2001:db8::1 8081 +} + +loopback_v6_cleanup() +{ + pft_cleanup +} + atf_test_case "nostate" "cleanup" nostate_head() { @@ -483,6 +567,8 @@ atf_add_test_case "basic_v6" atf_add_test_case "forward" atf_add_test_case "forward_v6" + atf_add_test_case "loopback" + atf_add_test_case "loopback_v6" atf_add_test_case "nostate" atf_add_test_case "nostate_v6" atf_add_test_case "adaptive"