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 | ||
