output_core.c 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344
  1. #include <linux/export.h>
  2. #include <linux/skbuff.h>
  3. #include <net/ip.h>
  4. #include <net/ipv6.h>
  5. /* This function exists only for tap drivers that must support broken
  6. * clients requesting UFO without specifying an IPv6 fragment ID.
  7. *
  8. * This is similar to ipv6_select_ident() but we use an independent hash
  9. * seed to limit information leakage.
  10. */
  11. void ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb)
  12. {
  13. struct in6_addr buf[2];
  14. struct in6_addr *addrs;
  15. u32 hash, id;
  16. addrs = skb_header_pointer(skb,
  17. skb_network_offset(skb) +
  18. offsetof(struct ipv6hdr, saddr),
  19. sizeof(buf), buf);
  20. if (addrs)
  21. {
  22. const struct {
  23. struct in6_addr dst;
  24. struct in6_addr src;
  25. } __aligned(SIPHASH_ALIGNMENT) combined = {
  26. .dst = addrs[1],
  27. .src = addrs[0],
  28. };
  29. /* Note the following code is not safe, but this is okay. */
  30. if (unlikely(siphash_key_is_zero(&net->ipv4.ip_id_key)))
  31. get_random_bytes(&net->ipv4.ip_id_key,
  32. sizeof(net->ipv4.ip_id_key));
  33. hash = siphash(&combined, sizeof(combined), &net->ipv4.ip_id_key);
  34. id = ip_idents_reserve(hash, 1);
  35. skb_shinfo(skb)->ip6_frag_id = htonl(id);
  36. }
  37. }
  38. EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident);