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 @@ -444,6 +444,20 @@ VNET_DEFINE(uint32_t, pf_hashseed); #define V_pf_hashseed VNET(pf_hashseed) +#if defined(SCTP) || defined(SCTP_SUPPORT) +static void +pf_sctp_checksum(struct mbuf *m, int off) +{ + uint32_t sum = 0; + + /* Zero out the checksum, to enable recalculation. */ + m_copyback(m, off + offsetof(struct sctphdr, checksum), + sizeof(sum), (caddr_t)&sum); + + sctp_delayed_cksum(m, off); +} +#endif + int pf_addr_cmp(struct pf_addr *a, struct pf_addr *b, sa_family_t af) { @@ -517,6 +531,32 @@ m_copyback(m, off, sizeof(*uh), (caddr_t)uh); break; } +#if defined(SCTP) || defined(SCTP_SUPPORT) + case IPPROTO_SCTP: { + struct sctphdr *sh = &pd->hdr.sctp; + uint16_t checksum = 0; + bool rewrite = false; + + if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af)) { + pf_change_ap(m, pd->src, &sh->src_port, pd->ip_sum, + &checksum, &nk->addr[pd->sidx], + nk->port[pd->sidx], 1, pd->af); + rewrite = true; + } + if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af)) { + pf_change_ap(m, pd->dst, &sh->dest_port, pd->ip_sum, + &checksum, &nk->addr[pd->didx], + nk->port[pd->didx], 1, pd->af); + rewrite = true; + } + + if (rewrite) { + m_copyback(m, off, sizeof(*sh), (caddr_t)sh); + pf_sctp_checksum(m, off); + } + break; + } +#endif case IPPROTO_ICMP: { struct icmp *ih = &pd->hdr.icmp; @@ -4453,6 +4493,39 @@ } rewrite++; break; +#if defined(SCTP) || defined(SCTP_SUPPORT) + case IPPROTO_SCTP: { + uint16_t checksum = 0; + bool changed = false; + + if (PF_ANEQ(saddr, &nk->addr[pd->sidx], af) || + nk->port[pd->sidx] != sport) { + pf_change_ap(m, saddr, &pd->hdr.sctp.src_port, + pd->ip_sum, &checksum, + &nk->addr[pd->sidx], + nk->port[pd->sidx], 1, af); + sport = pd->hdr.sctp.src_port; + pd->sport = &pd->hdr.sctp.src_port; + changed = true; + } + if (PF_ANEQ(daddr, &nk->addr[pd->didx], af) || + nk->port[pd->didx] != dport) { + pf_change_ap(m, daddr, &pd->hdr.sctp.dest_port, + pd->ip_sum, &checksum, + &nk->addr[pd->didx], + nk->port[pd->didx], 1, af); + dport = pd->hdr.sctp.dest_port; + pd->dport = &pd->hdr.sctp.dest_port; + changed = true; + } + + if (changed) { + pf_sctp_checksum(m, off); + rewrite++; + } + break; + } +#endif #ifdef INET case IPPROTO_ICMP: nk->port[0] = nk->port[1]; @@ -5790,6 +5863,7 @@ return (PF_PASS); } +#if defined(SCTP) || defined(SCTP_SUPPORT) static int pf_test_state_sctp(struct pf_kstate **state, int direction, struct pfi_kkif *kif, struct mbuf *m, int off, void *h, @@ -5847,8 +5921,37 @@ (*state)->expire = time_uptime; + /* translate source/destination address, if necessary */ + if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { + uint16_t checksum = 0; + struct pf_state_key *nk = (*state)->key[pd->didx]; + bool changed = false; + + if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af) || + nk->port[pd->sidx] != pd->hdr.sctp.src_port) { + pf_change_ap(m, pd->src, &pd->hdr.sctp.src_port, + pd->ip_sum, &checksum, &nk->addr[pd->sidx], + nk->port[pd->sidx], 1, pd->af); + changed = true; + } + + if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af) || + nk->port[pd->didx] != pd->hdr.sctp.dest_port) { + pf_change_ap(m, pd->dst, &pd->hdr.sctp.dest_port, + pd->ip_sum, &checksum, &nk->addr[pd->didx], + nk->port[pd->didx], 1, pd->af); + changed = true; + } + + if (changed) { + m_copyback(m, off, sizeof(pd->hdr.sctp), (caddr_t)&pd->hdr.sctp); + pf_sctp_checksum(m, off); + } + } + return (PF_PASS); } +#endif static int pf_test_state_icmp(struct pf_kstate **state, int direction, struct pfi_kkif *kif, @@ -7575,6 +7678,7 @@ break; } +#if defined(SCTP) || defined(SCTP_SUPPORT) case IPPROTO_SCTP: { if (!pf_pull_hdr(m, off, &pd.hdr.sctp, sizeof(pd.hdr.sctp), &action, &reason, AF_INET)) { @@ -7606,6 +7710,7 @@ } break; } +#endif case IPPROTO_ICMP: { if (!pf_pull_hdr(m, off, &pd.hdr.icmp, ICMP_MINLEN, @@ -8165,6 +8270,7 @@ break; } +#if defined(SCTP) || defined(SCTP_SUPPORT) case IPPROTO_SCTP: { if (!pf_pull_hdr(m, off, &pd.hdr.sctp, sizeof(pd.hdr.sctp), &action, &reason, AF_INET6)) { @@ -8196,6 +8302,7 @@ } break; } +#endif case IPPROTO_ICMP: { action = PF_DROP;