diff options
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 63 |
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 | |||
88 | static 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 | |||
119 | static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff, | 67 | static 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 | ||