1/* 2 * Copyright (c) 2010 Patrick McHardy <kaber@trash.net> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9#include <linux/module.h> 10#include <linux/gfp.h> 11#include <linux/skbuff.h> 12#include <linux/selinux.h> 13#include <linux/netfilter_ipv4/ip_tables.h> 14#include <linux/netfilter_ipv6/ip6_tables.h> 15#include <linux/netfilter/x_tables.h> 16#include <linux/netfilter/xt_CT.h> 17#include <net/netfilter/nf_conntrack.h> 18#include <net/netfilter/nf_conntrack_helper.h> 19#include <net/netfilter/nf_conntrack_ecache.h> 20#include <net/netfilter/nf_conntrack_zones.h> 21 22static unsigned int xt_ct_target(struct sk_buff *skb, 23 const struct xt_action_param *par) 24{ 25 const struct xt_ct_target_info *info = par->targinfo; 26 struct nf_conn *ct = info->ct; 27 28 /* Previously seen (loopback)? Ignore. */ 29 if (skb->nfct != NULL) 30 return XT_CONTINUE; 31 32 atomic_inc(&ct->ct_general.use); 33 skb->nfct = &ct->ct_general; 34 skb->nfctinfo = IP_CT_NEW; 35 36 return XT_CONTINUE; 37} 38 39static u8 xt_ct_find_proto(const struct xt_tgchk_param *par) 40{ 41 if (par->family == NFPROTO_IPV4) { 42 const struct ipt_entry *e = par->entryinfo; 43 44 if (e->ip.invflags & IPT_INV_PROTO) 45 return 0; 46 return e->ip.proto; 47 } else if (par->family == NFPROTO_IPV6) { 48 const struct ip6t_entry *e = par->entryinfo; 49 50 if (e->ipv6.invflags & IP6T_INV_PROTO) 51 return 0; 52 return e->ipv6.proto; 53 } else 54 return 0; 55} 56 57static int xt_ct_tg_check(const struct xt_tgchk_param *par) 58{ 59 struct xt_ct_target_info *info = par->targinfo; 60 struct nf_conntrack_tuple t; 61 struct nf_conn_help *help; 62 struct nf_conn *ct; 63 int ret = 0; 64 u8 proto; 65 66 if (info->flags & ~XT_CT_NOTRACK) 67 return -EINVAL; 68 69 if (info->flags & XT_CT_NOTRACK) { 70 ct = nf_ct_untracked_get(); 71 atomic_inc(&ct->ct_general.use); 72 goto out; 73 } 74 75#ifndef CONFIG_NF_CONNTRACK_ZONES 76 if (info->zone) 77 goto err1; 78#endif 79 80 ret = nf_ct_l3proto_try_module_get(par->family); 81 if (ret < 0) 82 goto err1; 83 84 memset(&t, 0, sizeof(t)); 85 ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL); 86 ret = PTR_ERR(ct); 87 if (IS_ERR(ct)) 88 goto err2; 89 90 ret = 0; 91 if ((info->ct_events || info->exp_events) && 92 !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events, 93 GFP_KERNEL)) 94 goto err3; 95 96 if (info->helper[0]) { 97 ret = -ENOENT; 98 proto = xt_ct_find_proto(par); 99 if (!proto) 100 goto err3; 101 102 ret = -ENOMEM; 103 help = nf_ct_helper_ext_add(ct, GFP_KERNEL); 104 if (help == NULL) 105 goto err3; 106 107 ret = -ENOENT; 108 help->helper = nf_conntrack_helper_try_module_get(info->helper, 109 par->family, 110 proto); 111 if (help->helper == NULL) 112 goto err3; 113 } 114 115 __set_bit(IPS_TEMPLATE_BIT, &ct->status); 116 __set_bit(IPS_CONFIRMED_BIT, &ct->status); 117out: 118 info->ct = ct; 119 return 0; 120 121err3: 122 nf_conntrack_free(ct); 123err2: 124 nf_ct_l3proto_module_put(par->family); 125err1: 126 return ret; 127} 128 129static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par) 130{ 131 struct xt_ct_target_info *info = par->targinfo; 132 struct nf_conn *ct = info->ct; 133 struct nf_conn_help *help; 134 135 if (!nf_ct_is_untracked(ct)) { 136 help = nfct_help(ct); 137 if (help) 138 module_put(help->helper->me); 139 140 nf_ct_l3proto_module_put(par->family); 141 } 142 nf_ct_put(info->ct); 143} 144 145static struct xt_target xt_ct_tg __read_mostly = { 146 .name = "CT", 147 .family = NFPROTO_UNSPEC, 148 .targetsize = sizeof(struct xt_ct_target_info), 149 .checkentry = xt_ct_tg_check, 150 .destroy = xt_ct_tg_destroy, 151 .target = xt_ct_target, 152 .table = "raw", 153 .me = THIS_MODULE, 154}; 155 156static int __init xt_ct_tg_init(void) 157{ 158 return xt_register_target(&xt_ct_tg); 159} 160 161static void __exit xt_ct_tg_exit(void) 162{ 163 xt_unregister_target(&xt_ct_tg); 164} 165 166module_init(xt_ct_tg_init); 167module_exit(xt_ct_tg_exit); 168 169MODULE_LICENSE("GPL"); 170MODULE_DESCRIPTION("Xtables: connection tracking target"); 171MODULE_ALIAS("ipt_CT"); 172MODULE_ALIAS("ip6t_CT"); 173