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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9 #include <linux/module.h> 10 #include <linux/gfp.h> 11 #include <linux/skbuff.h> 12 #include <linux/netfilter_ipv4/ip_tables.h> 13 #include <linux/netfilter_ipv6/ip6_tables.h> 14 #include <linux/netfilter/x_tables.h> 15 #include <linux/netfilter/xt_CT.h> 16 #include <net/netfilter/nf_conntrack.h> 17 #include <net/netfilter/nf_conntrack_helper.h> 18 #include <net/netfilter/nf_conntrack_ecache.h> 19 #include <net/netfilter/nf_conntrack_l4proto.h> 20 #include <net/netfilter/nf_conntrack_timeout.h> 21 #include <net/netfilter/nf_conntrack_zones.h> 22 23 static unsigned int xt_ct_target_v0(struct sk_buff *skb, 24 const struct xt_action_param *par) 25 { 26 const struct xt_ct_target_info *info = par->targinfo; 27 struct nf_conn *ct = info->ct; 28 29 /* Previously seen (loopback)? Ignore. */ 30 if (skb->nfct != NULL) 31 return XT_CONTINUE; 32 33 atomic_inc(&ct->ct_general.use); 34 skb->nfct = &ct->ct_general; 35 skb->nfctinfo = IP_CT_NEW; 36 37 return XT_CONTINUE; 38 } 39 40 static unsigned int xt_ct_target_v1(struct sk_buff *skb, 41 const struct xt_action_param *par) 42 { 43 const struct xt_ct_target_info_v1 *info = par->targinfo; 44 struct nf_conn *ct = info->ct; 45 46 /* Previously seen (loopback)? Ignore. */ 47 if (skb->nfct != NULL) 48 return XT_CONTINUE; 49 50 atomic_inc(&ct->ct_general.use); 51 skb->nfct = &ct->ct_general; 52 skb->nfctinfo = IP_CT_NEW; 53 54 return XT_CONTINUE; 55 } 56 57 static u8 xt_ct_find_proto(const struct xt_tgchk_param *par) 58 { 59 if (par->family == NFPROTO_IPV4) { 60 const struct ipt_entry *e = par->entryinfo; 61 62 if (e->ip.invflags & IPT_INV_PROTO) 63 return 0; 64 return e->ip.proto; 65 } else if (par->family == NFPROTO_IPV6) { 66 const struct ip6t_entry *e = par->entryinfo; 67 68 if (e->ipv6.invflags & IP6T_INV_PROTO) 69 return 0; 70 return e->ipv6.proto; 71 } else 72 return 0; 73 } 74 75 static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par) 76 { 77 struct xt_ct_target_info *info = par->targinfo; 78 struct nf_conntrack_tuple t; 79 struct nf_conn_help *help; 80 struct nf_conn *ct; 81 int ret = 0; 82 u8 proto; 83 84 if (info->flags & ~XT_CT_NOTRACK) 85 return -EINVAL; 86 87 if (info->flags & XT_CT_NOTRACK) { 88 ct = nf_ct_untracked_get(); 89 atomic_inc(&ct->ct_general.use); 90 goto out; 91 } 92 93 #ifndef CONFIG_NF_CONNTRACK_ZONES 94 if (info->zone) 95 goto err1; 96 #endif 97 98 ret = nf_ct_l3proto_try_module_get(par->family); 99 if (ret < 0) 100 goto err1; 101 102 memset(&t, 0, sizeof(t)); 103 ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL); 104 ret = PTR_ERR(ct); 105 if (IS_ERR(ct)) 106 goto err2; 107 108 ret = 0; 109 if ((info->ct_events || info->exp_events) && 110 !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events, 111 GFP_KERNEL)) 112 goto err3; 113 114 if (info->helper[0]) { 115 ret = -ENOENT; 116 proto = xt_ct_find_proto(par); 117 if (!proto) { 118 pr_info("You must specify a L4 protocol, " 119 "and not use inversions on it.\n"); 120 goto err3; 121 } 122 123 ret = -ENOMEM; 124 help = nf_ct_helper_ext_add(ct, GFP_KERNEL); 125 if (help == NULL) 126 goto err3; 127 128 ret = -ENOENT; 129 help->helper = nf_conntrack_helper_try_module_get(info->helper, 130 par->family, 131 proto); 132 if (help->helper == NULL) { 133 pr_info("No such helper \"%s\"\n", info->helper); 134 goto err3; 135 } 136 } 137 138 __set_bit(IPS_TEMPLATE_BIT, &ct->status); 139 __set_bit(IPS_CONFIRMED_BIT, &ct->status); 140 out: 141 info->ct = ct; 142 return 0; 143 144 err3: 145 nf_conntrack_free(ct); 146 err2: 147 nf_ct_l3proto_module_put(par->family); 148 err1: 149 return ret; 150 } 151 152 static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) 153 { 154 struct xt_ct_target_info_v1 *info = par->targinfo; 155 struct nf_conntrack_tuple t; 156 struct nf_conn_help *help; 157 struct nf_conn *ct; 158 int ret = 0; 159 u8 proto; 160 161 if (info->flags & ~XT_CT_NOTRACK) 162 return -EINVAL; 163 164 if (info->flags & XT_CT_NOTRACK) { 165 ct = nf_ct_untracked_get(); 166 atomic_inc(&ct->ct_general.use); 167 goto out; 168 } 169 170 #ifndef CONFIG_NF_CONNTRACK_ZONES 171 if (info->zone) 172 goto err1; 173 #endif 174 175 ret = nf_ct_l3proto_try_module_get(par->family); 176 if (ret < 0) 177 goto err1; 178 179 memset(&t, 0, sizeof(t)); 180 ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL); 181 ret = PTR_ERR(ct); 182 if (IS_ERR(ct)) 183 goto err2; 184 185 ret = 0; 186 if ((info->ct_events || info->exp_events) && 187 !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events, 188 GFP_KERNEL)) 189 goto err3; 190 191 if (info->helper[0]) { 192 ret = -ENOENT; 193 proto = xt_ct_find_proto(par); 194 if (!proto) { 195 pr_info("You must specify a L4 protocol, " 196 "and not use inversions on it.\n"); 197 goto err3; 198 } 199 200 ret = -ENOMEM; 201 help = nf_ct_helper_ext_add(ct, GFP_KERNEL); 202 if (help == NULL) 203 goto err3; 204 205 ret = -ENOENT; 206 help->helper = nf_conntrack_helper_try_module_get(info->helper, 207 par->family, 208 proto); 209 if (help->helper == NULL) { 210 pr_info("No such helper \"%s\"\n", info->helper); 211 goto err3; 212 } 213 } 214 215 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT 216 if (info->timeout) { 217 typeof(nf_ct_timeout_find_get_hook) timeout_find_get; 218 struct ctnl_timeout *timeout; 219 struct nf_conn_timeout *timeout_ext; 220 221 rcu_read_lock(); 222 timeout_find_get = 223 rcu_dereference(nf_ct_timeout_find_get_hook); 224 225 if (timeout_find_get) { 226 const struct ipt_entry *e = par->entryinfo; 227 228 if (e->ip.invflags & IPT_INV_PROTO) { 229 ret = -EINVAL; 230 pr_info("You cannot use inversion on " 231 "L4 protocol\n"); 232 goto err4; 233 } 234 timeout = timeout_find_get(info->timeout); 235 if (timeout == NULL) { 236 ret = -ENOENT; 237 pr_info("No such timeout policy \"%s\"\n", 238 info->timeout); 239 goto err4; 240 } 241 if (timeout->l3num != par->family) { 242 ret = -EINVAL; 243 pr_info("Timeout policy `%s' can only be " 244 "used by L3 protocol number %d\n", 245 info->timeout, timeout->l3num); 246 goto err4; 247 } 248 if (timeout->l4proto->l4proto != e->ip.proto) { 249 ret = -EINVAL; 250 pr_info("Timeout policy `%s' can only be " 251 "used by L4 protocol number %d\n", 252 info->timeout, 253 timeout->l4proto->l4proto); 254 goto err4; 255 } 256 timeout_ext = nf_ct_timeout_ext_add(ct, timeout, 257 GFP_KERNEL); 258 if (timeout_ext == NULL) { 259 ret = -ENOMEM; 260 goto err4; 261 } 262 } else { 263 ret = -ENOENT; 264 pr_info("Timeout policy base is empty\n"); 265 goto err4; 266 } 267 rcu_read_unlock(); 268 } 269 #endif 270 271 __set_bit(IPS_TEMPLATE_BIT, &ct->status); 272 __set_bit(IPS_CONFIRMED_BIT, &ct->status); 273 out: 274 info->ct = ct; 275 return 0; 276 277 err4: 278 rcu_read_unlock(); 279 err3: 280 nf_conntrack_free(ct); 281 err2: 282 nf_ct_l3proto_module_put(par->family); 283 err1: 284 return ret; 285 } 286 287 static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par) 288 { 289 struct xt_ct_target_info *info = par->targinfo; 290 struct nf_conn *ct = info->ct; 291 struct nf_conn_help *help; 292 293 if (!nf_ct_is_untracked(ct)) { 294 help = nfct_help(ct); 295 if (help) 296 module_put(help->helper->me); 297 298 nf_ct_l3proto_module_put(par->family); 299 } 300 nf_ct_put(info->ct); 301 } 302 303 static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par) 304 { 305 struct xt_ct_target_info_v1 *info = par->targinfo; 306 struct nf_conn *ct = info->ct; 307 struct nf_conn_help *help; 308 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT 309 struct nf_conn_timeout *timeout_ext; 310 typeof(nf_ct_timeout_put_hook) timeout_put; 311 #endif 312 if (!nf_ct_is_untracked(ct)) { 313 help = nfct_help(ct); 314 if (help) 315 module_put(help->helper->me); 316 317 nf_ct_l3proto_module_put(par->family); 318 319 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT 320 rcu_read_lock(); 321 timeout_put = rcu_dereference(nf_ct_timeout_put_hook); 322 323 if (timeout_put) { 324 timeout_ext = nf_ct_timeout_find(ct); 325 if (timeout_ext) 326 timeout_put(timeout_ext->timeout); 327 } 328 rcu_read_unlock(); 329 #endif 330 } 331 nf_ct_put(info->ct); 332 } 333 334 static struct xt_target xt_ct_tg_reg[] __read_mostly = { 335 { 336 .name = "CT", 337 .family = NFPROTO_UNSPEC, 338 .targetsize = sizeof(struct xt_ct_target_info), 339 .checkentry = xt_ct_tg_check_v0, 340 .destroy = xt_ct_tg_destroy_v0, 341 .target = xt_ct_target_v0, 342 .table = "raw", 343 .me = THIS_MODULE, 344 }, 345 { 346 .name = "CT", 347 .family = NFPROTO_UNSPEC, 348 .revision = 1, 349 .targetsize = sizeof(struct xt_ct_target_info_v1), 350 .checkentry = xt_ct_tg_check_v1, 351 .destroy = xt_ct_tg_destroy_v1, 352 .target = xt_ct_target_v1, 353 .table = "raw", 354 .me = THIS_MODULE, 355 }, 356 }; 357 358 static int __init xt_ct_tg_init(void) 359 { 360 return xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg)); 361 } 362 363 static void __exit xt_ct_tg_exit(void) 364 { 365 xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg)); 366 } 367 368 module_init(xt_ct_tg_init); 369 module_exit(xt_ct_tg_exit); 370 371 MODULE_LICENSE("GPL"); 372 MODULE_DESCRIPTION("Xtables: connection tracking target"); 373 MODULE_ALIAS("ipt_CT"); 374 MODULE_ALIAS("ip6t_CT"); 375