aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/netfilter/nf_conntrack.h4
-rw-r--r--net/ipv4/netfilter/nf_conntrack_proto_icmp.c32
-rw-r--r--net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c42
-rw-r--r--net/netfilter/nf_conntrack_core.c30
4 files changed, 49 insertions, 59 deletions
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index d4f02eb0c66c..810020ec345d 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -186,6 +186,10 @@ extern void nf_conntrack_hash_insert(struct nf_conn *ct);
186 186
187extern void nf_conntrack_flush(void); 187extern void nf_conntrack_flush(void);
188 188
189extern int nf_ct_get_tuplepr(const struct sk_buff *skb,
190 unsigned int nhoff,
191 u_int16_t l3num,
192 struct nf_conntrack_tuple *tuple);
189extern int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, 193extern int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse,
190 const struct nf_conntrack_tuple *orig); 194 const struct nf_conntrack_tuple *orig);
191 195
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index 0fe8fb0466ef..b8b79992797e 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -136,40 +136,22 @@ icmp_error_message(struct sk_buff *skb,
136 unsigned int hooknum) 136 unsigned int hooknum)
137{ 137{
138 struct nf_conntrack_tuple innertuple, origtuple; 138 struct nf_conntrack_tuple innertuple, origtuple;
139 struct {
140 struct icmphdr icmp;
141 struct iphdr ip;
142 } _in, *inside;
143 struct nf_conntrack_l4proto *innerproto; 139 struct nf_conntrack_l4proto *innerproto;
144 struct nf_conntrack_tuple_hash *h; 140 struct nf_conntrack_tuple_hash *h;
145 int dataoff;
146 141
147 NF_CT_ASSERT(skb->nfct == NULL); 142 NF_CT_ASSERT(skb->nfct == NULL);
148 143
149 /* Not enough header? */ 144 /* Are they talking about one of our connections? */
150 inside = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_in), &_in); 145 if (!nf_ct_get_tuplepr(skb,
151 if (inside == NULL) 146 skb_network_offset(skb) + ip_hdrlen(skb)
152 return -NF_ACCEPT; 147 + sizeof(struct icmphdr),
153 148 PF_INET, &origtuple)) {
154 /* Ignore ICMP's containing fragments (shouldn't happen) */ 149 pr_debug("icmp_error_message: failed to get tuple\n");
155 if (inside->ip.frag_off & htons(IP_OFFSET)) {
156 pr_debug("icmp_error_message: fragment of proto %u\n",
157 inside->ip.protocol);
158 return -NF_ACCEPT; 150 return -NF_ACCEPT;
159 } 151 }
160 152
161 /* rcu_read_lock()ed by nf_hook_slow */ 153 /* rcu_read_lock()ed by nf_hook_slow */
162 innerproto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol); 154 innerproto = __nf_ct_l4proto_find(PF_INET, origtuple.dst.protonum);
163
164 dataoff = ip_hdrlen(skb) + sizeof(inside->icmp);
165 /* Are they talking about one of our connections? */
166 if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET,
167 inside->ip.protocol, &origtuple,
168 &nf_conntrack_l3proto_ipv4, innerproto)) {
169 pr_debug("icmp_error_message: ! get_tuple p=%u",
170 inside->ip.protocol);
171 return -NF_ACCEPT;
172 }
173 155
174 /* Ordinarily, we'd expect the inverted tupleproto, but it's 156 /* Ordinarily, we'd expect the inverted tupleproto, but it's
175 been preserved inside the ICMP. */ 157 been preserved inside the ICMP. */
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index 9defc7e14554..0fca7e8abeb7 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -136,49 +136,23 @@ icmpv6_error_message(struct sk_buff *skb,
136{ 136{
137 struct nf_conntrack_tuple intuple, origtuple; 137 struct nf_conntrack_tuple intuple, origtuple;
138 struct nf_conntrack_tuple_hash *h; 138 struct nf_conntrack_tuple_hash *h;
139 struct icmp6hdr _hdr, *hp;
140 unsigned int inip6off;
141 struct nf_conntrack_l4proto *inproto; 139 struct nf_conntrack_l4proto *inproto;
142 u_int8_t inprotonum;
143 unsigned int inprotoff;
144 140
145 NF_CT_ASSERT(skb->nfct == NULL); 141 NF_CT_ASSERT(skb->nfct == NULL);
146 142
147 hp = skb_header_pointer(skb, icmp6off, sizeof(_hdr), &_hdr);
148 if (hp == NULL) {
149 pr_debug("icmpv6_error: Can't get ICMPv6 hdr.\n");
150 return -NF_ACCEPT;
151 }
152
153 inip6off = icmp6off + sizeof(_hdr);
154 if (skb_copy_bits(skb, inip6off+offsetof(struct ipv6hdr, nexthdr),
155 &inprotonum, sizeof(inprotonum)) != 0) {
156 pr_debug("icmpv6_error: Can't get nexthdr in inner IPv6 "
157 "header.\n");
158 return -NF_ACCEPT;
159 }
160 inprotoff = nf_ct_ipv6_skip_exthdr(skb,
161 inip6off + sizeof(struct ipv6hdr),
162 &inprotonum,
163 skb->len - inip6off
164 - sizeof(struct ipv6hdr));
165
166 if ((inprotoff > skb->len) || (inprotonum == NEXTHDR_FRAGMENT)) {
167 pr_debug("icmpv6_error: Can't get protocol header in ICMPv6 "
168 "payload.\n");
169 return -NF_ACCEPT;
170 }
171
172 /* rcu_read_lock()ed by nf_hook_slow */
173 inproto = __nf_ct_l4proto_find(PF_INET6, inprotonum);
174
175 /* Are they talking about one of our connections? */ 143 /* Are they talking about one of our connections? */
176 if (!nf_ct_get_tuple(skb, inip6off, inprotoff, PF_INET6, inprotonum, 144 if (!nf_ct_get_tuplepr(skb,
177 &origtuple, &nf_conntrack_l3proto_ipv6, inproto)) { 145 skb_network_offset(skb)
146 + sizeof(struct ipv6hdr)
147 + sizeof(struct icmp6hdr),
148 PF_INET6, &origtuple)) {
178 pr_debug("icmpv6_error: Can't get tuple\n"); 149 pr_debug("icmpv6_error: Can't get tuple\n");
179 return -NF_ACCEPT; 150 return -NF_ACCEPT;
180 } 151 }
181 152
153 /* rcu_read_lock()ed by nf_hook_slow */
154 inproto = __nf_ct_l4proto_find(PF_INET6, origtuple.dst.protonum);
155
182 /* Ordinarily, we'd expect the inverted tupleproto, but it's 156 /* Ordinarily, we'd expect the inverted tupleproto, but it's
183 been preserved inside the ICMP. */ 157 been preserved inside the ICMP. */
184 if (!nf_ct_invert_tuple(&intuple, &origtuple, 158 if (!nf_ct_invert_tuple(&intuple, &origtuple,
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 5b194e3c4e25..8cce814f6bee 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -113,6 +113,36 @@ nf_ct_get_tuple(const struct sk_buff *skb,
113} 113}
114EXPORT_SYMBOL_GPL(nf_ct_get_tuple); 114EXPORT_SYMBOL_GPL(nf_ct_get_tuple);
115 115
116int nf_ct_get_tuplepr(const struct sk_buff *skb,
117 unsigned int nhoff,
118 u_int16_t l3num,
119 struct nf_conntrack_tuple *tuple)
120{
121 struct nf_conntrack_l3proto *l3proto;
122 struct nf_conntrack_l4proto *l4proto;
123 unsigned int protoff;
124 u_int8_t protonum;
125 int ret;
126
127 rcu_read_lock();
128
129 l3proto = __nf_ct_l3proto_find(l3num);
130 ret = l3proto->get_l4proto(skb, nhoff, &protoff, &protonum);
131 if (ret != NF_ACCEPT) {
132 rcu_read_unlock();
133 return 0;
134 }
135
136 l4proto = __nf_ct_l4proto_find(l3num, protonum);
137
138 ret = nf_ct_get_tuple(skb, nhoff, protoff, l3num, protonum, tuple,
139 l3proto, l4proto);
140
141 rcu_read_unlock();
142 return ret;
143}
144EXPORT_SYMBOL_GPL(nf_ct_get_tuplepr);
145
116int 146int
117nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse, 147nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
118 const struct nf_conntrack_tuple *orig, 148 const struct nf_conntrack_tuple *orig,