nf_dup_ipv4.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * (C) 2007 by Sebastian Claßen <sebastian.classen@freenet.ag>
  4. * (C) 2007-2010 by Jan Engelhardt <jengelh@medozas.de>
  5. *
  6. * Extracted from xt_TEE.c
  7. */
  8. #include <linux/ip.h>
  9. #include <linux/module.h>
  10. #include <linux/percpu.h>
  11. #include <linux/route.h>
  12. #include <linux/skbuff.h>
  13. #include <linux/netfilter.h>
  14. #include <net/checksum.h>
  15. #include <net/icmp.h>
  16. #include <net/ip.h>
  17. #include <net/route.h>
  18. #include <net/netfilter/ipv4/nf_dup_ipv4.h>
  19. #if IS_ENABLED(CONFIG_NF_CONNTRACK)
  20. #include <net/netfilter/nf_conntrack.h>
  21. #endif
  22. static bool nf_dup_ipv4_route(struct net *net, struct sk_buff *skb,
  23. const struct in_addr *gw, int oif)
  24. {
  25. const struct iphdr *iph = ip_hdr(skb);
  26. struct rtable *rt;
  27. struct flowi4 fl4;
  28. memset(&fl4, 0, sizeof(fl4));
  29. if (oif != -1)
  30. fl4.flowi4_oif = oif;
  31. fl4.daddr = gw->s_addr;
  32. fl4.flowi4_tos = RT_TOS(iph->tos);
  33. fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
  34. fl4.flowi4_flags = FLOWI_FLAG_KNOWN_NH;
  35. rt = ip_route_output_key(net, &fl4);
  36. if (IS_ERR(rt))
  37. return false;
  38. skb_dst_drop(skb);
  39. skb_dst_set(skb, &rt->dst);
  40. skb->dev = rt->dst.dev;
  41. skb->protocol = htons(ETH_P_IP);
  42. return true;
  43. }
  44. void nf_dup_ipv4(struct net *net, struct sk_buff *skb, unsigned int hooknum,
  45. const struct in_addr *gw, int oif)
  46. {
  47. struct iphdr *iph;
  48. if (this_cpu_read(nf_skb_duplicated))
  49. return;
  50. /*
  51. * Copy the skb, and route the copy. Will later return %XT_CONTINUE for
  52. * the original skb, which should continue on its way as if nothing has
  53. * happened. The copy should be independently delivered to the gateway.
  54. */
  55. skb = pskb_copy(skb, GFP_ATOMIC);
  56. if (skb == NULL)
  57. return;
  58. #if IS_ENABLED(CONFIG_NF_CONNTRACK)
  59. /* Avoid counting cloned packets towards the original connection. */
  60. nf_reset_ct(skb);
  61. nf_ct_set(skb, NULL, IP_CT_UNTRACKED);
  62. #endif
  63. /*
  64. * If we are in PREROUTING/INPUT, decrease the TTL to mitigate potential
  65. * loops between two hosts.
  66. *
  67. * Set %IP_DF so that the original source is notified of a potentially
  68. * decreased MTU on the clone route. IPv6 does this too.
  69. *
  70. * IP header checksum will be recalculated at ip_local_out.
  71. */
  72. iph = ip_hdr(skb);
  73. iph->frag_off |= htons(IP_DF);
  74. if (hooknum == NF_INET_PRE_ROUTING ||
  75. hooknum == NF_INET_LOCAL_IN)
  76. --iph->ttl;
  77. if (nf_dup_ipv4_route(net, skb, gw, oif)) {
  78. __this_cpu_write(nf_skb_duplicated, true);
  79. ip_local_out(net, skb->sk, skb);
  80. __this_cpu_write(nf_skb_duplicated, false);
  81. } else {
  82. kfree_skb(skb);
  83. }
  84. }
  85. EXPORT_SYMBOL_GPL(nf_dup_ipv4);
  86. MODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>");
  87. MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
  88. MODULE_DESCRIPTION("nf_dup_ipv4: Duplicate IPv4 packet");
  89. MODULE_LICENSE("GPL");