The branch stable/13 has been updated by kp:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=540c8cd7adc5b30fa11ea47822c333863b0663b5

commit 540c8cd7adc5b30fa11ea47822c333863b0663b5
Author:     Kristof Provost <[email protected]>
AuthorDate: 2023-05-31 14:03:39 +0000
Commit:     Kristof Provost <[email protected]>
CommitDate: 2023-08-11 12:13:09 +0000

    pf: support 'return' for SCTP
    
    Send an SCTP Abort message if we're refusing a connection, just like we
    send a RST for TCP.
    
    MFC after:      3 weeks
    Sponsored by:   Orange Business Services
    Differential Revision:  https://reviews.freebsd.org/D40864
    
    (cherry picked from commit d1bc1e9e1ae04016e16154884914d839566ebaec)
---
 sys/net/pfvar.h          |   1 +
 sys/netpfil/pf/pf.c      | 117 +++++++++++++++++++++++++++++++++++++++++++++++
 sys/netpfil/pf/pf_norm.c |   2 +
 3 files changed, 120 insertions(+)

diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 55bd25a3d29e..99c504d99368 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1330,6 +1330,7 @@ struct pf_pdesc {
 #define PFDESC_SCTP_DATA       0x0040
 #define PFDESC_SCTP_OTHER      0x0080
        u_int16_t        sctp_flags;
+       u_int32_t        sctp_initiate_tag;
 };
 #endif
 
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 16e0ee762f6a..ce5e1b813bb2 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -2911,6 +2911,120 @@ pf_build_tcp(const struct pf_krule *r, sa_family_t af,
        return (m);
 }
 
+static void
+pf_send_sctp_abort(sa_family_t af, struct pf_pdesc *pd,
+    uint8_t ttl, int rtableid)
+{
+       struct mbuf             *m;
+#ifdef INET
+       struct ip               *h = NULL;
+#endif /* INET */
+#ifdef INET6
+       struct ip6_hdr          *h6 = NULL;
+#endif /* INET6 */
+       struct sctphdr          *hdr;
+       struct sctp_chunkhdr    *chunk;
+       struct pf_send_entry    *pfse;
+       int                      off = 0;
+
+       MPASS(af == pd->af);
+
+       m = m_gethdr(M_NOWAIT, MT_DATA);
+       if (m == NULL)
+               return;
+
+       m->m_data += max_linkhdr;
+       m->m_flags |= M_SKIP_FIREWALL;
+       /* 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;
+
+       /* IPv4|6 header */
+       switch (af) {
+#ifdef INET
+       case AF_INET:
+               bzero(m->m_data, sizeof(struct ip) + sizeof(*hdr) + 
sizeof(*chunk));
+
+               h = mtod(m, struct ip *);
+
+               /* IP header fields included in the TCP checksum */
+
+               h->ip_p = IPPROTO_SCTP;
+               h->ip_len = htons(sizeof(*h) + sizeof(*hdr) + sizeof(*chunk));
+               h->ip_ttl = ttl ? ttl : V_ip_defttl;
+               h->ip_src = pd->dst->v4;
+               h->ip_dst = pd->src->v4;
+
+               off += sizeof(struct ip);
+               break;
+#endif /* INET */
+#ifdef INET6
+       case AF_INET6:
+               bzero(m->m_data, sizeof(struct ip6_hdr) + sizeof(*hdr) + 
sizeof(*chunk));
+
+               h6 = mtod(m, struct ip6_hdr *);
+
+               /* IP header fields included in the TCP checksum */
+               h6->ip6_vfc |= IPV6_VERSION;
+               h6->ip6_nxt = IPPROTO_SCTP;
+               h6->ip6_plen = htons(sizeof(*h6) + sizeof(*hdr) + 
sizeof(*chunk));
+               h6->ip6_hlim = ttl ? ttl : V_ip6_defhlim;
+               memcpy(&h6->ip6_src, &pd->dst->v6, sizeof(struct in6_addr));
+               memcpy(&h6->ip6_dst, &pd->src->v6, sizeof(struct in6_addr));
+
+               off += sizeof(struct ip6_hdr);
+               break;
+#endif /* INET6 */
+       }
+
+       /* SCTP header */
+       hdr = mtodo(m, off);
+
+       hdr->src_port = pd->hdr.sctp.dest_port;
+       hdr->dest_port = pd->hdr.sctp.src_port;
+       hdr->v_tag = pd->sctp_initiate_tag;
+       hdr->checksum = 0;
+
+       /* Abort chunk. */
+       off += sizeof(struct sctphdr);
+       chunk = mtodo(m, off);
+
+       chunk->chunk_type = SCTP_ABORT_ASSOCIATION;
+       chunk->chunk_length = htons(sizeof(*chunk));
+
+       /* SCTP checksum */
+       off += sizeof(*chunk);
+       m->m_pkthdr.len = m->m_len = off;
+
+       pf_sctp_checksum(m, off - sizeof(*hdr) - sizeof(*chunk));;
+
+       if (rtableid >= 0)
+               M_SETFIB(m, rtableid);
+
+       /* Allocate outgoing queue entry, mbuf and mbuf tag. */
+       pfse = malloc(sizeof(*pfse), M_PFTEMP, M_NOWAIT);
+       if (pfse == NULL) {
+               m_freem(m);
+               return;
+       }
+
+       switch (af) {
+#ifdef INET
+       case AF_INET:
+               pfse->pfse_type = PFSE_IP;
+               break;
+#endif /* INET */
+#ifdef INET6
+       case AF_INET6:
+               pfse->pfse_type = PFSE_IP6;
+               break;
+#endif /* INET6 */
+       }
+
+       pfse->pfse_m = m;
+       pf_send(pfse);
+}
+
 void
 pf_send_tcp(const struct pf_krule *r, sa_family_t af,
     const struct pf_addr *saddr, const struct pf_addr *daddr,
@@ -3014,6 +3128,9 @@ pf_return(struct pf_krule *r, struct pf_krule *nr, struct 
pf_pdesc *pd,
                                ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0,
                                r->return_ttl, 1, 0);
                }
+       } else if (pd->proto == IPPROTO_SCTP &&
+           (r->rule_flag & PFRULE_RETURN)) {
+               pf_send_sctp_abort(af, pd, r->return_ttl, r->rtableid);
        } else if (pd->proto != IPPROTO_ICMP && af == AF_INET &&
                r->return_icmp)
                pf_send_icmp(m, r->return_icmp >> 8,
diff --git a/sys/netpfil/pf/pf_norm.c b/sys/netpfil/pf/pf_norm.c
index 06aa577b45a7..ac02896d0762 100644
--- a/sys/netpfil/pf/pf_norm.c
+++ b/sys/netpfil/pf/pf_norm.c
@@ -2037,6 +2037,8 @@ pf_scan_sctp(struct mbuf *m, int ipoff, int off, struct 
pf_pdesc *pd)
                        if (pd->hdr.sctp.v_tag != 0)
                                return (PF_DROP);
 
+                       pd->sctp_initiate_tag = init.init.initiate_tag;
+
                        pd->sctp_flags |= PFDESC_SCTP_INIT;
                        break;
                }

Reply via email to