root/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nf_ct6_defrag_user
  2. ipv6_defrag
  3. defrag6_net_exit
  4. nf_defrag_init
  5. nf_defrag_fini
  6. nf_defrag_ipv6_enable

   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 
   6 #include <linux/types.h>
   7 #include <linux/ipv6.h>
   8 #include <linux/in6.h>
   9 #include <linux/netfilter.h>
  10 #include <linux/module.h>
  11 #include <linux/skbuff.h>
  12 #include <linux/icmp.h>
  13 #include <linux/sysctl.h>
  14 #include <net/ipv6_frag.h>
  15 
  16 #include <linux/netfilter_ipv6.h>
  17 #include <linux/netfilter_bridge.h>
  18 #if IS_ENABLED(CONFIG_NF_CONNTRACK)
  19 #include <net/netfilter/nf_conntrack.h>
  20 #include <net/netfilter/nf_conntrack_helper.h>
  21 #include <net/netfilter/nf_conntrack_l4proto.h>
  22 #include <net/netfilter/nf_conntrack_core.h>
  23 #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
  24 #endif
  25 #include <net/netfilter/nf_conntrack_zones.h>
  26 #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
  27 
  28 static DEFINE_MUTEX(defrag6_mutex);
  29 
  30 static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
  31                                                 struct sk_buff *skb)
  32 {
  33         u16 zone_id = NF_CT_DEFAULT_ZONE_ID;
  34 #if IS_ENABLED(CONFIG_NF_CONNTRACK)
  35         if (skb_nfct(skb)) {
  36                 enum ip_conntrack_info ctinfo;
  37                 const struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
  38 
  39                 zone_id = nf_ct_zone_id(nf_ct_zone(ct), CTINFO2DIR(ctinfo));
  40         }
  41 #endif
  42         if (nf_bridge_in_prerouting(skb))
  43                 return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone_id;
  44 
  45         if (hooknum == NF_INET_PRE_ROUTING)
  46                 return IP6_DEFRAG_CONNTRACK_IN + zone_id;
  47         else
  48                 return IP6_DEFRAG_CONNTRACK_OUT + zone_id;
  49 }
  50 
  51 static unsigned int ipv6_defrag(void *priv,
  52                                 struct sk_buff *skb,
  53                                 const struct nf_hook_state *state)
  54 {
  55         int err;
  56 
  57 #if IS_ENABLED(CONFIG_NF_CONNTRACK)
  58         /* Previously seen (loopback)?  */
  59         if (skb_nfct(skb) && !nf_ct_is_template((struct nf_conn *)skb_nfct(skb)))
  60                 return NF_ACCEPT;
  61 
  62         if (skb->_nfct == IP_CT_UNTRACKED)
  63                 return NF_ACCEPT;
  64 #endif
  65 
  66         err = nf_ct_frag6_gather(state->net, skb,
  67                                  nf_ct6_defrag_user(state->hook, skb));
  68         /* queued */
  69         if (err == -EINPROGRESS)
  70                 return NF_STOLEN;
  71 
  72         return err == 0 ? NF_ACCEPT : NF_DROP;
  73 }
  74 
  75 static const struct nf_hook_ops ipv6_defrag_ops[] = {
  76         {
  77                 .hook           = ipv6_defrag,
  78                 .pf             = NFPROTO_IPV6,
  79                 .hooknum        = NF_INET_PRE_ROUTING,
  80                 .priority       = NF_IP6_PRI_CONNTRACK_DEFRAG,
  81         },
  82         {
  83                 .hook           = ipv6_defrag,
  84                 .pf             = NFPROTO_IPV6,
  85                 .hooknum        = NF_INET_LOCAL_OUT,
  86                 .priority       = NF_IP6_PRI_CONNTRACK_DEFRAG,
  87         },
  88 };
  89 
  90 static void __net_exit defrag6_net_exit(struct net *net)
  91 {
  92         if (net->nf.defrag_ipv6) {
  93                 nf_unregister_net_hooks(net, ipv6_defrag_ops,
  94                                         ARRAY_SIZE(ipv6_defrag_ops));
  95                 net->nf.defrag_ipv6 = false;
  96         }
  97 }
  98 
  99 static struct pernet_operations defrag6_net_ops = {
 100         .exit = defrag6_net_exit,
 101 };
 102 
 103 static int __init nf_defrag_init(void)
 104 {
 105         int ret = 0;
 106 
 107         ret = nf_ct_frag6_init();
 108         if (ret < 0) {
 109                 pr_err("nf_defrag_ipv6: can't initialize frag6.\n");
 110                 return ret;
 111         }
 112         ret = register_pernet_subsys(&defrag6_net_ops);
 113         if (ret < 0) {
 114                 pr_err("nf_defrag_ipv6: can't register pernet ops\n");
 115                 goto cleanup_frag6;
 116         }
 117         return ret;
 118 
 119 cleanup_frag6:
 120         nf_ct_frag6_cleanup();
 121         return ret;
 122 
 123 }
 124 
 125 static void __exit nf_defrag_fini(void)
 126 {
 127         unregister_pernet_subsys(&defrag6_net_ops);
 128         nf_ct_frag6_cleanup();
 129 }
 130 
 131 int nf_defrag_ipv6_enable(struct net *net)
 132 {
 133         int err = 0;
 134 
 135         might_sleep();
 136 
 137         if (net->nf.defrag_ipv6)
 138                 return 0;
 139 
 140         mutex_lock(&defrag6_mutex);
 141         if (net->nf.defrag_ipv6)
 142                 goto out_unlock;
 143 
 144         err = nf_register_net_hooks(net, ipv6_defrag_ops,
 145                                     ARRAY_SIZE(ipv6_defrag_ops));
 146         if (err == 0)
 147                 net->nf.defrag_ipv6 = true;
 148 
 149  out_unlock:
 150         mutex_unlock(&defrag6_mutex);
 151         return err;
 152 }
 153 EXPORT_SYMBOL_GPL(nf_defrag_ipv6_enable);
 154 
 155 module_init(nf_defrag_init);
 156 module_exit(nf_defrag_fini);
 157 
 158 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */