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 inline int xt_ct_target(struct sk_buff *skb, struct nf_conn *ct) 24{ 25 /* Previously seen (loopback)? Ignore. */ 26 if (skb->nfct != NULL) 27 return XT_CONTINUE; 28 29 atomic_inc(&ct->ct_general.use); 30 skb->nfct = &ct->ct_general; 31 skb->nfctinfo = IP_CT_NEW; 32 33 return XT_CONTINUE; 34} 35 36static unsigned int xt_ct_target_v0(struct sk_buff *skb, 37 const struct xt_action_param *par) 38{ 39 const struct xt_ct_target_info *info = par->targinfo; 40 struct nf_conn *ct = info->ct; 41 42 return xt_ct_target(skb, ct); 43} 44 45static unsigned int xt_ct_target_v1(struct sk_buff *skb, 46 const struct xt_action_param *par) 47{ 48 const struct xt_ct_target_info_v1 *info = par->targinfo; 49 struct nf_conn *ct = info->ct; 50 51 return xt_ct_target(skb, ct); 52} 53 54static u8 xt_ct_find_proto(const struct xt_tgchk_param *par) 55{ 56 if (par->family == NFPROTO_IPV4) { 57 const struct ipt_entry *e = par->entryinfo; 58 59 if (e->ip.invflags & IPT_INV_PROTO) 60 return 0; 61 return e->ip.proto; 62 } else if (par->family == NFPROTO_IPV6) { 63 const struct ip6t_entry *e = par->entryinfo; 64 65 if (e->ipv6.invflags & IP6T_INV_PROTO) 66 return 0; 67 return e->ipv6.proto; 68 } else 69 return 0; 70} 71 72static int 73xt_ct_set_helper(struct nf_conn *ct, const char *helper_name, 74 const struct xt_tgchk_param *par) 75{ 76 struct nf_conntrack_helper *helper; 77 struct nf_conn_help *help; 78 u8 proto; 79 80 proto = xt_ct_find_proto(par); 81 if (!proto) { 82 pr_info("You must specify a L4 protocol, and not use " 83 "inversions on it.\n"); 84 return -ENOENT; 85 } 86 87 helper = nf_conntrack_helper_try_module_get(helper_name, par->family, 88 proto); 89 if (helper == NULL) { 90 pr_info("No such helper \"%s\"\n", helper_name); 91 return -ENOENT; 92 } 93 94 help = nf_ct_helper_ext_add(ct, helper, GFP_KERNEL); 95 if (help == NULL) { 96 module_put(helper->me); 97 return -ENOMEM; 98 } 99 100 help->helper = helper; 101 return 0; 102} 103 104#ifdef CONFIG_NF_CONNTRACK_TIMEOUT 105static void __xt_ct_tg_timeout_put(struct ctnl_timeout *timeout) 106{ 107 typeof(nf_ct_timeout_put_hook) timeout_put; 108 109 timeout_put = rcu_dereference(nf_ct_timeout_put_hook); 110 if (timeout_put) 111 timeout_put(timeout); 112} 113#endif 114 115static int 116xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par, 117 const char *timeout_name) 118{ 119#ifdef CONFIG_NF_CONNTRACK_TIMEOUT 120 typeof(nf_ct_timeout_find_get_hook) timeout_find_get; 121 struct ctnl_timeout *timeout; 122 struct nf_conn_timeout *timeout_ext; 123 struct nf_conntrack_l4proto *l4proto; 124 int ret = 0; 125 u8 proto; 126 127 rcu_read_lock(); 128 timeout_find_get = rcu_dereference(nf_ct_timeout_find_get_hook); 129 if (timeout_find_get == NULL) { 130 ret = -ENOENT; 131 pr_info("Timeout policy base is empty\n"); 132 goto out; 133 } 134 135 proto = xt_ct_find_proto(par); 136 if (!proto) { 137 ret = -EINVAL; 138 pr_info("You must specify a L4 protocol, and not use " 139 "inversions on it.\n"); 140 goto out; 141 } 142 143 timeout = timeout_find_get(timeout_name); 144 if (timeout == NULL) { 145 ret = -ENOENT; 146 pr_info("No such timeout policy \"%s\"\n", timeout_name); 147 goto out; 148 } 149 150 if (timeout->l3num != par->family) { 151 ret = -EINVAL; 152 pr_info("Timeout policy `%s' can only be used by L3 protocol " 153 "number %d\n", timeout_name, timeout->l3num); 154 goto err_put_timeout; 155 } 156 /* Make sure the timeout policy matches any existing protocol tracker, 157 * otherwise default to generic. 158 */ 159 l4proto = __nf_ct_l4proto_find(par->family, proto); 160 if (timeout->l4proto->l4proto != l4proto->l4proto) { 161 ret = -EINVAL; 162 pr_info("Timeout policy `%s' can only be used by L4 protocol " 163 "number %d\n", 164 timeout_name, timeout->l4proto->l4proto); 165 goto err_put_timeout; 166 } 167 timeout_ext = nf_ct_timeout_ext_add(ct, timeout, GFP_ATOMIC); 168 if (timeout_ext == NULL) 169 ret = -ENOMEM; 170 171err_put_timeout: 172 __xt_ct_tg_timeout_put(timeout); 173out: 174 rcu_read_unlock(); 175 return ret; 176#else 177 return -EOPNOTSUPP; 178#endif 179} 180 181static int xt_ct_tg_check(const struct xt_tgchk_param *par, 182 struct xt_ct_target_info_v1 *info) 183{ 184 struct nf_conntrack_tuple t; 185 struct nf_conn *ct; 186 int ret = -EOPNOTSUPP; 187 188 if (info->flags & XT_CT_NOTRACK) { 189 ct = nf_ct_untracked_get(); 190 atomic_inc(&ct->ct_general.use); 191 goto out; 192 } 193 194#ifndef CONFIG_NF_CONNTRACK_ZONES 195 if (info->zone) 196 goto err1; 197#endif 198 199 ret = nf_ct_l3proto_try_module_get(par->family); 200 if (ret < 0) 201 goto err1; 202 203 memset(&t, 0, sizeof(t)); 204 ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL); 205 ret = PTR_ERR(ct); 206 if (IS_ERR(ct)) 207 goto err2; 208 209 ret = 0; 210 if ((info->ct_events || info->exp_events) && 211 !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events, 212 GFP_KERNEL)) 213 goto err3; 214 215 if (info->helper[0]) { 216 ret = xt_ct_set_helper(ct, info->helper, par); 217 if (ret < 0) 218 goto err3; 219 } 220 221 if (info->timeout[0]) { 222 ret = xt_ct_set_timeout(ct, par, info->timeout); 223 if (ret < 0) 224 goto err3; 225 } 226 227 __set_bit(IPS_TEMPLATE_BIT, &ct->status); 228 __set_bit(IPS_CONFIRMED_BIT, &ct->status); 229 230 /* Overload tuple linked list to put us in template list. */ 231 hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, 232 &par->net->ct.tmpl); 233out: 234 info->ct = ct; 235 return 0; 236 237err3: 238 nf_conntrack_free(ct); 239err2: 240 nf_ct_l3proto_module_put(par->family); 241err1: 242 return ret; 243} 244 245static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par) 246{ 247 struct xt_ct_target_info *info = par->targinfo; 248 struct xt_ct_target_info_v1 info_v1 = { 249 .flags = info->flags, 250 .zone = info->zone, 251 .ct_events = info->ct_events, 252 .exp_events = info->exp_events, 253 }; 254 int ret; 255 256 if (info->flags & ~XT_CT_NOTRACK) 257 return -EINVAL; 258 259 memcpy(info_v1.helper, info->helper, sizeof(info->helper)); 260 261 ret = xt_ct_tg_check(par, &info_v1); 262 if (ret < 0) 263 return ret; 264 265 info->ct = info_v1.ct; 266 267 return ret; 268} 269 270static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) 271{ 272 struct xt_ct_target_info_v1 *info = par->targinfo; 273 274 if (info->flags & ~XT_CT_NOTRACK) 275 return -EINVAL; 276 277 return xt_ct_tg_check(par, par->targinfo); 278} 279 280static int xt_ct_tg_check_v2(const struct xt_tgchk_param *par) 281{ 282 struct xt_ct_target_info_v1 *info = par->targinfo; 283 284 if (info->flags & ~XT_CT_MASK) 285 return -EINVAL; 286 287 return xt_ct_tg_check(par, par->targinfo); 288} 289 290static void xt_ct_destroy_timeout(struct nf_conn *ct) 291{ 292#ifdef CONFIG_NF_CONNTRACK_TIMEOUT 293 struct nf_conn_timeout *timeout_ext; 294 typeof(nf_ct_timeout_put_hook) timeout_put; 295 296 rcu_read_lock(); 297 timeout_put = rcu_dereference(nf_ct_timeout_put_hook); 298 299 if (timeout_put) { 300 timeout_ext = nf_ct_timeout_find(ct); 301 if (timeout_ext) 302 timeout_put(timeout_ext->timeout); 303 } 304 rcu_read_unlock(); 305#endif 306} 307 308static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par, 309 struct xt_ct_target_info_v1 *info) 310{ 311 struct nf_conn *ct = info->ct; 312 struct nf_conn_help *help; 313 314 if (!nf_ct_is_untracked(ct)) { 315 help = nfct_help(ct); 316 if (help) 317 module_put(help->helper->me); 318 319 nf_ct_l3proto_module_put(par->family); 320 321 xt_ct_destroy_timeout(ct); 322 } 323 nf_ct_put(info->ct); 324} 325 326static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par) 327{ 328 struct xt_ct_target_info *info = par->targinfo; 329 struct xt_ct_target_info_v1 info_v1 = { 330 .flags = info->flags, 331 .zone = info->zone, 332 .ct_events = info->ct_events, 333 .exp_events = info->exp_events, 334 .ct = info->ct, 335 }; 336 memcpy(info_v1.helper, info->helper, sizeof(info->helper)); 337 338 xt_ct_tg_destroy(par, &info_v1); 339} 340 341static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par) 342{ 343 xt_ct_tg_destroy(par, par->targinfo); 344} 345 346static struct xt_target xt_ct_tg_reg[] __read_mostly = { 347 { 348 .name = "CT", 349 .family = NFPROTO_UNSPEC, 350 .targetsize = sizeof(struct xt_ct_target_info), 351 .checkentry = xt_ct_tg_check_v0, 352 .destroy = xt_ct_tg_destroy_v0, 353 .target = xt_ct_target_v0, 354 .table = "raw", 355 .me = THIS_MODULE, 356 }, 357 { 358 .name = "CT", 359 .family = NFPROTO_UNSPEC, 360 .revision = 1, 361 .targetsize = sizeof(struct xt_ct_target_info_v1), 362 .checkentry = xt_ct_tg_check_v1, 363 .destroy = xt_ct_tg_destroy_v1, 364 .target = xt_ct_target_v1, 365 .table = "raw", 366 .me = THIS_MODULE, 367 }, 368 { 369 .name = "CT", 370 .family = NFPROTO_UNSPEC, 371 .revision = 2, 372 .targetsize = sizeof(struct xt_ct_target_info_v1), 373 .checkentry = xt_ct_tg_check_v2, 374 .destroy = xt_ct_tg_destroy_v1, 375 .target = xt_ct_target_v1, 376 .table = "raw", 377 .me = THIS_MODULE, 378 }, 379}; 380 381static unsigned int 382notrack_tg(struct sk_buff *skb, const struct xt_action_param *par) 383{ 384 /* Previously seen (loopback)? Ignore. */ 385 if (skb->nfct != NULL) 386 return XT_CONTINUE; 387 388 skb->nfct = &nf_ct_untracked_get()->ct_general; 389 skb->nfctinfo = IP_CT_NEW; 390 nf_conntrack_get(skb->nfct); 391 392 return XT_CONTINUE; 393} 394 395static int notrack_chk(const struct xt_tgchk_param *par) 396{ 397 if (!par->net->xt.notrack_deprecated_warning) { 398 pr_info("netfilter: NOTRACK target is deprecated, " 399 "use CT instead or upgrade iptables\n"); 400 par->net->xt.notrack_deprecated_warning = true; 401 } 402 return 0; 403} 404 405static struct xt_target notrack_tg_reg __read_mostly = { 406 .name = "NOTRACK", 407 .revision = 0, 408 .family = NFPROTO_UNSPEC, 409 .checkentry = notrack_chk, 410 .target = notrack_tg, 411 .table = "raw", 412 .me = THIS_MODULE, 413}; 414 415static int __init xt_ct_tg_init(void) 416{ 417 int ret; 418 419 ret = xt_register_target(¬rack_tg_reg); 420 if (ret < 0) 421 return ret; 422 423 ret = xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg)); 424 if (ret < 0) { 425 xt_unregister_target(¬rack_tg_reg); 426 return ret; 427 } 428 return 0; 429} 430 431static void __exit xt_ct_tg_exit(void) 432{ 433 xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg)); 434 xt_unregister_target(¬rack_tg_reg); 435} 436 437module_init(xt_ct_tg_init); 438module_exit(xt_ct_tg_exit); 439 440MODULE_LICENSE("GPL"); 441MODULE_DESCRIPTION("Xtables: connection tracking target"); 442MODULE_ALIAS("ipt_CT"); 443MODULE_ALIAS("ip6t_CT"); 444MODULE_ALIAS("ipt_NOTRACK"); 445MODULE_ALIAS("ip6t_NOTRACK"); 446