Skip to content

Commit 75f2811

Browse files
committed
ipv6: Add fragment reporting to ipv6_skip_exthdr().
While parsing through IPv6 extension headers, fragment headers are skipped making them invisible to the caller. This reports the fragment offset of the last header in order to make it possible to determine whether the packet is fragmented and, if so whether it is a first or last fragment. Signed-off-by: Jesse Gross <[email protected]>
1 parent 396cf94 commit 75f2811

File tree

17 files changed

+45
-19
lines changed

17 files changed

+45
-19
lines changed

include/net/ipv6.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ extern void ipv6_push_frag_opts(struct sk_buff *skb,
558558
u8 *proto);
559559

560560
extern int ipv6_skip_exthdr(const struct sk_buff *, int start,
561-
u8 *nexthdrp);
561+
u8 *nexthdrp, __be16 *frag_offp);
562562

563563
extern int ipv6_ext_hdr(u8 nexthdr);
564564

net/bridge/br_multicast.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1458,6 +1458,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
14581458
const struct ipv6hdr *ip6h;
14591459
u8 icmp6_type;
14601460
u8 nexthdr;
1461+
__be16 frag_off;
14611462
unsigned len;
14621463
int offset;
14631464
int err;
@@ -1483,7 +1484,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
14831484
return -EINVAL;
14841485

14851486
nexthdr = ip6h->nexthdr;
1486-
offset = ipv6_skip_exthdr(skb, sizeof(*ip6h), &nexthdr);
1487+
offset = ipv6_skip_exthdr(skb, sizeof(*ip6h), &nexthdr, &frag_off);
14871488

14881489
if (offset < 0 || nexthdr != IPPROTO_ICMPV6)
14891490
return 0;

net/bridge/netfilter/ebt_ip6.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,10 @@ ebt_ip6_mt(const struct sk_buff *skb, struct xt_action_param *par)
5555
return false;
5656
if (info->bitmask & EBT_IP6_PROTO) {
5757
uint8_t nexthdr = ih6->nexthdr;
58+
__be16 frag_off;
5859
int offset_ph;
5960

60-
offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr);
61+
offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr, &frag_off);
6162
if (offset_ph == -1)
6263
return false;
6364
if (FWINV(info->protocol != nexthdr, EBT_IP6_PROTO))

net/bridge/netfilter/ebt_log.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ ebt_log_packet(u_int8_t pf, unsigned int hooknum,
113113
const struct ipv6hdr *ih;
114114
struct ipv6hdr _iph;
115115
uint8_t nexthdr;
116+
__be16 frag_off;
116117
int offset_ph;
117118

118119
ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
@@ -123,7 +124,7 @@ ebt_log_packet(u_int8_t pf, unsigned int hooknum,
123124
printk(" IPv6 SRC=%pI6 IPv6 DST=%pI6, IPv6 priority=0x%01X, Next Header=%d",
124125
&ih->saddr, &ih->daddr, ih->priority, ih->nexthdr);
125126
nexthdr = ih->nexthdr;
126-
offset_ph = ipv6_skip_exthdr(skb, sizeof(_iph), &nexthdr);
127+
offset_ph = ipv6_skip_exthdr(skb, sizeof(_iph), &nexthdr, &frag_off);
127128
if (offset_ph == -1)
128129
goto out;
129130
print_ports(skb, nexthdr, offset_ph);

net/ipv6/exthdrs_core.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,23 @@ int ipv6_ext_hdr(u8 nexthdr)
5757
* it returns NULL.
5858
* - First fragment header is skipped, not-first ones
5959
* are considered as unparsable.
60+
* - Reports the offset field of the final fragment header so it is
61+
* possible to tell whether this is a first fragment, later fragment,
62+
* or not fragmented.
6063
* - ESP is unparsable for now and considered like
6164
* normal payload protocol.
6265
* - Note also special handling of AUTH header. Thanks to IPsec wizards.
6366
*
6467
* --ANK (980726)
6568
*/
6669

67-
int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp)
70+
int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp,
71+
__be16 *frag_offp)
6872
{
6973
u8 nexthdr = *nexthdrp;
7074

75+
*frag_offp = 0;
76+
7177
while (ipv6_ext_hdr(nexthdr)) {
7278
struct ipv6_opt_hdr _hdr, *hp;
7379
int hdrlen;
@@ -87,7 +93,8 @@ int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp)
8793
if (fp == NULL)
8894
return -1;
8995

90-
if (ntohs(*fp) & ~0x7)
96+
*frag_offp = *fp;
97+
if (ntohs(*frag_offp) & ~0x7)
9198
break;
9299
hdrlen = 8;
93100
} else if (nexthdr == NEXTHDR_AUTH)

net/ipv6/icmp.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,12 @@ static int is_ineligible(struct sk_buff *skb)
135135
int ptr = (u8 *)(ipv6_hdr(skb) + 1) - skb->data;
136136
int len = skb->len - ptr;
137137
__u8 nexthdr = ipv6_hdr(skb)->nexthdr;
138+
__be16 frag_off;
138139

139140
if (len < 0)
140141
return 1;
141142

142-
ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr);
143+
ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, &frag_off);
143144
if (ptr < 0)
144145
return 0;
145146
if (nexthdr == IPPROTO_ICMPV6) {
@@ -596,14 +597,16 @@ static void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
596597
int inner_offset;
597598
int hash;
598599
u8 nexthdr;
600+
__be16 frag_off;
599601

600602
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
601603
return;
602604

603605
nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr;
604606
if (ipv6_ext_hdr(nexthdr)) {
605607
/* now skip over extension headers */
606-
inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr);
608+
inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
609+
&nexthdr, &frag_off);
607610
if (inner_offset<0)
608611
return;
609612
} else {

net/ipv6/ip6_input.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ int ip6_mc_input(struct sk_buff *skb)
280280
u8 *ptr = skb_network_header(skb) + opt->ra;
281281
struct icmp6hdr *icmp6;
282282
u8 nexthdr = hdr->nexthdr;
283+
__be16 frag_off;
283284
int offset;
284285

285286
/* Check if the value of Router Alert
@@ -293,7 +294,7 @@ int ip6_mc_input(struct sk_buff *skb)
293294
goto out;
294295
}
295296
offset = ipv6_skip_exthdr(skb, sizeof(*hdr),
296-
&nexthdr);
297+
&nexthdr, &frag_off);
297298
if (offset < 0)
298299
goto out;
299300

net/ipv6/ip6_output.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,10 +329,11 @@ static int ip6_forward_proxy_check(struct sk_buff *skb)
329329
{
330330
struct ipv6hdr *hdr = ipv6_hdr(skb);
331331
u8 nexthdr = hdr->nexthdr;
332+
__be16 frag_off;
332333
int offset;
333334

334335
if (ipv6_ext_hdr(nexthdr)) {
335-
offset = ipv6_skip_exthdr(skb, sizeof(*hdr), &nexthdr);
336+
offset = ipv6_skip_exthdr(skb, sizeof(*hdr), &nexthdr, &frag_off);
336337
if (offset < 0)
337338
return 0;
338339
} else

net/ipv6/netfilter/ip6t_REJECT.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
4949
const __u8 tclass = DEFAULT_TOS_VALUE;
5050
struct dst_entry *dst = NULL;
5151
u8 proto;
52+
__be16 frag_off;
5253
struct flowi6 fl6;
5354

5455
if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
@@ -58,7 +59,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
5859
}
5960

6061
proto = oip6h->nexthdr;
61-
tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto);
62+
tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto, &frag_off);
6263

6364
if ((tcphoff < 0) || (tcphoff > oldskb->len)) {
6465
pr_debug("Cannot get TCP header.\n");

net/netfilter/ipset/ip_set_getport.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,11 @@ ip_set_get_ip6_port(const struct sk_buff *skb, bool src,
116116
{
117117
int protoff;
118118
u8 nexthdr;
119+
__be16 frag_off;
119120

120121
nexthdr = ipv6_hdr(skb)->nexthdr;
121-
protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr);
122+
protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
123+
&frag_off);
122124
if (protoff < 0)
123125
return false;
124126

0 commit comments

Comments
 (0)