diff options
author | Daniel Borkmann <daniel@iogearbox.net> | 2015-04-02 08:28:30 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2015-04-08 10:47:49 -0400 |
commit | d64d80a2cde94f3e89caebd27240be419fec5b81 (patch) | |
tree | ad0b515bfbf7f37185776c384f952cc7ee7f64ae /net/netfilter | |
parent | 0b67c43ce36a9964f1d5e3f973ee19eefd3f9f8f (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.c | 95 |
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 | ||
146 | static bool | 146 | static struct sock *xt_socket_lookup_slow_v4(const struct sk_buff *skb, |
147 | socket_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 | |||
204 | static bool | ||
205 | socket_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 | ||
236 | static bool | 239 | static 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 | ||
330 | static bool | 333 | static struct sock *xt_socket_lookup_slow_v6(const struct sk_buff *skb, |
331 | socket_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 | |||
373 | static bool | ||
374 | socket_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 | ||