nf_defrag_ipv4.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* (C) 1999-2001 Paul `Rusty' Russell
  3. * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
  4. */
  5. #include <linux/types.h>
  6. #include <linux/ip.h>
  7. #include <linux/netfilter.h>
  8. #include <linux/module.h>
  9. #include <linux/skbuff.h>
  10. #include <net/netns/generic.h>
  11. #include <net/route.h>
  12. #include <net/ip.h>
  13. #include <linux/netfilter_bridge.h>
  14. #include <linux/netfilter_ipv4.h>
  15. #include <net/netfilter/ipv4/nf_defrag_ipv4.h>
  16. #if IS_ENABLED(CONFIG_NF_CONNTRACK)
  17. #include <net/netfilter/nf_conntrack.h>
  18. #endif
  19. #include <net/netfilter/nf_conntrack_zones.h>
  20. static DEFINE_MUTEX(defrag4_mutex);
  21. static int nf_ct_ipv4_gather_frags(struct net *net, struct sk_buff *skb,
  22. u_int32_t user)
  23. {
  24. int err;
  25. local_bh_disable();
  26. err = ip_defrag(net, skb, user);
  27. local_bh_enable();
  28. if (!err)
  29. skb->ignore_df = 1;
  30. return err;
  31. }
  32. static enum ip_defrag_users nf_ct_defrag_user(unsigned int hooknum,
  33. struct sk_buff *skb)
  34. {
  35. u16 zone_id = NF_CT_DEFAULT_ZONE_ID;
  36. #if IS_ENABLED(CONFIG_NF_CONNTRACK)
  37. if (skb_nfct(skb)) {
  38. enum ip_conntrack_info ctinfo;
  39. const struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
  40. zone_id = nf_ct_zone_id(nf_ct_zone(ct), CTINFO2DIR(ctinfo));
  41. }
  42. #endif
  43. if (nf_bridge_in_prerouting(skb))
  44. return IP_DEFRAG_CONNTRACK_BRIDGE_IN + zone_id;
  45. if (hooknum == NF_INET_PRE_ROUTING)
  46. return IP_DEFRAG_CONNTRACK_IN + zone_id;
  47. else
  48. return IP_DEFRAG_CONNTRACK_OUT + zone_id;
  49. }
  50. static unsigned int ipv4_conntrack_defrag(void *priv,
  51. struct sk_buff *skb,
  52. const struct nf_hook_state *state)
  53. {
  54. struct sock *sk = skb->sk;
  55. if (sk && sk_fullsock(sk) && (sk->sk_family == PF_INET) &&
  56. inet_sk(sk)->nodefrag)
  57. return NF_ACCEPT;
  58. #if IS_ENABLED(CONFIG_NF_CONNTRACK)
  59. #if !IS_ENABLED(CONFIG_NF_NAT)
  60. /* Previously seen (loopback)? Ignore. Do this before
  61. fragment check. */
  62. if (skb_nfct(skb) && !nf_ct_is_template((struct nf_conn *)skb_nfct(skb)))
  63. return NF_ACCEPT;
  64. #endif
  65. if (skb->_nfct == IP_CT_UNTRACKED)
  66. return NF_ACCEPT;
  67. #endif
  68. /* Gather fragments. */
  69. if (ip_is_fragment(ip_hdr(skb))) {
  70. enum ip_defrag_users user =
  71. nf_ct_defrag_user(state->hook, skb);
  72. if (nf_ct_ipv4_gather_frags(state->net, skb, user))
  73. return NF_STOLEN;
  74. }
  75. return NF_ACCEPT;
  76. }
  77. static const struct nf_hook_ops ipv4_defrag_ops[] = {
  78. {
  79. .hook = ipv4_conntrack_defrag,
  80. .pf = NFPROTO_IPV4,
  81. .hooknum = NF_INET_PRE_ROUTING,
  82. .priority = NF_IP_PRI_CONNTRACK_DEFRAG,
  83. },
  84. {
  85. .hook = ipv4_conntrack_defrag,
  86. .pf = NFPROTO_IPV4,
  87. .hooknum = NF_INET_LOCAL_OUT,
  88. .priority = NF_IP_PRI_CONNTRACK_DEFRAG,
  89. },
  90. };
  91. static void __net_exit defrag4_net_exit(struct net *net)
  92. {
  93. if (net->nf.defrag_ipv4) {
  94. nf_unregister_net_hooks(net, ipv4_defrag_ops,
  95. ARRAY_SIZE(ipv4_defrag_ops));
  96. net->nf.defrag_ipv4 = false;
  97. }
  98. }
  99. static struct pernet_operations defrag4_net_ops = {
  100. .exit = defrag4_net_exit,
  101. };
  102. static int __init nf_defrag_init(void)
  103. {
  104. return register_pernet_subsys(&defrag4_net_ops);
  105. }
  106. static void __exit nf_defrag_fini(void)
  107. {
  108. unregister_pernet_subsys(&defrag4_net_ops);
  109. }
  110. int nf_defrag_ipv4_enable(struct net *net)
  111. {
  112. int err = 0;
  113. might_sleep();
  114. if (net->nf.defrag_ipv4)
  115. return 0;
  116. mutex_lock(&defrag4_mutex);
  117. if (net->nf.defrag_ipv4)
  118. goto out_unlock;
  119. err = nf_register_net_hooks(net, ipv4_defrag_ops,
  120. ARRAY_SIZE(ipv4_defrag_ops));
  121. if (err == 0)
  122. net->nf.defrag_ipv4 = true;
  123. out_unlock:
  124. mutex_unlock(&defrag4_mutex);
  125. return err;
  126. }
  127. EXPORT_SYMBOL_GPL(nf_defrag_ipv4_enable);
  128. module_init(nf_defrag_init);
  129. module_exit(nf_defrag_fini);
  130. MODULE_LICENSE("GPL");