aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c63
1 files changed, 6 insertions, 57 deletions
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 521ddca876f8..dcf6010f68d9 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -64,82 +64,31 @@ static int ipv6_print_tuple(struct seq_file *s,
64 tuple->src.u3.ip6, tuple->dst.u3.ip6); 64 tuple->src.u3.ip6, tuple->dst.u3.ip6);
65} 65}
66 66
67/*
68 * Based on ipv6_skip_exthdr() in net/ipv6/exthdr.c
69 *
70 * This function parses (probably truncated) exthdr set "hdr"
71 * of length "len". "nexthdrp" initially points to some place,
72 * where type of the first header can be found.
73 *
74 * It skips all well-known exthdrs, and returns pointer to the start
75 * of unparsable area i.e. the first header with unknown type.
76 * if success, *nexthdr is updated by type/protocol of this header.
77 *
78 * NOTES: - it may return pointer pointing beyond end of packet,
79 * if the last recognized header is truncated in the middle.
80 * - if packet is truncated, so that all parsed headers are skipped,
81 * it returns -1.
82 * - if packet is fragmented, return pointer of the fragment header.
83 * - ESP is unparsable for now and considered like
84 * normal payload protocol.
85 * - Note also special handling of AUTH header. Thanks to IPsec wizards.
86 */
87
88static int nf_ct_ipv6_skip_exthdr(const struct sk_buff *skb, int start,
89 u8 *nexthdrp, int len)
90{
91 u8 nexthdr = *nexthdrp;
92
93 while (ipv6_ext_hdr(nexthdr)) {
94 struct ipv6_opt_hdr hdr;
95 int hdrlen;
96
97 if (len < (int)sizeof(struct ipv6_opt_hdr))
98 return -1;
99 if (nexthdr == NEXTHDR_NONE)
100 break;
101 if (nexthdr == NEXTHDR_FRAGMENT)
102 break;
103 if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
104 BUG();
105 if (nexthdr == NEXTHDR_AUTH)
106 hdrlen = (hdr.hdrlen+2)<<2;
107 else
108 hdrlen = ipv6_optlen(&hdr);
109
110 nexthdr = hdr.nexthdr;
111 len -= hdrlen;
112 start += hdrlen;
113 }
114
115 *nexthdrp = nexthdr;
116 return start;
117}
118
119static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff, 67static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
120 unsigned int *dataoff, u_int8_t *protonum) 68 unsigned int *dataoff, u_int8_t *protonum)
121{ 69{
122 unsigned int extoff = nhoff + sizeof(struct ipv6hdr); 70 unsigned int extoff = nhoff + sizeof(struct ipv6hdr);
123 unsigned char pnum; 71 __be16 frag_off;
124 int protoff; 72 int protoff;
73 u8 nexthdr;
125 74
126 if (skb_copy_bits(skb, nhoff + offsetof(struct ipv6hdr, nexthdr), 75 if (skb_copy_bits(skb, nhoff + offsetof(struct ipv6hdr, nexthdr),
127 &pnum, sizeof(pnum)) != 0) { 76 &nexthdr, sizeof(nexthdr)) != 0) {
128 pr_debug("ip6_conntrack_core: can't get nexthdr\n"); 77 pr_debug("ip6_conntrack_core: can't get nexthdr\n");
129 return -NF_ACCEPT; 78 return -NF_ACCEPT;
130 } 79 }
131 protoff = nf_ct_ipv6_skip_exthdr(skb, extoff, &pnum, skb->len - extoff); 80 protoff = ipv6_skip_exthdr(skb, extoff, &nexthdr, &frag_off);
132 /* 81 /*
133 * (protoff == skb->len) mean that the packet doesn't have no data 82 * (protoff == skb->len) mean that the packet doesn't have no data
134 * except of IPv6 & ext headers. but it's tracked anyway. - YK 83 * except of IPv6 & ext headers. but it's tracked anyway. - YK
135 */ 84 */
136 if ((protoff < 0) || (protoff > skb->len)) { 85 if (protoff < 0 || (frag_off & htons(~0x7)) != 0) {
137 pr_debug("ip6_conntrack_core: can't find proto in pkt\n"); 86 pr_debug("ip6_conntrack_core: can't find proto in pkt\n");
138 return -NF_ACCEPT; 87 return -NF_ACCEPT;
139 } 88 }
140 89
141 *dataoff = protoff; 90 *dataoff = protoff;
142 *protonum = pnum; 91 *protonum = nexthdr;
143 return NF_ACCEPT; 92 return NF_ACCEPT;
144} 93}
145 94