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