Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F109956244
D46931.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D46931.diff
View Options
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1612,9 +1612,9 @@
u_int16_t flags; /* Let SCRUB trigger behavior in
* state code. Easier than tags */
#define PFDESC_TCP_NORM 0x0001 /* TCP shall be statefully scrubbed */
-#define PFDESC_IP_REAS 0x0002 /* IP frags would've been reassembled */
u_int16_t virtual_proto;
#define PF_VPROTO_FRAGMENT 256
+ int extoff;
sa_family_t af;
u_int8_t proto;
u_int8_t tos;
@@ -2362,8 +2362,8 @@
#endif /* INET */
#ifdef INET6
-int pf_walk_header6(struct mbuf *, uint8_t *, int *, int *, uint32_t *,
- u_short *);
+int pf_walk_header6(struct mbuf *, struct ip6_hdr *, int *, int *, int *,
+ uint8_t *, uint32_t *, u_short *);
int pf_normalize_ip6(struct mbuf **, struct pfi_kkif *, int,
u_short *, struct pf_pdesc *);
void pf_poolmask(struct pf_addr *, struct pf_addr*,
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
@@ -7026,7 +7026,8 @@
#endif /* INET */
#ifdef INET6
struct ip6_hdr h2_6;
- int terminal = 0;
+ int fragoff2, extoff2;
+ u_int32_t jumbolen;
#endif /* INET6 */
int ipoff2 = 0;
int off2 = 0;
@@ -7078,47 +7079,16 @@
"(ip6)\n"));
return (PF_DROP);
}
- pd2.proto = h2_6.ip6_nxt;
+ off2 = ipoff2;
+ if (pf_walk_header6(m, &h2_6, &off2, &extoff2,
+ &fragoff2, &pd2.proto, &jumbolen,
+ reason) != PF_PASS)
+ return (PF_DROP);
+
pd2.src = (struct pf_addr *)&h2_6.ip6_src;
pd2.dst = (struct pf_addr *)&h2_6.ip6_dst;
pd2.ip_sum = NULL;
off2 = ipoff2 + sizeof(h2_6);
- do {
- switch (pd2.proto) {
- case IPPROTO_FRAGMENT:
- /*
- * ICMPv6 error messages for
- * non-first fragments
- */
- REASON_SET(reason, PFRES_FRAG);
- return (PF_DROP);
- case IPPROTO_AH:
- case IPPROTO_HOPOPTS:
- case IPPROTO_ROUTING:
- case IPPROTO_DSTOPTS: {
- /* get next header and header length */
- struct ip6_ext opt6;
-
- if (!pf_pull_hdr(m, off2, &opt6,
- sizeof(opt6), NULL, reason,
- pd2.af)) {
- DPFPRINTF(PF_DEBUG_MISC,
- ("pf: ICMPv6 short opt\n"));
- return (PF_DROP);
- }
- if (pd2.proto == IPPROTO_AH)
- off2 += (opt6.ip6e_len + 2) * 4;
- else
- off2 += (opt6.ip6e_len + 1) * 8;
- pd2.proto = opt6.ip6e_nxt;
- /* goto the next header */
- break;
- }
- default:
- terminal++;
- break;
- }
- } while (!terminal);
break;
#endif /* INET6 */
}
@@ -8537,28 +8507,44 @@
}
int
-pf_walk_header6(struct mbuf *m, uint8_t *nxt, int *off, int *extoff,
- uint32_t *jumbolen, u_short *reason)
+pf_walk_header6(struct mbuf *m, struct ip6_hdr *h, int *off, int *extoff,
+ int *fragoff, uint8_t *nxt, uint32_t *jumbolen, u_short *reason)
{
+ struct ip6_frag frag;
struct ip6_ext ext;
struct ip6_rthdr rthdr;
- struct ip6_hdr *h = mtod(m, struct ip6_hdr *);
int rthdr_cnt = 0;
+ *off += sizeof(struct ip6_hdr);
+ *extoff = *fragoff = 0;
*nxt = h->ip6_nxt;
- *off = sizeof(struct ip6_hdr);
- *extoff = 0;
*jumbolen = 0;
for (;;) {
switch (*nxt) {
case IPPROTO_FRAGMENT:
+ if (*fragoff != 0) {
+ DPFPRINTF(PF_DEBUG_MISC, ("IPv6 multiple fragment"));
+ REASON_SET(reason, PFRES_FRAG);
+ return (PF_DROP);
+ }
/* jumbo payload packets cannot be fragmented */
if (*jumbolen != 0) {
DPFPRINTF(PF_DEBUG_MISC, ("IPv6 fragmented jumbo"));
REASON_SET(reason, PFRES_FRAG);
return (PF_DROP);
}
- return (PF_PASS);
+ if (!pf_pull_hdr(m, *off, &frag, sizeof(frag), NULL,
+ reason, AF_INET6)) {
+ DPFPRINTF(PF_DEBUG_MISC, ("IPv6 short fragment"));
+ return (PF_DROP);
+ }
+ *fragoff = *off;
+ /* stop walking over non initial fragments */
+ if ((frag.ip6f_offlg & IP6F_OFF_MASK) != 0)
+ return (PF_PASS);
+ *off += sizeof(frag);
+ *nxt = frag.ip6f_nxt;
+ break;
case IPPROTO_ROUTING:
if (rthdr_cnt++) {
DPFPRINTF(PF_DEBUG_MISC, ("IPv6 multiple rthdr"));
@@ -8567,6 +8553,12 @@
}
if (!pf_pull_hdr(m, *off, &rthdr, sizeof(rthdr), NULL,
reason, AF_INET6)) {
+ /* fragments may be short */
+ if (*fragoff != 0) {
+ *off = *fragoff;
+ *nxt = IPPROTO_FRAGMENT;
+ return (PF_PASS);
+ }
DPFPRINTF(PF_DEBUG_MISC, ("IPv6 short rthdr"));
return (PF_DROP);
}
@@ -8581,11 +8573,19 @@
case IPPROTO_DSTOPTS:
if (!pf_pull_hdr(m, *off, &ext, sizeof(ext), NULL,
reason, AF_INET6)) {
+ /* fragments may be short */
+ if (*fragoff != 0) {
+ *off = *fragoff;
+ *nxt = IPPROTO_FRAGMENT;
+ return (PF_PASS);
+ }
DPFPRINTF(PF_DEBUG_MISC, ("IPv6 short exthdr"));
return (PF_DROP);
}
- *extoff = *off;
- if (*nxt == IPPROTO_HOPOPTS) {
+ /* reassembly needs the ext header before the frag */
+ if (*fragoff == 0)
+ *extoff = *off;
+ if (*nxt == IPPROTO_HOPOPTS && *fragoff == 0) {
if (pf_walk_option6(m, *off + sizeof(ext),
*off + (ext.ip6e_len + 1) * 8, jumbolen,
reason) != PF_PASS)
@@ -8603,6 +8603,20 @@
*off += (ext.ip6e_len + 1) * 8;
*nxt = ext.ip6e_nxt;
break;
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+ case IPPROTO_SCTP:
+ case IPPROTO_ICMPV6:
+ /* fragments may be short, ignore inner header then */
+ if (*fragoff != 0 && ntohs(h->ip6_plen) < *off +
+ (*nxt == IPPROTO_TCP ? sizeof(struct tcphdr) :
+ *nxt == IPPROTO_UDP ? sizeof(struct udphdr) :
+ *nxt == IPPROTO_SCTP ? sizeof(struct sctphdr) :
+ sizeof(struct icmp6_hdr))) {
+ *off = *fragoff;
+ *nxt = IPPROTO_FRAGMENT;
+ }
+ /* FALLTHROUGH */
default:
return (PF_PASS);
}
@@ -8705,7 +8719,7 @@
#ifdef INET6
case AF_INET6: {
struct ip6_hdr *h;
- int extoff;
+ int fragoff;
uint32_t jumbolen;
uint8_t nxt;
@@ -8719,8 +8733,10 @@
return (-1);
}
- if (pf_walk_header6(m, &nxt, off, &extoff, &jumbolen, reason)
- != PF_PASS) {
+ h = mtod(m, struct ip6_hdr *);
+ *off = 0;
+ if (pf_walk_header6(m, h, off, &pd->extoff, &fragoff, &nxt,
+ &jumbolen, reason) != PF_PASS) {
*action = PF_DROP;
return (-1);
}
@@ -8740,6 +8756,9 @@
pd->virtual_proto = pd->proto = h->ip6_nxt;
pd->act.rtableid = -1;
+ if (fragoff != 0)
+ pd->virtual_proto = PF_VPROTO_FRAGMENT;
+
/*
* we do not support jumbogram. if we keep going, zero ip6_plen
* will do something bad, so drop the packet for now.
@@ -8750,7 +8769,7 @@
}
/* We do IP header normalization and packet reassembly here */
- if (pf_normalize_ip6(m0, kif, *off, reason, pd) !=
+ if (pf_normalize_ip6(m0, kif, fragoff, reason, pd) !=
PF_PASS) {
*action = PF_DROP;
return (-1);
@@ -8769,14 +8788,17 @@
h = mtod(m, struct ip6_hdr *);
pd->virtual_proto = pd->proto = h->ip6_nxt;
- /* recalc offset, refetch header, then update pd */
- if (pf_walk_header6(m, &nxt, off, &extoff, &jumbolen, reason) !=
- PF_PASS) {
+ /* refetch header, recalc offset, then update pd */
+ h = mtod(m, struct ip6_hdr *);
+ *off = 0;
+
+ if (pf_walk_header6(m, h, off, &pd->extoff, &fragoff, &nxt,
+ &jumbolen, reason) != PF_PASS) {
*action = PF_DROP;
return (-1);
}
- if (pd->proto == IPPROTO_FRAGMENT) {
+ if (fragoff != 0) {
/*
* handle fragments that aren't reassembled by
* normalization
diff --git a/sys/netpfil/pf/pf_norm.c b/sys/netpfil/pf/pf_norm.c
--- a/sys/netpfil/pf/pf_norm.c
+++ b/sys/netpfil/pf/pf_norm.c
@@ -1215,20 +1215,12 @@
struct mbuf *m;
struct pf_krule *r;
struct ip6_frag frag;
- int extoff;
- uint32_t jumbolen;
- uint8_t nxt;
bool scrub_compat;
PF_RULES_RASSERT();
-again:
m = *m0;
- if (pf_walk_header6(m, &nxt, &off, &extoff, &jumbolen, reason)
- != PF_PASS)
- return (PF_DROP);
-
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr);
/*
* Check if there are any scrub rules, matching or not.
@@ -1280,20 +1272,14 @@
/* Offset now points to data portion. */
off += sizeof(frag);
- if (nxt == IPPROTO_FRAGMENT) {
- if (pd->flags & PFDESC_IP_REAS)
- return (PF_DROP);
-
+ if (pd->virtual_proto == PF_VPROTO_FRAGMENT) {
/* Returns PF_DROP or *m0 is NULL or completely reassembled
* mbuf. */
- if (pf_reassemble6(m0, &frag, off, extoff, reason) != PF_PASS)
+ if (pf_reassemble6(m0, &frag, off, pd->extoff, reason) != PF_PASS)
return (PF_DROP);
-
- pd->flags |= PFDESC_IP_REAS;
m = *m0;
if (m == NULL)
return (PF_DROP);
- goto again;
}
return (PF_PASS);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Feb 12, 5:18 PM (20 h, 23 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16613629
Default Alt Text
D46931.diff (8 KB)
Attached To
Mode
D46931: pf: remove the last hand-rolled IPv6 extension header loop
Attached
Detach File
Event Timeline
Log In to Comment