184f3bb9aSPatrick McHardy /* 284f3bb9aSPatrick McHardy * Copyright (c) 2010 Patrick McHardy <kaber@trash.net> 384f3bb9aSPatrick McHardy * 484f3bb9aSPatrick McHardy * This program is free software; you can redistribute it and/or modify 584f3bb9aSPatrick McHardy * it under the terms of the GNU General Public License version 2 as 684f3bb9aSPatrick McHardy * published by the Free Software Foundation. 784f3bb9aSPatrick McHardy */ 8a7fed762SJan Engelhardt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 984f3bb9aSPatrick McHardy #include <linux/module.h> 105a0e3ad6STejun Heo #include <linux/gfp.h> 1184f3bb9aSPatrick McHardy #include <linux/skbuff.h> 1284f3bb9aSPatrick McHardy #include <linux/netfilter_ipv4/ip_tables.h> 1384f3bb9aSPatrick McHardy #include <linux/netfilter_ipv6/ip6_tables.h> 1484f3bb9aSPatrick McHardy #include <linux/netfilter/x_tables.h> 1584f3bb9aSPatrick McHardy #include <linux/netfilter/xt_CT.h> 1684f3bb9aSPatrick McHardy #include <net/netfilter/nf_conntrack.h> 17eeb4cb95SPablo Neira Ayuso #include <net/netfilter/nf_conntrack_l4proto.h> 1884f3bb9aSPatrick McHardy #include <net/netfilter/nf_conntrack_helper.h> 1984f3bb9aSPatrick McHardy #include <net/netfilter/nf_conntrack_ecache.h> 2024de58f4SPablo Neira Ayuso #include <net/netfilter/nf_conntrack_timeout.h> 215d0aa2ccSPatrick McHardy #include <net/netfilter/nf_conntrack_zones.h> 2284f3bb9aSPatrick McHardy 23d52ed437SPablo Neira Ayuso static inline int xt_ct_target(struct sk_buff *skb, struct nf_conn *ct) 2484f3bb9aSPatrick McHardy { 2584f3bb9aSPatrick McHardy /* Previously seen (loopback)? Ignore. */ 26a9e419dcSFlorian Westphal if (skb->_nfct != 0) 2784f3bb9aSPatrick McHardy return XT_CONTINUE; 2884f3bb9aSPatrick McHardy 29cc41c84bSFlorian Westphal if (ct) { 3084f3bb9aSPatrick McHardy atomic_inc(&ct->ct_general.use); 31c74454faSFlorian Westphal nf_ct_set(skb, ct, IP_CT_NEW); 32cc41c84bSFlorian Westphal } else { 33cc41c84bSFlorian Westphal nf_ct_set(skb, ct, IP_CT_UNTRACKED); 34cc41c84bSFlorian Westphal } 3584f3bb9aSPatrick McHardy 3684f3bb9aSPatrick McHardy return XT_CONTINUE; 3784f3bb9aSPatrick McHardy } 3884f3bb9aSPatrick McHardy 39d52ed437SPablo Neira Ayuso static unsigned int xt_ct_target_v0(struct sk_buff *skb, 40d52ed437SPablo Neira Ayuso const struct xt_action_param *par) 41d52ed437SPablo Neira Ayuso { 42d52ed437SPablo Neira Ayuso const struct xt_ct_target_info *info = par->targinfo; 43d52ed437SPablo Neira Ayuso struct nf_conn *ct = info->ct; 44d52ed437SPablo Neira Ayuso 45d52ed437SPablo Neira Ayuso return xt_ct_target(skb, ct); 46d52ed437SPablo Neira Ayuso } 47d52ed437SPablo Neira Ayuso 4824de58f4SPablo Neira Ayuso static unsigned int xt_ct_target_v1(struct sk_buff *skb, 4924de58f4SPablo Neira Ayuso const struct xt_action_param *par) 5024de58f4SPablo Neira Ayuso { 5124de58f4SPablo Neira Ayuso const struct xt_ct_target_info_v1 *info = par->targinfo; 5224de58f4SPablo Neira Ayuso struct nf_conn *ct = info->ct; 5324de58f4SPablo Neira Ayuso 54d52ed437SPablo Neira Ayuso return xt_ct_target(skb, ct); 5524de58f4SPablo Neira Ayuso } 5624de58f4SPablo Neira Ayuso 5784f3bb9aSPatrick McHardy static u8 xt_ct_find_proto(const struct xt_tgchk_param *par) 5884f3bb9aSPatrick McHardy { 59076f7839SJan Engelhardt if (par->family == NFPROTO_IPV4) { 6084f3bb9aSPatrick McHardy const struct ipt_entry *e = par->entryinfo; 6184f3bb9aSPatrick McHardy 6284f3bb9aSPatrick McHardy if (e->ip.invflags & IPT_INV_PROTO) 6384f3bb9aSPatrick McHardy return 0; 6484f3bb9aSPatrick McHardy return e->ip.proto; 65076f7839SJan Engelhardt } else if (par->family == NFPROTO_IPV6) { 6684f3bb9aSPatrick McHardy const struct ip6t_entry *e = par->entryinfo; 6784f3bb9aSPatrick McHardy 6884f3bb9aSPatrick McHardy if (e->ipv6.invflags & IP6T_INV_PROTO) 6984f3bb9aSPatrick McHardy return 0; 7084f3bb9aSPatrick McHardy return e->ipv6.proto; 7184f3bb9aSPatrick McHardy } else 7284f3bb9aSPatrick McHardy return 0; 7384f3bb9aSPatrick McHardy } 7484f3bb9aSPatrick McHardy 75236df005SPablo Neira Ayuso static int 76236df005SPablo Neira Ayuso xt_ct_set_helper(struct nf_conn *ct, const char *helper_name, 77236df005SPablo Neira Ayuso const struct xt_tgchk_param *par) 78236df005SPablo Neira Ayuso { 79236df005SPablo Neira Ayuso struct nf_conntrack_helper *helper; 80236df005SPablo Neira Ayuso struct nf_conn_help *help; 81236df005SPablo Neira Ayuso u8 proto; 82236df005SPablo Neira Ayuso 83236df005SPablo Neira Ayuso proto = xt_ct_find_proto(par); 84236df005SPablo Neira Ayuso if (!proto) { 85236df005SPablo Neira Ayuso pr_info("You must specify a L4 protocol, and not use " 86236df005SPablo Neira Ayuso "inversions on it.\n"); 87236df005SPablo Neira Ayuso return -ENOENT; 88236df005SPablo Neira Ayuso } 89236df005SPablo Neira Ayuso 90236df005SPablo Neira Ayuso helper = nf_conntrack_helper_try_module_get(helper_name, par->family, 91236df005SPablo Neira Ayuso proto); 92236df005SPablo Neira Ayuso if (helper == NULL) { 93236df005SPablo Neira Ayuso pr_info("No such helper \"%s\"\n", helper_name); 94236df005SPablo Neira Ayuso return -ENOENT; 95236df005SPablo Neira Ayuso } 96236df005SPablo Neira Ayuso 97236df005SPablo Neira Ayuso help = nf_ct_helper_ext_add(ct, helper, GFP_KERNEL); 98236df005SPablo Neira Ayuso if (help == NULL) { 99236df005SPablo Neira Ayuso module_put(helper->me); 100236df005SPablo Neira Ayuso return -ENOMEM; 101236df005SPablo Neira Ayuso } 102236df005SPablo Neira Ayuso 103236df005SPablo Neira Ayuso help->helper = helper; 104236df005SPablo Neira Ayuso return 0; 105236df005SPablo Neira Ayuso } 106236df005SPablo Neira Ayuso 107ee14186fSPablo Neira Ayuso #ifdef CONFIG_NF_CONNTRACK_TIMEOUT 108ee14186fSPablo Neira Ayuso static void __xt_ct_tg_timeout_put(struct ctnl_timeout *timeout) 109ee14186fSPablo Neira Ayuso { 110ee14186fSPablo Neira Ayuso typeof(nf_ct_timeout_put_hook) timeout_put; 111ee14186fSPablo Neira Ayuso 112ee14186fSPablo Neira Ayuso timeout_put = rcu_dereference(nf_ct_timeout_put_hook); 113ee14186fSPablo Neira Ayuso if (timeout_put) 114ee14186fSPablo Neira Ayuso timeout_put(timeout); 115ee14186fSPablo Neira Ayuso } 116ee14186fSPablo Neira Ayuso #endif 117ee14186fSPablo Neira Ayuso 118236df005SPablo Neira Ayuso static int 119236df005SPablo Neira Ayuso xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par, 120236df005SPablo Neira Ayuso const char *timeout_name) 121236df005SPablo Neira Ayuso { 122236df005SPablo Neira Ayuso #ifdef CONFIG_NF_CONNTRACK_TIMEOUT 123236df005SPablo Neira Ayuso typeof(nf_ct_timeout_find_get_hook) timeout_find_get; 124236df005SPablo Neira Ayuso struct ctnl_timeout *timeout; 125236df005SPablo Neira Ayuso struct nf_conn_timeout *timeout_ext; 126236df005SPablo Neira Ayuso struct nf_conntrack_l4proto *l4proto; 127236df005SPablo Neira Ayuso int ret = 0; 1280153d5a8SPablo Neira Ayuso u8 proto; 129236df005SPablo Neira Ayuso 130236df005SPablo Neira Ayuso rcu_read_lock(); 131236df005SPablo Neira Ayuso timeout_find_get = rcu_dereference(nf_ct_timeout_find_get_hook); 132236df005SPablo Neira Ayuso if (timeout_find_get == NULL) { 133236df005SPablo Neira Ayuso ret = -ENOENT; 134236df005SPablo Neira Ayuso pr_info("Timeout policy base is empty\n"); 135236df005SPablo Neira Ayuso goto out; 136236df005SPablo Neira Ayuso } 137236df005SPablo Neira Ayuso 1380153d5a8SPablo Neira Ayuso proto = xt_ct_find_proto(par); 1390153d5a8SPablo Neira Ayuso if (!proto) { 140236df005SPablo Neira Ayuso ret = -EINVAL; 1410153d5a8SPablo Neira Ayuso pr_info("You must specify a L4 protocol, and not use " 1420153d5a8SPablo Neira Ayuso "inversions on it.\n"); 143236df005SPablo Neira Ayuso goto out; 144236df005SPablo Neira Ayuso } 145236df005SPablo Neira Ayuso 14619576c94SPablo Neira timeout = timeout_find_get(par->net, timeout_name); 147236df005SPablo Neira Ayuso if (timeout == NULL) { 148236df005SPablo Neira Ayuso ret = -ENOENT; 149236df005SPablo Neira Ayuso pr_info("No such timeout policy \"%s\"\n", timeout_name); 150236df005SPablo Neira Ayuso goto out; 151236df005SPablo Neira Ayuso } 152236df005SPablo Neira Ayuso 153236df005SPablo Neira Ayuso if (timeout->l3num != par->family) { 154236df005SPablo Neira Ayuso ret = -EINVAL; 155236df005SPablo Neira Ayuso pr_info("Timeout policy `%s' can only be used by L3 protocol " 156236df005SPablo Neira Ayuso "number %d\n", timeout_name, timeout->l3num); 157236df005SPablo Neira Ayuso goto err_put_timeout; 158236df005SPablo Neira Ayuso } 159236df005SPablo Neira Ayuso /* Make sure the timeout policy matches any existing protocol tracker, 160236df005SPablo Neira Ayuso * otherwise default to generic. 161236df005SPablo Neira Ayuso */ 1620153d5a8SPablo Neira Ayuso l4proto = __nf_ct_l4proto_find(par->family, proto); 163236df005SPablo Neira Ayuso if (timeout->l4proto->l4proto != l4proto->l4proto) { 164236df005SPablo Neira Ayuso ret = -EINVAL; 165236df005SPablo Neira Ayuso pr_info("Timeout policy `%s' can only be used by L4 protocol " 166236df005SPablo Neira Ayuso "number %d\n", 167236df005SPablo Neira Ayuso timeout_name, timeout->l4proto->l4proto); 168236df005SPablo Neira Ayuso goto err_put_timeout; 169236df005SPablo Neira Ayuso } 170236df005SPablo Neira Ayuso timeout_ext = nf_ct_timeout_ext_add(ct, timeout, GFP_ATOMIC); 171236df005SPablo Neira Ayuso if (timeout_ext == NULL) 172236df005SPablo Neira Ayuso ret = -ENOMEM; 173236df005SPablo Neira Ayuso 174403d89adSPablo Neira Ayuso rcu_read_unlock(); 175403d89adSPablo Neira Ayuso return ret; 176403d89adSPablo Neira Ayuso 177236df005SPablo Neira Ayuso err_put_timeout: 178236df005SPablo Neira Ayuso __xt_ct_tg_timeout_put(timeout); 179236df005SPablo Neira Ayuso out: 180236df005SPablo Neira Ayuso rcu_read_unlock(); 181236df005SPablo Neira Ayuso return ret; 182236df005SPablo Neira Ayuso #else 183236df005SPablo Neira Ayuso return -EOPNOTSUPP; 184236df005SPablo Neira Ayuso #endif 185236df005SPablo Neira Ayuso } 186236df005SPablo Neira Ayuso 187deedb590SDaniel Borkmann static u16 xt_ct_flags_to_dir(const struct xt_ct_target_info_v1 *info) 188deedb590SDaniel Borkmann { 189deedb590SDaniel Borkmann switch (info->flags & (XT_CT_ZONE_DIR_ORIG | 190deedb590SDaniel Borkmann XT_CT_ZONE_DIR_REPL)) { 191deedb590SDaniel Borkmann case XT_CT_ZONE_DIR_ORIG: 192deedb590SDaniel Borkmann return NF_CT_ZONE_DIR_ORIG; 193deedb590SDaniel Borkmann case XT_CT_ZONE_DIR_REPL: 194deedb590SDaniel Borkmann return NF_CT_ZONE_DIR_REPL; 195deedb590SDaniel Borkmann default: 196deedb590SDaniel Borkmann return NF_CT_DEFAULT_ZONE_DIR; 197deedb590SDaniel Borkmann } 198deedb590SDaniel Borkmann } 199deedb590SDaniel Borkmann 200d52ed437SPablo Neira Ayuso static int xt_ct_tg_check(const struct xt_tgchk_param *par, 201d52ed437SPablo Neira Ayuso struct xt_ct_target_info_v1 *info) 20224de58f4SPablo Neira Ayuso { 203308ac914SDaniel Borkmann struct nf_conntrack_zone zone; 20424de58f4SPablo Neira Ayuso struct nf_conn *ct; 2054610476dSPablo Neira Ayuso int ret = -EOPNOTSUPP; 206236df005SPablo Neira Ayuso 20724de58f4SPablo Neira Ayuso if (info->flags & XT_CT_NOTRACK) { 20827e7190eSEric Dumazet ct = NULL; 20924de58f4SPablo Neira Ayuso goto out; 21024de58f4SPablo Neira Ayuso } 21124de58f4SPablo Neira Ayuso 21224de58f4SPablo Neira Ayuso #ifndef CONFIG_NF_CONNTRACK_ZONES 213deedb590SDaniel Borkmann if (info->zone || info->flags & (XT_CT_ZONE_DIR_ORIG | 2145e8018fcSDaniel Borkmann XT_CT_ZONE_DIR_REPL | 2155e8018fcSDaniel Borkmann XT_CT_ZONE_MARK)) 21624de58f4SPablo Neira Ayuso goto err1; 21724de58f4SPablo Neira Ayuso #endif 21824de58f4SPablo Neira Ayuso 219ecb2421bSFlorian Westphal ret = nf_ct_netns_get(par->net, par->family); 22024de58f4SPablo Neira Ayuso if (ret < 0) 22124de58f4SPablo Neira Ayuso goto err1; 22224de58f4SPablo Neira Ayuso 223308ac914SDaniel Borkmann memset(&zone, 0, sizeof(zone)); 224308ac914SDaniel Borkmann zone.id = info->zone; 225deedb590SDaniel Borkmann zone.dir = xt_ct_flags_to_dir(info); 2265e8018fcSDaniel Borkmann if (info->flags & XT_CT_ZONE_MARK) 2275e8018fcSDaniel Borkmann zone.flags |= NF_CT_FLAG_MARK; 228308ac914SDaniel Borkmann 229308ac914SDaniel Borkmann ct = nf_ct_tmpl_alloc(par->net, &zone, GFP_KERNEL); 2301a727c63SDan Carpenter if (!ct) { 2311a727c63SDan Carpenter ret = -ENOMEM; 23224de58f4SPablo Neira Ayuso goto err2; 2331a727c63SDan Carpenter } 23424de58f4SPablo Neira Ayuso 23524de58f4SPablo Neira Ayuso ret = 0; 23624de58f4SPablo Neira Ayuso if ((info->ct_events || info->exp_events) && 23724de58f4SPablo Neira Ayuso !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events, 23814abfa16SEric Leblond GFP_KERNEL)) { 23914abfa16SEric Leblond ret = -EINVAL; 24024de58f4SPablo Neira Ayuso goto err3; 24114abfa16SEric Leblond } 24224de58f4SPablo Neira Ayuso 24324de58f4SPablo Neira Ayuso if (info->helper[0]) { 244236df005SPablo Neira Ayuso ret = xt_ct_set_helper(ct, info->helper, par); 245236df005SPablo Neira Ayuso if (ret < 0) 24624de58f4SPablo Neira Ayuso goto err3; 24724de58f4SPablo Neira Ayuso } 24824de58f4SPablo Neira Ayuso 2496cf51852SPablo Neira Ayuso if (info->timeout[0]) { 250236df005SPablo Neira Ayuso ret = xt_ct_set_timeout(ct, par, info->timeout); 251236df005SPablo Neira Ayuso if (ret < 0) 252236df005SPablo Neira Ayuso goto err3; 25324de58f4SPablo Neira Ayuso } 2540838aa7fSPablo Neira Ayuso __set_bit(IPS_CONFIRMED_BIT, &ct->status); 2550838aa7fSPablo Neira Ayuso nf_conntrack_get(&ct->ct_general); 25624de58f4SPablo Neira Ayuso out: 25724de58f4SPablo Neira Ayuso info->ct = ct; 25824de58f4SPablo Neira Ayuso return 0; 25924de58f4SPablo Neira Ayuso 26024de58f4SPablo Neira Ayuso err3: 2619cf94eabSDaniel Borkmann nf_ct_tmpl_free(ct); 26224de58f4SPablo Neira Ayuso err2: 263ecb2421bSFlorian Westphal nf_ct_netns_put(par->net, par->family); 26424de58f4SPablo Neira Ayuso err1: 26524de58f4SPablo Neira Ayuso return ret; 26624de58f4SPablo Neira Ayuso } 26724de58f4SPablo Neira Ayuso 268d52ed437SPablo Neira Ayuso static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par) 26984f3bb9aSPatrick McHardy { 27084f3bb9aSPatrick McHardy struct xt_ct_target_info *info = par->targinfo; 271d52ed437SPablo Neira Ayuso struct xt_ct_target_info_v1 info_v1 = { 272d52ed437SPablo Neira Ayuso .flags = info->flags, 273d52ed437SPablo Neira Ayuso .zone = info->zone, 274d52ed437SPablo Neira Ayuso .ct_events = info->ct_events, 275d52ed437SPablo Neira Ayuso .exp_events = info->exp_events, 276d52ed437SPablo Neira Ayuso }; 277d52ed437SPablo Neira Ayuso int ret; 27884f3bb9aSPatrick McHardy 2795474f57fSPablo Neira Ayuso if (info->flags & ~XT_CT_NOTRACK) 2805474f57fSPablo Neira Ayuso return -EINVAL; 2815474f57fSPablo Neira Ayuso 282d52ed437SPablo Neira Ayuso memcpy(info_v1.helper, info->helper, sizeof(info->helper)); 28384f3bb9aSPatrick McHardy 284d52ed437SPablo Neira Ayuso ret = xt_ct_tg_check(par, &info_v1); 285d52ed437SPablo Neira Ayuso if (ret < 0) 286d52ed437SPablo Neira Ayuso return ret; 287d52ed437SPablo Neira Ayuso 288d52ed437SPablo Neira Ayuso info->ct = info_v1.ct; 289d52ed437SPablo Neira Ayuso 290d52ed437SPablo Neira Ayuso return ret; 29184f3bb9aSPatrick McHardy } 292d52ed437SPablo Neira Ayuso 293d52ed437SPablo Neira Ayuso static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) 294d52ed437SPablo Neira Ayuso { 2955474f57fSPablo Neira Ayuso struct xt_ct_target_info_v1 *info = par->targinfo; 2965474f57fSPablo Neira Ayuso 2975474f57fSPablo Neira Ayuso if (info->flags & ~XT_CT_NOTRACK) 2985474f57fSPablo Neira Ayuso return -EINVAL; 2995474f57fSPablo Neira Ayuso 3005474f57fSPablo Neira Ayuso return xt_ct_tg_check(par, par->targinfo); 3015474f57fSPablo Neira Ayuso } 3025474f57fSPablo Neira Ayuso 3035474f57fSPablo Neira Ayuso static int xt_ct_tg_check_v2(const struct xt_tgchk_param *par) 3045474f57fSPablo Neira Ayuso { 3055474f57fSPablo Neira Ayuso struct xt_ct_target_info_v1 *info = par->targinfo; 3065474f57fSPablo Neira Ayuso 3075474f57fSPablo Neira Ayuso if (info->flags & ~XT_CT_MASK) 3085474f57fSPablo Neira Ayuso return -EINVAL; 3095474f57fSPablo Neira Ayuso 310d52ed437SPablo Neira Ayuso return xt_ct_tg_check(par, par->targinfo); 31184f3bb9aSPatrick McHardy } 31284f3bb9aSPatrick McHardy 313236df005SPablo Neira Ayuso static void xt_ct_destroy_timeout(struct nf_conn *ct) 31424de58f4SPablo Neira Ayuso { 31524de58f4SPablo Neira Ayuso #ifdef CONFIG_NF_CONNTRACK_TIMEOUT 31624de58f4SPablo Neira Ayuso struct nf_conn_timeout *timeout_ext; 31724de58f4SPablo Neira Ayuso typeof(nf_ct_timeout_put_hook) timeout_put; 31824de58f4SPablo Neira Ayuso 3191ac0bf99SPablo Neira Ayuso rcu_read_lock(); 32024de58f4SPablo Neira Ayuso timeout_put = rcu_dereference(nf_ct_timeout_put_hook); 32124de58f4SPablo Neira Ayuso 32224de58f4SPablo Neira Ayuso if (timeout_put) { 32324de58f4SPablo Neira Ayuso timeout_ext = nf_ct_timeout_find(ct); 324ae2d708eSPablo Neira Ayuso if (timeout_ext) { 32524de58f4SPablo Neira Ayuso timeout_put(timeout_ext->timeout); 326ae2d708eSPablo Neira Ayuso RCU_INIT_POINTER(timeout_ext->timeout, NULL); 327ae2d708eSPablo Neira Ayuso } 32824de58f4SPablo Neira Ayuso } 3291ac0bf99SPablo Neira Ayuso rcu_read_unlock(); 33024de58f4SPablo Neira Ayuso #endif 33124de58f4SPablo Neira Ayuso } 332236df005SPablo Neira Ayuso 333d52ed437SPablo Neira Ayuso static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par, 334d52ed437SPablo Neira Ayuso struct xt_ct_target_info_v1 *info) 335236df005SPablo Neira Ayuso { 336236df005SPablo Neira Ayuso struct nf_conn *ct = info->ct; 337236df005SPablo Neira Ayuso struct nf_conn_help *help; 338236df005SPablo Neira Ayuso 339cc41c84bSFlorian Westphal if (ct) { 340236df005SPablo Neira Ayuso help = nfct_help(ct); 341236df005SPablo Neira Ayuso if (help) 342236df005SPablo Neira Ayuso module_put(help->helper->me); 343236df005SPablo Neira Ayuso 344ecb2421bSFlorian Westphal nf_ct_netns_put(par->net, par->family); 345236df005SPablo Neira Ayuso 346236df005SPablo Neira Ayuso xt_ct_destroy_timeout(ct); 34724de58f4SPablo Neira Ayuso nf_ct_put(info->ct); 34824de58f4SPablo Neira Ayuso } 34927e7190eSEric Dumazet } 35024de58f4SPablo Neira Ayuso 351d52ed437SPablo Neira Ayuso static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par) 352d52ed437SPablo Neira Ayuso { 353d52ed437SPablo Neira Ayuso struct xt_ct_target_info *info = par->targinfo; 354d52ed437SPablo Neira Ayuso struct xt_ct_target_info_v1 info_v1 = { 355d52ed437SPablo Neira Ayuso .flags = info->flags, 356d52ed437SPablo Neira Ayuso .zone = info->zone, 357d52ed437SPablo Neira Ayuso .ct_events = info->ct_events, 358d52ed437SPablo Neira Ayuso .exp_events = info->exp_events, 359d52ed437SPablo Neira Ayuso .ct = info->ct, 360d52ed437SPablo Neira Ayuso }; 361d52ed437SPablo Neira Ayuso memcpy(info_v1.helper, info->helper, sizeof(info->helper)); 362d52ed437SPablo Neira Ayuso 363d52ed437SPablo Neira Ayuso xt_ct_tg_destroy(par, &info_v1); 364d52ed437SPablo Neira Ayuso } 365d52ed437SPablo Neira Ayuso 366d52ed437SPablo Neira Ayuso static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par) 367d52ed437SPablo Neira Ayuso { 368d52ed437SPablo Neira Ayuso xt_ct_tg_destroy(par, par->targinfo); 369d52ed437SPablo Neira Ayuso } 370d52ed437SPablo Neira Ayuso 37124de58f4SPablo Neira Ayuso static struct xt_target xt_ct_tg_reg[] __read_mostly = { 37224de58f4SPablo Neira Ayuso { 37384f3bb9aSPatrick McHardy .name = "CT", 37484f3bb9aSPatrick McHardy .family = NFPROTO_UNSPEC, 3757d5f7ed8SJan Engelhardt .targetsize = sizeof(struct xt_ct_target_info), 376ec231890SWillem de Bruijn .usersize = offsetof(struct xt_ct_target_info, ct), 37724de58f4SPablo Neira Ayuso .checkentry = xt_ct_tg_check_v0, 37824de58f4SPablo Neira Ayuso .destroy = xt_ct_tg_destroy_v0, 37924de58f4SPablo Neira Ayuso .target = xt_ct_target_v0, 38084f3bb9aSPatrick McHardy .table = "raw", 38184f3bb9aSPatrick McHardy .me = THIS_MODULE, 38224de58f4SPablo Neira Ayuso }, 38324de58f4SPablo Neira Ayuso { 38424de58f4SPablo Neira Ayuso .name = "CT", 38524de58f4SPablo Neira Ayuso .family = NFPROTO_UNSPEC, 38624de58f4SPablo Neira Ayuso .revision = 1, 38724de58f4SPablo Neira Ayuso .targetsize = sizeof(struct xt_ct_target_info_v1), 388ec231890SWillem de Bruijn .usersize = offsetof(struct xt_ct_target_info, ct), 38924de58f4SPablo Neira Ayuso .checkentry = xt_ct_tg_check_v1, 39024de58f4SPablo Neira Ayuso .destroy = xt_ct_tg_destroy_v1, 39124de58f4SPablo Neira Ayuso .target = xt_ct_target_v1, 39224de58f4SPablo Neira Ayuso .table = "raw", 39324de58f4SPablo Neira Ayuso .me = THIS_MODULE, 39424de58f4SPablo Neira Ayuso }, 3955474f57fSPablo Neira Ayuso { 3965474f57fSPablo Neira Ayuso .name = "CT", 3975474f57fSPablo Neira Ayuso .family = NFPROTO_UNSPEC, 3985474f57fSPablo Neira Ayuso .revision = 2, 3995474f57fSPablo Neira Ayuso .targetsize = sizeof(struct xt_ct_target_info_v1), 400ec231890SWillem de Bruijn .usersize = offsetof(struct xt_ct_target_info, ct), 4015474f57fSPablo Neira Ayuso .checkentry = xt_ct_tg_check_v2, 4025474f57fSPablo Neira Ayuso .destroy = xt_ct_tg_destroy_v1, 4035474f57fSPablo Neira Ayuso .target = xt_ct_target_v1, 4045474f57fSPablo Neira Ayuso .table = "raw", 4055474f57fSPablo Neira Ayuso .me = THIS_MODULE, 4065474f57fSPablo Neira Ayuso }, 40784f3bb9aSPatrick McHardy }; 40884f3bb9aSPatrick McHardy 40910db9069SPablo Neira Ayuso static unsigned int 41010db9069SPablo Neira Ayuso notrack_tg(struct sk_buff *skb, const struct xt_action_param *par) 41110db9069SPablo Neira Ayuso { 41210db9069SPablo Neira Ayuso /* Previously seen (loopback)? Ignore. */ 413a9e419dcSFlorian Westphal if (skb->_nfct != 0) 41410db9069SPablo Neira Ayuso return XT_CONTINUE; 41510db9069SPablo Neira Ayuso 416cc41c84bSFlorian Westphal nf_ct_set(skb, NULL, IP_CT_UNTRACKED); 41710db9069SPablo Neira Ayuso 41810db9069SPablo Neira Ayuso return XT_CONTINUE; 41910db9069SPablo Neira Ayuso } 42010db9069SPablo Neira Ayuso 42110db9069SPablo Neira Ayuso static int notrack_chk(const struct xt_tgchk_param *par) 42210db9069SPablo Neira Ayuso { 42310db9069SPablo Neira Ayuso if (!par->net->xt.notrack_deprecated_warning) { 42410db9069SPablo Neira Ayuso pr_info("netfilter: NOTRACK target is deprecated, " 42510db9069SPablo Neira Ayuso "use CT instead or upgrade iptables\n"); 42610db9069SPablo Neira Ayuso par->net->xt.notrack_deprecated_warning = true; 42710db9069SPablo Neira Ayuso } 42810db9069SPablo Neira Ayuso return 0; 42910db9069SPablo Neira Ayuso } 43010db9069SPablo Neira Ayuso 43110db9069SPablo Neira Ayuso static struct xt_target notrack_tg_reg __read_mostly = { 43210db9069SPablo Neira Ayuso .name = "NOTRACK", 43310db9069SPablo Neira Ayuso .revision = 0, 43410db9069SPablo Neira Ayuso .family = NFPROTO_UNSPEC, 43510db9069SPablo Neira Ayuso .checkentry = notrack_chk, 43610db9069SPablo Neira Ayuso .target = notrack_tg, 43710db9069SPablo Neira Ayuso .table = "raw", 43810db9069SPablo Neira Ayuso .me = THIS_MODULE, 43910db9069SPablo Neira Ayuso }; 44010db9069SPablo Neira Ayuso 44184f3bb9aSPatrick McHardy static int __init xt_ct_tg_init(void) 44284f3bb9aSPatrick McHardy { 44310db9069SPablo Neira Ayuso int ret; 44410db9069SPablo Neira Ayuso 44510db9069SPablo Neira Ayuso ret = xt_register_target(¬rack_tg_reg); 44610db9069SPablo Neira Ayuso if (ret < 0) 44710db9069SPablo Neira Ayuso return ret; 44810db9069SPablo Neira Ayuso 44910db9069SPablo Neira Ayuso ret = xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg)); 45010db9069SPablo Neira Ayuso if (ret < 0) { 45110db9069SPablo Neira Ayuso xt_unregister_target(¬rack_tg_reg); 45210db9069SPablo Neira Ayuso return ret; 45310db9069SPablo Neira Ayuso } 45410db9069SPablo Neira Ayuso return 0; 45584f3bb9aSPatrick McHardy } 45684f3bb9aSPatrick McHardy 45784f3bb9aSPatrick McHardy static void __exit xt_ct_tg_exit(void) 45884f3bb9aSPatrick McHardy { 45924de58f4SPablo Neira Ayuso xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg)); 46010db9069SPablo Neira Ayuso xt_unregister_target(¬rack_tg_reg); 46184f3bb9aSPatrick McHardy } 46284f3bb9aSPatrick McHardy 46384f3bb9aSPatrick McHardy module_init(xt_ct_tg_init); 46484f3bb9aSPatrick McHardy module_exit(xt_ct_tg_exit); 46584f3bb9aSPatrick McHardy 46684f3bb9aSPatrick McHardy MODULE_LICENSE("GPL"); 46784f3bb9aSPatrick McHardy MODULE_DESCRIPTION("Xtables: connection tracking target"); 46884f3bb9aSPatrick McHardy MODULE_ALIAS("ipt_CT"); 46984f3bb9aSPatrick McHardy MODULE_ALIAS("ip6t_CT"); 47010db9069SPablo Neira Ayuso MODULE_ALIAS("ipt_NOTRACK"); 47110db9069SPablo Neira Ayuso MODULE_ALIAS("ip6t_NOTRACK"); 472