Commit be18dd53 authored by Yasuyuki Kozakai's avatar Yasuyuki Kozakai Committed by Stephen Hemminger

[NETFILTER]: Fix ipv6 TCP/UDP matching wrt. extension headers

parent a0d49aa6
...@@ -46,3 +46,4 @@ EXPORT_SYMBOL(ip6_append_data); ...@@ -46,3 +46,4 @@ EXPORT_SYMBOL(ip6_append_data);
EXPORT_SYMBOL(ip6_flush_pending_frames); EXPORT_SYMBOL(ip6_flush_pending_frames);
EXPORT_SYMBOL(ip6_push_pending_frames); EXPORT_SYMBOL(ip6_push_pending_frames);
EXPORT_SYMBOL(ipv6_push_nfrag_opts); EXPORT_SYMBOL(ipv6_push_nfrag_opts);
EXPORT_SYMBOL(ipv6_skip_exthdr);
...@@ -1570,8 +1570,10 @@ tcp_match(const struct sk_buff *skb, ...@@ -1570,8 +1570,10 @@ tcp_match(const struct sk_buff *skb,
u_int16_t datalen, u_int16_t datalen,
int *hotdrop) int *hotdrop)
{ {
const struct tcphdr *tcp = hdr; const struct tcphdr *tcp;
const struct ip6t_tcp *tcpinfo = matchinfo; const struct ip6t_tcp *tcpinfo = matchinfo;
int tcpoff;
u8 nexthdr = skb->nh.ipv6h->nexthdr;
/* To quote Alan: /* To quote Alan:
...@@ -1592,6 +1594,24 @@ tcp_match(const struct sk_buff *skb, ...@@ -1592,6 +1594,24 @@ tcp_match(const struct sk_buff *skb,
return 0; return 0;
} }
tcpoff = (u8*)(skb->nh.ipv6h + 1) - skb->data;
tcpoff = ipv6_skip_exthdr(skb, tcpoff, &nexthdr, skb->len - tcpoff);
if (tcpoff < 0 || tcpoff > skb->len) {
duprintf("tcp_match: cannot skip exthdr. Dropping.\n");
*hotdrop = 1;
return 0;
} else if (nexthdr == IPPROTO_FRAGMENT)
return 0;
else if (nexthdr != IPPROTO_TCP ||
skb->len - tcpoff < sizeof(struct tcphdr)) {
/* cannot be occured */
duprintf("tcp_match: cannot get TCP header. Dropping.\n");
*hotdrop = 1;
return 0;
}
tcp = (struct tcphdr *)(skb->data + tcpoff);
/* FIXME: Try tcp doff >> packet len against various stacks --RR */ /* FIXME: Try tcp doff >> packet len against various stacks --RR */
#define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg)) #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
...@@ -1642,8 +1662,10 @@ udp_match(const struct sk_buff *skb, ...@@ -1642,8 +1662,10 @@ udp_match(const struct sk_buff *skb,
u_int16_t datalen, u_int16_t datalen,
int *hotdrop) int *hotdrop)
{ {
const struct udphdr *udp = hdr; const struct udphdr *udp;
const struct ip6t_udp *udpinfo = matchinfo; const struct ip6t_udp *udpinfo = matchinfo;
int udpoff;
u8 nexthdr = skb->nh.ipv6h->nexthdr;
if (offset == 0 && datalen < sizeof(struct udphdr)) { if (offset == 0 && datalen < sizeof(struct udphdr)) {
/* We've been asked to examine this packet, and we /* We've been asked to examine this packet, and we
...@@ -1653,6 +1675,23 @@ udp_match(const struct sk_buff *skb, ...@@ -1653,6 +1675,23 @@ udp_match(const struct sk_buff *skb,
return 0; return 0;
} }
udpoff = (u8*)(skb->nh.ipv6h + 1) - skb->data;
udpoff = ipv6_skip_exthdr(skb, udpoff, &nexthdr, skb->len - udpoff);
if (udpoff < 0 || udpoff > skb->len) {
duprintf("udp_match: cannot skip exthdr. Dropping.\n");
*hotdrop = 1;
return 0;
} else if (nexthdr == IPPROTO_FRAGMENT)
return 0;
else if (nexthdr != IPPROTO_UDP ||
skb->len - udpoff < sizeof(struct udphdr)) {
duprintf("udp_match: cannot get UDP header. Dropping.\n");
*hotdrop = 1;
return 0;
}
udp = (struct udphdr *)(skb->data + udpoff);
/* Must not be a fragment. */ /* Must not be a fragment. */
return !offset return !offset
&& port_match(udpinfo->spts[0], udpinfo->spts[1], && port_match(udpinfo->spts[0], udpinfo->spts[1],
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment