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 @@ -180,6 +180,8 @@ VNET_DEFINE(int, altqs_inactive_open); VNET_DEFINE(u_int32_t, ticket_pabuf); +static const int PF_HDR_LIMIT = 20; /* arbitrary limit */ + VNET_DEFINE(SHA512_CTX, pf_tcp_secret_ctx); #define V_pf_tcp_secret_ctx VNET(pf_tcp_secret_ctx) VNET_DEFINE(u_char, pf_tcp_secret[16]); @@ -9698,6 +9700,7 @@ { struct ah ext; u_int32_t hlen, end; + int hdr_cnt; hlen = h->ip_hl << 2; if (hlen < sizeof(struct ip) || hlen > ntohs(h->ip_len)) { @@ -9710,7 +9713,7 @@ /* stop walking over non initial fragments */ if ((h->ip_off & htons(IP_OFFMASK)) != 0) return (PF_PASS); - for (;;) { + for (hdr_cnt = 0; hdr_cnt < PF_HDR_LIMIT; hdr_cnt++) { switch (pd->proto) { case IPPROTO_AH: /* fragments may be short */ @@ -9729,6 +9732,9 @@ return (PF_PASS); } } + DPFPRINTF(PF_DEBUG_MISC, ("IPv4 nested authentication header limit")); + REASON_SET(reason, PFRES_IPOPTIONS); + return (PF_DROP); } #ifdef INET6 @@ -9801,14 +9807,13 @@ struct ip6_ext ext; struct ip6_rthdr rthdr; uint32_t end; - int hdr_cnt = 0, fraghdr_cnt = 0, rthdr_cnt = 0; + int hdr_cnt, fraghdr_cnt = 0, rthdr_cnt = 0; pd->off += sizeof(struct ip6_hdr); end = pd->off + ntohs(h->ip6_plen); pd->fragoff = pd->extoff = pd->jumbolen = 0; pd->proto = h->ip6_nxt; - for (;;) { - hdr_cnt++; + for (hdr_cnt = 0; hdr_cnt < PF_HDR_LIMIT; hdr_cnt++) { switch (pd->proto) { case IPPROTO_FRAGMENT: if (fraghdr_cnt++) { @@ -9863,7 +9868,7 @@ /* FALLTHROUGH */ case IPPROTO_HOPOPTS: /* RFC2460 4.1: Hop-by-Hop only after IPv6 header */ - if (pd->proto == IPPROTO_HOPOPTS && hdr_cnt > 1) { + if (pd->proto == IPPROTO_HOPOPTS && hdr_cnt > 0) { DPFPRINTF(PF_DEBUG_MISC, ("IPv6 hopopts not first")); REASON_SET(reason, PFRES_IPOPTIONS); return (PF_DROP); @@ -9922,6 +9927,9 @@ return (PF_PASS); } } + DPFPRINTF(PF_DEBUG_MISC, ("IPv6 nested extension header limit")); + REASON_SET(reason, PFRES_IPOPTIONS); + return (PF_DROP); } #endif /* INET6 */