aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristof Provost <kp@FreeBSD.org>2021-09-01 07:54:55 +0000
committerKristof Provost <kp@FreeBSD.org>2021-09-17 08:44:05 +0000
commit21d8ee0cd3bfa1d20c903cfde12053c360d41ef4 (patch)
treea1a4d1beb2a08fefcfea8ffcc28a0ccf86342bc6
parent3c1c3728f32cc71a3694f13be0610db5ff88519c (diff)
downloadsrc-21d8ee0cd3bfa1d20c903cfde12053c360d41ef4.tar.gz
src-21d8ee0cd3bfa1d20c903cfde12053c360d41ef4.zip
pf: fix synproxy to local
When we're synproxy-ing a connection that's going to us (as opposed to a forwarded one) we wound up trying to send out the pf-generated tcp packets through pf_intr(), which called ip(6)_output(). That doesn't work all that well for packets that are destined for us, so in that case we must call ip(6)_input() instead. MFC after: 1 week Sponsored by: Modirum MDPay Differential Revision: https://reviews.freebsd.org/D31853 (cherry picked from commit 0a51d74c3ab8e7ee8771cc3ee78ffba831c953ef)
-rw-r--r--sys/netpfil/pf/pf.c62
1 files changed, 57 insertions, 5 deletions
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index ce94c71fb49e..0722a864a574 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -1482,6 +1482,42 @@ pf_send(struct pf_send_entry *pfse)
swi_sched(V_pf_swi_cookie, 0);
}
+static bool
+pf_isforlocal(struct mbuf *m, int af)
+{
+ switch (af) {
+ case AF_INET: {
+ struct rm_priotracker in_ifa_tracker;
+ struct ip *ip;
+ struct in_ifaddr *ia = NULL;
+
+ ip = mtod(m, struct ip *);
+ IN_IFADDR_RLOCK(&in_ifa_tracker);
+ LIST_FOREACH(ia, INADDR_HASH(ip->ip_dst.s_addr), ia_hash) {
+ if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) {
+ IN_IFADDR_RUNLOCK(&in_ifa_tracker);
+ return (true);
+ }
+ }
+ IN_IFADDR_RUNLOCK(&in_ifa_tracker);
+ break;
+ }
+ case AF_INET6: {
+ struct ip6_hdr *ip6;
+ struct in6_ifaddr *ia;
+ ip6 = mtod(m, struct ip6_hdr *);
+ ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */);
+ if (ia == NULL)
+ return (false);
+ return (! (ia->ia6_flags & IN6_IFF_NOTREADY));
+ }
+ default:
+ panic("Unsupported af %d", af);
+ }
+
+ return (false);
+}
+
void
pf_intr(void *v)
{
@@ -1498,9 +1534,18 @@ pf_intr(void *v)
STAILQ_FOREACH_SAFE(pfse, &queue, pfse_next, next) {
switch (pfse->pfse_type) {
#ifdef INET
- case PFSE_IP:
- ip_output(pfse->pfse_m, NULL, NULL, 0, NULL, NULL);
+ case PFSE_IP: {
+ if (pf_isforlocal(pfse->pfse_m, AF_INET)) {
+ pfse->pfse_m->m_flags |= M_SKIP_FIREWALL;
+ pfse->pfse_m->m_pkthdr.csum_flags |=
+ CSUM_IP_VALID | CSUM_IP_CHECKED;
+ ip_input(pfse->pfse_m);
+ } else {
+ ip_output(pfse->pfse_m, NULL, NULL, 0, NULL,
+ NULL);
+ }
break;
+ }
case PFSE_ICMP:
icmp_error(pfse->pfse_m, pfse->icmpopts.type,
pfse->icmpopts.code, 0, pfse->icmpopts.mtu);
@@ -1508,8 +1553,13 @@ pf_intr(void *v)
#endif /* INET */
#ifdef INET6
case PFSE_IP6:
- ip6_output(pfse->pfse_m, NULL, NULL, 0, NULL, NULL,
- NULL);
+ if (pf_isforlocal(pfse->pfse_m, AF_INET6)) {
+ pfse->pfse_m->m_flags |= M_SKIP_FIREWALL;
+ ip6_input(pfse->pfse_m);
+ } else {
+ ip6_output(pfse->pfse_m, NULL, NULL, 0, NULL,
+ NULL, NULL);
+ }
break;
case PFSE_ICMP6:
icmp6_error(pfse->pfse_m, pfse->icmpopts.type,
@@ -2657,7 +2707,9 @@ pf_build_tcp(const struct pf_krule *r, sa_family_t af,
#endif /* ALTQ */
m->m_data += max_linkhdr;
m->m_pkthdr.len = m->m_len = len;
- m->m_pkthdr.rcvif = NULL;
+ /* The rest of the stack assumes a rcvif, so provide one.
+ * This is a locally generated packet, so .. close enough. */
+ m->m_pkthdr.rcvif = V_loif;
bzero(m->m_data, len);
switch (af) {
#ifdef INET