at v3.6-rc3 404 lines 9.4 kB view raw
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_l4proto.h> 18#include <net/netfilter/nf_conntrack_helper.h> 19#include <net/netfilter/nf_conntrack_ecache.h> 20#include <net/netfilter/nf_conntrack_timeout.h> 21#include <net/netfilter/nf_conntrack_zones.h> 22 23static 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 40static 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 57static 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 75static 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 struct nf_conntrack_helper *helper; 116 117 ret = -ENOENT; 118 proto = xt_ct_find_proto(par); 119 if (!proto) { 120 pr_info("You must specify a L4 protocol, " 121 "and not use inversions on it.\n"); 122 goto err3; 123 } 124 125 ret = -ENOENT; 126 helper = nf_conntrack_helper_try_module_get(info->helper, 127 par->family, 128 proto); 129 if (helper == NULL) { 130 pr_info("No such helper \"%s\"\n", info->helper); 131 goto err3; 132 } 133 134 ret = -ENOMEM; 135 help = nf_ct_helper_ext_add(ct, helper, GFP_KERNEL); 136 if (help == NULL) 137 goto err3; 138 139 help->helper = helper; 140 } 141 142 __set_bit(IPS_TEMPLATE_BIT, &ct->status); 143 __set_bit(IPS_CONFIRMED_BIT, &ct->status); 144out: 145 info->ct = ct; 146 return 0; 147 148err3: 149 nf_conntrack_free(ct); 150err2: 151 nf_ct_l3proto_module_put(par->family); 152err1: 153 return ret; 154} 155 156#ifdef CONFIG_NF_CONNTRACK_TIMEOUT 157static void __xt_ct_tg_timeout_put(struct ctnl_timeout *timeout) 158{ 159 typeof(nf_ct_timeout_put_hook) timeout_put; 160 161 timeout_put = rcu_dereference(nf_ct_timeout_put_hook); 162 if (timeout_put) 163 timeout_put(timeout); 164} 165#endif 166 167static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) 168{ 169 struct xt_ct_target_info_v1 *info = par->targinfo; 170 struct nf_conntrack_tuple t; 171 struct nf_conn_help *help; 172 struct nf_conn *ct; 173 int ret = 0; 174 u8 proto; 175#ifdef CONFIG_NF_CONNTRACK_TIMEOUT 176 struct ctnl_timeout *timeout; 177#endif 178 if (info->flags & ~XT_CT_NOTRACK) 179 return -EINVAL; 180 181 if (info->flags & XT_CT_NOTRACK) { 182 ct = nf_ct_untracked_get(); 183 atomic_inc(&ct->ct_general.use); 184 goto out; 185 } 186 187#ifndef CONFIG_NF_CONNTRACK_ZONES 188 if (info->zone) 189 goto err1; 190#endif 191 192 ret = nf_ct_l3proto_try_module_get(par->family); 193 if (ret < 0) 194 goto err1; 195 196 memset(&t, 0, sizeof(t)); 197 ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL); 198 ret = PTR_ERR(ct); 199 if (IS_ERR(ct)) 200 goto err2; 201 202 ret = 0; 203 if ((info->ct_events || info->exp_events) && 204 !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events, 205 GFP_KERNEL)) 206 goto err3; 207 208 if (info->helper[0]) { 209 struct nf_conntrack_helper *helper; 210 211 ret = -ENOENT; 212 proto = xt_ct_find_proto(par); 213 if (!proto) { 214 pr_info("You must specify a L4 protocol, " 215 "and not use inversions on it.\n"); 216 goto err3; 217 } 218 219 ret = -ENOENT; 220 helper = nf_conntrack_helper_try_module_get(info->helper, 221 par->family, 222 proto); 223 if (helper == NULL) { 224 pr_info("No such helper \"%s\"\n", info->helper); 225 goto err3; 226 } 227 228 ret = -ENOMEM; 229 help = nf_ct_helper_ext_add(ct, helper, GFP_KERNEL); 230 if (help == NULL) 231 goto err3; 232 233 help->helper = helper; 234 } 235 236#ifdef CONFIG_NF_CONNTRACK_TIMEOUT 237 if (info->timeout[0]) { 238 typeof(nf_ct_timeout_find_get_hook) timeout_find_get; 239 struct nf_conn_timeout *timeout_ext; 240 241 rcu_read_lock(); 242 timeout_find_get = 243 rcu_dereference(nf_ct_timeout_find_get_hook); 244 245 if (timeout_find_get) { 246 const struct ipt_entry *e = par->entryinfo; 247 struct nf_conntrack_l4proto *l4proto; 248 249 if (e->ip.invflags & IPT_INV_PROTO) { 250 ret = -EINVAL; 251 pr_info("You cannot use inversion on " 252 "L4 protocol\n"); 253 goto err4; 254 } 255 timeout = timeout_find_get(info->timeout); 256 if (timeout == NULL) { 257 ret = -ENOENT; 258 pr_info("No such timeout policy \"%s\"\n", 259 info->timeout); 260 goto err4; 261 } 262 if (timeout->l3num != par->family) { 263 ret = -EINVAL; 264 pr_info("Timeout policy `%s' can only be " 265 "used by L3 protocol number %d\n", 266 info->timeout, timeout->l3num); 267 goto err5; 268 } 269 /* Make sure the timeout policy matches any existing 270 * protocol tracker, otherwise default to generic. 271 */ 272 l4proto = __nf_ct_l4proto_find(par->family, 273 e->ip.proto); 274 if (timeout->l4proto->l4proto != l4proto->l4proto) { 275 ret = -EINVAL; 276 pr_info("Timeout policy `%s' can only be " 277 "used by L4 protocol number %d\n", 278 info->timeout, 279 timeout->l4proto->l4proto); 280 goto err5; 281 } 282 timeout_ext = nf_ct_timeout_ext_add(ct, timeout, 283 GFP_ATOMIC); 284 if (timeout_ext == NULL) { 285 ret = -ENOMEM; 286 goto err5; 287 } 288 } else { 289 ret = -ENOENT; 290 pr_info("Timeout policy base is empty\n"); 291 goto err4; 292 } 293 rcu_read_unlock(); 294 } 295#endif 296 297 __set_bit(IPS_TEMPLATE_BIT, &ct->status); 298 __set_bit(IPS_CONFIRMED_BIT, &ct->status); 299out: 300 info->ct = ct; 301 return 0; 302 303#ifdef CONFIG_NF_CONNTRACK_TIMEOUT 304err5: 305 __xt_ct_tg_timeout_put(timeout); 306err4: 307 rcu_read_unlock(); 308#endif 309err3: 310 nf_conntrack_free(ct); 311err2: 312 nf_ct_l3proto_module_put(par->family); 313err1: 314 return ret; 315} 316 317static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par) 318{ 319 struct xt_ct_target_info *info = par->targinfo; 320 struct nf_conn *ct = info->ct; 321 struct nf_conn_help *help; 322 323 if (!nf_ct_is_untracked(ct)) { 324 help = nfct_help(ct); 325 if (help) 326 module_put(help->helper->me); 327 328 nf_ct_l3proto_module_put(par->family); 329 } 330 nf_ct_put(info->ct); 331} 332 333static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par) 334{ 335 struct xt_ct_target_info_v1 *info = par->targinfo; 336 struct nf_conn *ct = info->ct; 337 struct nf_conn_help *help; 338#ifdef CONFIG_NF_CONNTRACK_TIMEOUT 339 struct nf_conn_timeout *timeout_ext; 340 typeof(nf_ct_timeout_put_hook) timeout_put; 341#endif 342 if (!nf_ct_is_untracked(ct)) { 343 help = nfct_help(ct); 344 if (help) 345 module_put(help->helper->me); 346 347 nf_ct_l3proto_module_put(par->family); 348 349#ifdef CONFIG_NF_CONNTRACK_TIMEOUT 350 rcu_read_lock(); 351 timeout_put = rcu_dereference(nf_ct_timeout_put_hook); 352 353 if (timeout_put) { 354 timeout_ext = nf_ct_timeout_find(ct); 355 if (timeout_ext) 356 timeout_put(timeout_ext->timeout); 357 } 358 rcu_read_unlock(); 359#endif 360 } 361 nf_ct_put(info->ct); 362} 363 364static struct xt_target xt_ct_tg_reg[] __read_mostly = { 365 { 366 .name = "CT", 367 .family = NFPROTO_UNSPEC, 368 .targetsize = sizeof(struct xt_ct_target_info), 369 .checkentry = xt_ct_tg_check_v0, 370 .destroy = xt_ct_tg_destroy_v0, 371 .target = xt_ct_target_v0, 372 .table = "raw", 373 .me = THIS_MODULE, 374 }, 375 { 376 .name = "CT", 377 .family = NFPROTO_UNSPEC, 378 .revision = 1, 379 .targetsize = sizeof(struct xt_ct_target_info_v1), 380 .checkentry = xt_ct_tg_check_v1, 381 .destroy = xt_ct_tg_destroy_v1, 382 .target = xt_ct_target_v1, 383 .table = "raw", 384 .me = THIS_MODULE, 385 }, 386}; 387 388static int __init xt_ct_tg_init(void) 389{ 390 return xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg)); 391} 392 393static void __exit xt_ct_tg_exit(void) 394{ 395 xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg)); 396} 397 398module_init(xt_ct_tg_init); 399module_exit(xt_ct_tg_exit); 400 401MODULE_LICENSE("GPL"); 402MODULE_DESCRIPTION("Xtables: connection tracking target"); 403MODULE_ALIAS("ipt_CT"); 404MODULE_ALIAS("ip6t_CT");