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