root/net/netfilter/xt_CT.c

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

DEFINITIONS

This source file includes following definitions.
  1. xt_ct_target
  2. xt_ct_target_v0
  3. xt_ct_target_v1
  4. xt_ct_find_proto
  5. xt_ct_set_helper
  6. xt_ct_set_timeout
  7. xt_ct_flags_to_dir
  8. xt_ct_tg_check
  9. xt_ct_tg_check_v0
  10. xt_ct_tg_check_v1
  11. xt_ct_tg_check_v2
  12. xt_ct_tg_destroy
  13. xt_ct_tg_destroy_v0
  14. xt_ct_tg_destroy_v1
  15. notrack_tg
  16. notrack_chk
  17. xt_ct_tg_init
  18. xt_ct_tg_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (c) 2010 Patrick McHardy <kaber@trash.net>
   4  */
   5 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   6 #include <linux/module.h>
   7 #include <linux/gfp.h>
   8 #include <linux/skbuff.h>
   9 #include <linux/netfilter_ipv4/ip_tables.h>
  10 #include <linux/netfilter_ipv6/ip6_tables.h>
  11 #include <linux/netfilter/x_tables.h>
  12 #include <linux/netfilter/xt_CT.h>
  13 #include <net/netfilter/nf_conntrack.h>
  14 #include <net/netfilter/nf_conntrack_l4proto.h>
  15 #include <net/netfilter/nf_conntrack_helper.h>
  16 #include <net/netfilter/nf_conntrack_ecache.h>
  17 #include <net/netfilter/nf_conntrack_timeout.h>
  18 #include <net/netfilter/nf_conntrack_zones.h>
  19 
  20 static inline int xt_ct_target(struct sk_buff *skb, struct nf_conn *ct)
  21 {
  22         /* Previously seen (loopback)? Ignore. */
  23         if (skb->_nfct != 0)
  24                 return XT_CONTINUE;
  25 
  26         if (ct) {
  27                 atomic_inc(&ct->ct_general.use);
  28                 nf_ct_set(skb, ct, IP_CT_NEW);
  29         } else {
  30                 nf_ct_set(skb, ct, IP_CT_UNTRACKED);
  31         }
  32 
  33         return XT_CONTINUE;
  34 }
  35 
  36 static unsigned int xt_ct_target_v0(struct sk_buff *skb,
  37                                     const struct xt_action_param *par)
  38 {
  39         const struct xt_ct_target_info *info = par->targinfo;
  40         struct nf_conn *ct = info->ct;
  41 
  42         return xt_ct_target(skb, ct);
  43 }
  44 
  45 static unsigned int xt_ct_target_v1(struct sk_buff *skb,
  46                                     const struct xt_action_param *par)
  47 {
  48         const struct xt_ct_target_info_v1 *info = par->targinfo;
  49         struct nf_conn *ct = info->ct;
  50 
  51         return xt_ct_target(skb, ct);
  52 }
  53 
  54 static u8 xt_ct_find_proto(const struct xt_tgchk_param *par)
  55 {
  56         if (par->family == NFPROTO_IPV4) {
  57                 const struct ipt_entry *e = par->entryinfo;
  58 
  59                 if (e->ip.invflags & IPT_INV_PROTO)
  60                         return 0;
  61                 return e->ip.proto;
  62         } else if (par->family == NFPROTO_IPV6) {
  63                 const struct ip6t_entry *e = par->entryinfo;
  64 
  65                 if (e->ipv6.invflags & IP6T_INV_PROTO)
  66                         return 0;
  67                 return e->ipv6.proto;
  68         } else
  69                 return 0;
  70 }
  71 
  72 static int
  73 xt_ct_set_helper(struct nf_conn *ct, const char *helper_name,
  74                  const struct xt_tgchk_param *par)
  75 {
  76         struct nf_conntrack_helper *helper;
  77         struct nf_conn_help *help;
  78         u8 proto;
  79 
  80         proto = xt_ct_find_proto(par);
  81         if (!proto) {
  82                 pr_info_ratelimited("You must specify a L4 protocol and not use inversions on it\n");
  83                 return -ENOENT;
  84         }
  85 
  86         helper = nf_conntrack_helper_try_module_get(helper_name, par->family,
  87                                                     proto);
  88         if (helper == NULL) {
  89                 pr_info_ratelimited("No such helper \"%s\"\n", helper_name);
  90                 return -ENOENT;
  91         }
  92 
  93         help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
  94         if (help == NULL) {
  95                 nf_conntrack_helper_put(helper);
  96                 return -ENOMEM;
  97         }
  98 
  99         help->helper = helper;
 100         return 0;
 101 }
 102 
 103 static int
 104 xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par,
 105                   const char *timeout_name)
 106 {
 107 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
 108         const struct nf_conntrack_l4proto *l4proto;
 109         u8 proto;
 110 
 111         proto = xt_ct_find_proto(par);
 112         if (!proto) {
 113                 pr_info_ratelimited("You must specify a L4 protocol and not "
 114                                     "use inversions on it");
 115                 return -EINVAL;
 116         }
 117         l4proto = nf_ct_l4proto_find(proto);
 118         return nf_ct_set_timeout(par->net, ct, par->family, l4proto->l4proto,
 119                                  timeout_name);
 120 
 121 #else
 122         return -EOPNOTSUPP;
 123 #endif
 124 }
 125 
 126 static u16 xt_ct_flags_to_dir(const struct xt_ct_target_info_v1 *info)
 127 {
 128         switch (info->flags & (XT_CT_ZONE_DIR_ORIG |
 129                                XT_CT_ZONE_DIR_REPL)) {
 130         case XT_CT_ZONE_DIR_ORIG:
 131                 return NF_CT_ZONE_DIR_ORIG;
 132         case XT_CT_ZONE_DIR_REPL:
 133                 return NF_CT_ZONE_DIR_REPL;
 134         default:
 135                 return NF_CT_DEFAULT_ZONE_DIR;
 136         }
 137 }
 138 
 139 static int xt_ct_tg_check(const struct xt_tgchk_param *par,
 140                           struct xt_ct_target_info_v1 *info)
 141 {
 142         struct nf_conntrack_zone zone;
 143         struct nf_conn_help *help;
 144         struct nf_conn *ct;
 145         int ret = -EOPNOTSUPP;
 146 
 147         if (info->flags & XT_CT_NOTRACK) {
 148                 ct = NULL;
 149                 goto out;
 150         }
 151 
 152 #ifndef CONFIG_NF_CONNTRACK_ZONES
 153         if (info->zone || info->flags & (XT_CT_ZONE_DIR_ORIG |
 154                                          XT_CT_ZONE_DIR_REPL |
 155                                          XT_CT_ZONE_MARK))
 156                 goto err1;
 157 #endif
 158 
 159         ret = nf_ct_netns_get(par->net, par->family);
 160         if (ret < 0)
 161                 goto err1;
 162 
 163         memset(&zone, 0, sizeof(zone));
 164         zone.id = info->zone;
 165         zone.dir = xt_ct_flags_to_dir(info);
 166         if (info->flags & XT_CT_ZONE_MARK)
 167                 zone.flags |= NF_CT_FLAG_MARK;
 168 
 169         ct = nf_ct_tmpl_alloc(par->net, &zone, GFP_KERNEL);
 170         if (!ct) {
 171                 ret = -ENOMEM;
 172                 goto err2;
 173         }
 174 
 175         ret = 0;
 176         if ((info->ct_events || info->exp_events) &&
 177             !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
 178                                   GFP_KERNEL)) {
 179                 ret = -EINVAL;
 180                 goto err3;
 181         }
 182 
 183         if (info->helper[0]) {
 184                 if (strnlen(info->helper, sizeof(info->helper)) == sizeof(info->helper)) {
 185                         ret = -ENAMETOOLONG;
 186                         goto err3;
 187                 }
 188 
 189                 ret = xt_ct_set_helper(ct, info->helper, par);
 190                 if (ret < 0)
 191                         goto err3;
 192         }
 193 
 194         if (info->timeout[0]) {
 195                 if (strnlen(info->timeout, sizeof(info->timeout)) == sizeof(info->timeout)) {
 196                         ret = -ENAMETOOLONG;
 197                         goto err4;
 198                 }
 199 
 200                 ret = xt_ct_set_timeout(ct, par, info->timeout);
 201                 if (ret < 0)
 202                         goto err4;
 203         }
 204         __set_bit(IPS_CONFIRMED_BIT, &ct->status);
 205         nf_conntrack_get(&ct->ct_general);
 206 out:
 207         info->ct = ct;
 208         return 0;
 209 
 210 err4:
 211         help = nfct_help(ct);
 212         if (help)
 213                 nf_conntrack_helper_put(help->helper);
 214 err3:
 215         nf_ct_tmpl_free(ct);
 216 err2:
 217         nf_ct_netns_put(par->net, par->family);
 218 err1:
 219         return ret;
 220 }
 221 
 222 static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
 223 {
 224         struct xt_ct_target_info *info = par->targinfo;
 225         struct xt_ct_target_info_v1 info_v1 = {
 226                 .flags          = info->flags,
 227                 .zone           = info->zone,
 228                 .ct_events      = info->ct_events,
 229                 .exp_events     = info->exp_events,
 230         };
 231         int ret;
 232 
 233         if (info->flags & ~XT_CT_NOTRACK)
 234                 return -EINVAL;
 235 
 236         memcpy(info_v1.helper, info->helper, sizeof(info->helper));
 237 
 238         ret = xt_ct_tg_check(par, &info_v1);
 239         if (ret < 0)
 240                 return ret;
 241 
 242         info->ct = info_v1.ct;
 243 
 244         return ret;
 245 }
 246 
 247 static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
 248 {
 249         struct xt_ct_target_info_v1 *info = par->targinfo;
 250 
 251         if (info->flags & ~XT_CT_NOTRACK)
 252                 return -EINVAL;
 253 
 254         return xt_ct_tg_check(par, par->targinfo);
 255 }
 256 
 257 static int xt_ct_tg_check_v2(const struct xt_tgchk_param *par)
 258 {
 259         struct xt_ct_target_info_v1 *info = par->targinfo;
 260 
 261         if (info->flags & ~XT_CT_MASK)
 262                 return -EINVAL;
 263 
 264         return xt_ct_tg_check(par, par->targinfo);
 265 }
 266 
 267 static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par,
 268                              struct xt_ct_target_info_v1 *info)
 269 {
 270         struct nf_conn *ct = info->ct;
 271         struct nf_conn_help *help;
 272 
 273         if (ct) {
 274                 help = nfct_help(ct);
 275                 if (help)
 276                         nf_conntrack_helper_put(help->helper);
 277 
 278                 nf_ct_netns_put(par->net, par->family);
 279 
 280                 nf_ct_destroy_timeout(ct);
 281                 nf_ct_put(info->ct);
 282         }
 283 }
 284 
 285 static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par)
 286 {
 287         struct xt_ct_target_info *info = par->targinfo;
 288         struct xt_ct_target_info_v1 info_v1 = {
 289                 .flags          = info->flags,
 290                 .zone           = info->zone,
 291                 .ct_events      = info->ct_events,
 292                 .exp_events     = info->exp_events,
 293                 .ct             = info->ct,
 294         };
 295         memcpy(info_v1.helper, info->helper, sizeof(info->helper));
 296 
 297         xt_ct_tg_destroy(par, &info_v1);
 298 }
 299 
 300 static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par)
 301 {
 302         xt_ct_tg_destroy(par, par->targinfo);
 303 }
 304 
 305 static struct xt_target xt_ct_tg_reg[] __read_mostly = {
 306         {
 307                 .name           = "CT",
 308                 .family         = NFPROTO_UNSPEC,
 309                 .targetsize     = sizeof(struct xt_ct_target_info),
 310                 .usersize       = offsetof(struct xt_ct_target_info, ct),
 311                 .checkentry     = xt_ct_tg_check_v0,
 312                 .destroy        = xt_ct_tg_destroy_v0,
 313                 .target         = xt_ct_target_v0,
 314                 .table          = "raw",
 315                 .me             = THIS_MODULE,
 316         },
 317         {
 318                 .name           = "CT",
 319                 .family         = NFPROTO_UNSPEC,
 320                 .revision       = 1,
 321                 .targetsize     = sizeof(struct xt_ct_target_info_v1),
 322                 .usersize       = offsetof(struct xt_ct_target_info, ct),
 323                 .checkentry     = xt_ct_tg_check_v1,
 324                 .destroy        = xt_ct_tg_destroy_v1,
 325                 .target         = xt_ct_target_v1,
 326                 .table          = "raw",
 327                 .me             = THIS_MODULE,
 328         },
 329         {
 330                 .name           = "CT",
 331                 .family         = NFPROTO_UNSPEC,
 332                 .revision       = 2,
 333                 .targetsize     = sizeof(struct xt_ct_target_info_v1),
 334                 .usersize       = offsetof(struct xt_ct_target_info, ct),
 335                 .checkentry     = xt_ct_tg_check_v2,
 336                 .destroy        = xt_ct_tg_destroy_v1,
 337                 .target         = xt_ct_target_v1,
 338                 .table          = "raw",
 339                 .me             = THIS_MODULE,
 340         },
 341 };
 342 
 343 static unsigned int
 344 notrack_tg(struct sk_buff *skb, const struct xt_action_param *par)
 345 {
 346         /* Previously seen (loopback)? Ignore. */
 347         if (skb->_nfct != 0)
 348                 return XT_CONTINUE;
 349 
 350         nf_ct_set(skb, NULL, IP_CT_UNTRACKED);
 351 
 352         return XT_CONTINUE;
 353 }
 354 
 355 static int notrack_chk(const struct xt_tgchk_param *par)
 356 {
 357         if (!par->net->xt.notrack_deprecated_warning) {
 358                 pr_info("netfilter: NOTRACK target is deprecated, "
 359                         "use CT instead or upgrade iptables\n");
 360                 par->net->xt.notrack_deprecated_warning = true;
 361         }
 362         return 0;
 363 }
 364 
 365 static struct xt_target notrack_tg_reg __read_mostly = {
 366         .name           = "NOTRACK",
 367         .revision       = 0,
 368         .family         = NFPROTO_UNSPEC,
 369         .checkentry     = notrack_chk,
 370         .target         = notrack_tg,
 371         .table          = "raw",
 372         .me             = THIS_MODULE,
 373 };
 374 
 375 static int __init xt_ct_tg_init(void)
 376 {
 377         int ret;
 378 
 379         ret = xt_register_target(&notrack_tg_reg);
 380         if (ret < 0)
 381                 return ret;
 382 
 383         ret = xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
 384         if (ret < 0) {
 385                 xt_unregister_target(&notrack_tg_reg);
 386                 return ret;
 387         }
 388         return 0;
 389 }
 390 
 391 static void __exit xt_ct_tg_exit(void)
 392 {
 393         xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
 394         xt_unregister_target(&notrack_tg_reg);
 395 }
 396 
 397 module_init(xt_ct_tg_init);
 398 module_exit(xt_ct_tg_exit);
 399 
 400 MODULE_LICENSE("GPL");
 401 MODULE_DESCRIPTION("Xtables: connection tracking target");
 402 MODULE_ALIAS("ipt_CT");
 403 MODULE_ALIAS("ip6t_CT");
 404 MODULE_ALIAS("ipt_NOTRACK");
 405 MODULE_ALIAS("ip6t_NOTRACK");

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