diff options
author | David S. Miller <davem@davemloft.net> | 2014-07-30 16:25:49 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-07-30 16:25:49 -0400 |
commit | f139c74a8df071217dcd63f3ef06ae7be7071c4d (patch) | |
tree | 5711f695577a18a06dbcd0101956e97b388ffa1a /net/ipv4 | |
parent | bd695a5f0ccf7b38982c426d86055ff3591c9b5b (diff) | |
parent | 26bcd8b72563b4c54892c4c2a409f6656fb8ae8b (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/route.c | 32 |
1 files changed, 29 insertions, 3 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 3162ea923ded..190199851c9a 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -457,8 +457,31 @@ static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst, | |||
457 | return neigh_create(&arp_tbl, pkey, dev); | 457 | return neigh_create(&arp_tbl, pkey, dev); |
458 | } | 458 | } |
459 | 459 | ||
460 | atomic_t *ip_idents __read_mostly; | 460 | #define IP_IDENTS_SZ 2048u |
461 | EXPORT_SYMBOL(ip_idents); | 461 | struct ip_ident_bucket { |
462 | atomic_t id; | ||
463 | u32 stamp32; | ||
464 | }; | ||
465 | |||
466 | static struct ip_ident_bucket *ip_idents __read_mostly; | ||
467 | |||
468 | /* In order to protect privacy, we add a perturbation to identifiers | ||
469 | * if one generator is seldom used. This makes hard for an attacker | ||
470 | * to infer how many packets were sent between two points in time. | ||
471 | */ | ||
472 | u32 ip_idents_reserve(u32 hash, int segs) | ||
473 | { | ||
474 | struct ip_ident_bucket *bucket = ip_idents + hash % IP_IDENTS_SZ; | ||
475 | u32 old = ACCESS_ONCE(bucket->stamp32); | ||
476 | u32 now = (u32)jiffies; | ||
477 | u32 delta = 0; | ||
478 | |||
479 | if (old != now && cmpxchg(&bucket->stamp32, old, now) == old) | ||
480 | delta = prandom_u32_max(now - old); | ||
481 | |||
482 | return atomic_add_return(segs + delta, &bucket->id) - segs; | ||
483 | } | ||
484 | EXPORT_SYMBOL(ip_idents_reserve); | ||
462 | 485 | ||
463 | void __ip_select_ident(struct iphdr *iph, int segs) | 486 | void __ip_select_ident(struct iphdr *iph, int segs) |
464 | { | 487 | { |
@@ -467,7 +490,10 @@ void __ip_select_ident(struct iphdr *iph, int segs) | |||
467 | 490 | ||
468 | net_get_random_once(&ip_idents_hashrnd, sizeof(ip_idents_hashrnd)); | 491 | net_get_random_once(&ip_idents_hashrnd, sizeof(ip_idents_hashrnd)); |
469 | 492 | ||
470 | hash = jhash_1word((__force u32)iph->daddr, ip_idents_hashrnd); | 493 | hash = jhash_3words((__force u32)iph->daddr, |
494 | (__force u32)iph->saddr, | ||
495 | iph->protocol, | ||
496 | ip_idents_hashrnd); | ||
471 | id = ip_idents_reserve(hash, segs); | 497 | id = ip_idents_reserve(hash, segs); |
472 | iph->id = htons(id); | 498 | iph->id = htons(id); |
473 | } | 499 | } |