aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2015-04-02 08:28:30 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2015-04-08 10:47:49 -0400
commitd64d80a2cde94f3e89caebd27240be419fec5b81 (patch)
treead0b515bfbf7f37185776c384f952cc7ee7f64ae /net/netfilter
parent0b67c43ce36a9964f1d5e3f973ee19eefd3f9f8f (diff)
netfilter: x_tables: don't extract flow keys on early demuxed sks in socket match
Currently in xt_socket, we take advantage of early demuxed sockets since commit 00028aa37098 ("netfilter: xt_socket: use IP early demux") in order to avoid a second socket lookup in the fast path, but we only make partial use of this: We still unnecessarily parse headers, extract proto, {s,d}addr and {s,d}ports from the skb data, accessing possible conntrack information, etc even though we were not even calling into the socket lookup via xt_socket_get_sock_{v4,v6}() due to skb->sk hit, meaning those cycles can be spared. After this patch, we only proceed the slower, manual lookup path when we have a skb->sk miss, thus time to match verdict for early demuxed sockets will improve further, which might be i.e. interesting for use cases such as mentioned in 681f130f39e1 ("netfilter: xt_socket: add XT_SOCKET_NOWILDCARD flag"). Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/xt_socket.c95
1 files changed, 50 insertions, 45 deletions
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c
index 895534e87a47..e092cb046326 100644
--- a/net/netfilter/xt_socket.c
+++ b/net/netfilter/xt_socket.c
@@ -143,13 +143,10 @@ static bool xt_socket_sk_is_transparent(struct sock *sk)
143 } 143 }
144} 144}
145 145
146static bool 146static struct sock *xt_socket_lookup_slow_v4(const struct sk_buff *skb,
147socket_match(const struct sk_buff *skb, struct xt_action_param *par, 147 const struct net_device *indev)
148 const struct xt_socket_mtinfo1 *info)
149{ 148{
150 const struct iphdr *iph = ip_hdr(skb); 149 const struct iphdr *iph = ip_hdr(skb);
151 struct udphdr _hdr, *hp = NULL;
152 struct sock *sk = skb->sk;
153 __be32 uninitialized_var(daddr), uninitialized_var(saddr); 150 __be32 uninitialized_var(daddr), uninitialized_var(saddr);
154 __be16 uninitialized_var(dport), uninitialized_var(sport); 151 __be16 uninitialized_var(dport), uninitialized_var(sport);
155 u8 uninitialized_var(protocol); 152 u8 uninitialized_var(protocol);
@@ -159,10 +156,12 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
159#endif 156#endif
160 157
161 if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_TCP) { 158 if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_TCP) {
159 struct udphdr _hdr, *hp;
160
162 hp = skb_header_pointer(skb, ip_hdrlen(skb), 161 hp = skb_header_pointer(skb, ip_hdrlen(skb),
163 sizeof(_hdr), &_hdr); 162 sizeof(_hdr), &_hdr);
164 if (hp == NULL) 163 if (hp == NULL)
165 return false; 164 return NULL;
166 165
167 protocol = iph->protocol; 166 protocol = iph->protocol;
168 saddr = iph->saddr; 167 saddr = iph->saddr;
@@ -172,16 +171,17 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
172 171
173 } else if (iph->protocol == IPPROTO_ICMP) { 172 } else if (iph->protocol == IPPROTO_ICMP) {
174 if (extract_icmp4_fields(skb, &protocol, &saddr, &daddr, 173 if (extract_icmp4_fields(skb, &protocol, &saddr, &daddr,
175 &sport, &dport)) 174 &sport, &dport))
176 return false; 175 return NULL;
177 } else { 176 } else {
178 return false; 177 return NULL;
179 } 178 }
180 179
181#ifdef XT_SOCKET_HAVE_CONNTRACK 180#ifdef XT_SOCKET_HAVE_CONNTRACK
182 /* Do the lookup with the original socket address in case this is a 181 /* Do the lookup with the original socket address in
183 * reply packet of an established SNAT-ted connection. */ 182 * case this is a reply packet of an established
184 183 * SNAT-ted connection.
184 */
185 ct = nf_ct_get(skb, &ctinfo); 185 ct = nf_ct_get(skb, &ctinfo);
186 if (ct && !nf_ct_is_untracked(ct) && 186 if (ct && !nf_ct_is_untracked(ct) &&
187 ((iph->protocol != IPPROTO_ICMP && 187 ((iph->protocol != IPPROTO_ICMP &&
@@ -197,10 +197,18 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
197 } 197 }
198#endif 198#endif
199 199
200 return xt_socket_get_sock_v4(dev_net(skb->dev), protocol, saddr, daddr,
201 sport, dport, indev);
202}
203
204static bool
205socket_match(const struct sk_buff *skb, struct xt_action_param *par,
206 const struct xt_socket_mtinfo1 *info)
207{
208 struct sock *sk = skb->sk;
209
200 if (!sk) 210 if (!sk)
201 sk = xt_socket_get_sock_v4(dev_net(skb->dev), protocol, 211 sk = xt_socket_lookup_slow_v4(skb, par->in);
202 saddr, daddr, sport, dport,
203 par->in);
204 if (sk) { 212 if (sk) {
205 bool wildcard; 213 bool wildcard;
206 bool transparent = true; 214 bool transparent = true;
@@ -225,12 +233,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
225 sk = NULL; 233 sk = NULL;
226 } 234 }
227 235
228 pr_debug("proto %hhu %pI4:%hu -> %pI4:%hu (orig %pI4:%hu) sock %p\n", 236 return sk != NULL;
229 protocol, &saddr, ntohs(sport),
230 &daddr, ntohs(dport),
231 &iph->daddr, hp ? ntohs(hp->dest) : 0, sk);
232
233 return (sk != NULL);
234} 237}
235 238
236static bool 239static bool
@@ -327,28 +330,26 @@ xt_socket_get_sock_v6(struct net *net, const u8 protocol,
327 return NULL; 330 return NULL;
328} 331}
329 332
330static bool 333static struct sock *xt_socket_lookup_slow_v6(const struct sk_buff *skb,
331socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par) 334 const struct net_device *indev)
332{ 335{
333 struct ipv6hdr ipv6_var, *iph = ipv6_hdr(skb);
334 struct udphdr _hdr, *hp = NULL;
335 struct sock *sk = skb->sk;
336 const struct in6_addr *daddr = NULL, *saddr = NULL;
337 __be16 uninitialized_var(dport), uninitialized_var(sport); 336 __be16 uninitialized_var(dport), uninitialized_var(sport);
338 int thoff = 0, uninitialized_var(tproto); 337 const struct in6_addr *daddr = NULL, *saddr = NULL;
339 const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo; 338 struct ipv6hdr *iph = ipv6_hdr(skb);
339 int thoff = 0, tproto;
340 340
341 tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL); 341 tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
342 if (tproto < 0) { 342 if (tproto < 0) {
343 pr_debug("unable to find transport header in IPv6 packet, dropping\n"); 343 pr_debug("unable to find transport header in IPv6 packet, dropping\n");
344 return NF_DROP; 344 return NULL;
345 } 345 }
346 346
347 if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP) { 347 if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP) {
348 hp = skb_header_pointer(skb, thoff, 348 struct udphdr _hdr, *hp;
349 sizeof(_hdr), &_hdr); 349
350 hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
350 if (hp == NULL) 351 if (hp == NULL)
351 return false; 352 return NULL;
352 353
353 saddr = &iph->saddr; 354 saddr = &iph->saddr;
354 sport = hp->source; 355 sport = hp->source;
@@ -356,17 +357,27 @@ socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
356 dport = hp->dest; 357 dport = hp->dest;
357 358
358 } else if (tproto == IPPROTO_ICMPV6) { 359 } else if (tproto == IPPROTO_ICMPV6) {
360 struct ipv6hdr ipv6_var;
361
359 if (extract_icmp6_fields(skb, thoff, &tproto, &saddr, &daddr, 362 if (extract_icmp6_fields(skb, thoff, &tproto, &saddr, &daddr,
360 &sport, &dport, &ipv6_var)) 363 &sport, &dport, &ipv6_var))
361 return false; 364 return NULL;
362 } else { 365 } else {
363 return false; 366 return NULL;
364 } 367 }
365 368
369 return xt_socket_get_sock_v6(dev_net(skb->dev), tproto, saddr, daddr,
370 sport, dport, indev);
371}
372
373static bool
374socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
375{
376 const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;
377 struct sock *sk = skb->sk;
378
366 if (!sk) 379 if (!sk)
367 sk = xt_socket_get_sock_v6(dev_net(skb->dev), tproto, 380 sk = xt_socket_lookup_slow_v6(skb, par->in);
368 saddr, daddr, sport, dport,
369 par->in);
370 if (sk) { 381 if (sk) {
371 bool wildcard; 382 bool wildcard;
372 bool transparent = true; 383 bool transparent = true;
@@ -391,13 +402,7 @@ socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
391 sk = NULL; 402 sk = NULL;
392 } 403 }
393 404
394 pr_debug("proto %hhd %pI6:%hu -> %pI6:%hu " 405 return sk != NULL;
395 "(orig %pI6:%hu) sock %p\n",
396 tproto, saddr, ntohs(sport),
397 daddr, ntohs(dport),
398 &iph->daddr, hp ? ntohs(hp->dest) : 0, sk);
399
400 return (sk != NULL);
401} 406}
402#endif 407#endif
403 408