1 /* L3/L4 protocol support for nf_conntrack. */ 2 3 /* (C) 1999-2001 Paul `Rusty' Russell 4 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> 5 * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 12 #include <linux/types.h> 13 #include <linux/netfilter.h> 14 #include <linux/module.h> 15 #include <linux/slab.h> 16 #include <linux/mutex.h> 17 #include <linux/vmalloc.h> 18 #include <linux/stddef.h> 19 #include <linux/err.h> 20 #include <linux/percpu.h> 21 #include <linux/notifier.h> 22 #include <linux/kernel.h> 23 #include <linux/netdevice.h> 24 25 #include <net/netfilter/nf_conntrack.h> 26 #include <net/netfilter/nf_conntrack_l3proto.h> 27 #include <net/netfilter/nf_conntrack_l4proto.h> 28 #include <net/netfilter/nf_conntrack_core.h> 29 30 static struct nf_conntrack_l4proto __rcu **nf_ct_protos[PF_MAX] __read_mostly; 31 struct nf_conntrack_l3proto __rcu *nf_ct_l3protos[AF_MAX] __read_mostly; 32 EXPORT_SYMBOL_GPL(nf_ct_l3protos); 33 34 static DEFINE_MUTEX(nf_ct_proto_mutex); 35 36 #ifdef CONFIG_SYSCTL 37 static int 38 nf_ct_register_sysctl(struct net *net, 39 struct ctl_table_header **header, 40 const char *path, 41 struct ctl_table *table) 42 { 43 if (*header == NULL) { 44 *header = register_net_sysctl(net, path, table); 45 if (*header == NULL) 46 return -ENOMEM; 47 } 48 49 return 0; 50 } 51 52 static void 53 nf_ct_unregister_sysctl(struct ctl_table_header **header, 54 struct ctl_table **table, 55 unsigned int users) 56 { 57 if (users > 0) 58 return; 59 60 unregister_net_sysctl_table(*header); 61 kfree(*table); 62 *header = NULL; 63 *table = NULL; 64 } 65 #endif 66 67 struct nf_conntrack_l4proto * 68 __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto) 69 { 70 if (unlikely(l3proto >= AF_MAX || nf_ct_protos[l3proto] == NULL)) 71 return &nf_conntrack_l4proto_generic; 72 73 return rcu_dereference(nf_ct_protos[l3proto][l4proto]); 74 } 75 EXPORT_SYMBOL_GPL(__nf_ct_l4proto_find); 76 77 /* this is guaranteed to always return a valid protocol helper, since 78 * it falls back to generic_protocol */ 79 struct nf_conntrack_l3proto * 80 nf_ct_l3proto_find_get(u_int16_t l3proto) 81 { 82 struct nf_conntrack_l3proto *p; 83 84 rcu_read_lock(); 85 p = __nf_ct_l3proto_find(l3proto); 86 if (!try_module_get(p->me)) 87 p = &nf_conntrack_l3proto_generic; 88 rcu_read_unlock(); 89 90 return p; 91 } 92 EXPORT_SYMBOL_GPL(nf_ct_l3proto_find_get); 93 94 void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p) 95 { 96 module_put(p->me); 97 } 98 EXPORT_SYMBOL_GPL(nf_ct_l3proto_put); 99 100 int 101 nf_ct_l3proto_try_module_get(unsigned short l3proto) 102 { 103 int ret; 104 struct nf_conntrack_l3proto *p; 105 106 retry: p = nf_ct_l3proto_find_get(l3proto); 107 if (p == &nf_conntrack_l3proto_generic) { 108 ret = request_module("nf_conntrack-%d", l3proto); 109 if (!ret) 110 goto retry; 111 112 return -EPROTOTYPE; 113 } 114 115 return 0; 116 } 117 EXPORT_SYMBOL_GPL(nf_ct_l3proto_try_module_get); 118 119 void nf_ct_l3proto_module_put(unsigned short l3proto) 120 { 121 struct nf_conntrack_l3proto *p; 122 123 /* rcu_read_lock not necessary since the caller holds a reference, but 124 * taken anyways to avoid lockdep warnings in __nf_ct_l3proto_find() 125 */ 126 rcu_read_lock(); 127 p = __nf_ct_l3proto_find(l3proto); 128 module_put(p->me); 129 rcu_read_unlock(); 130 } 131 EXPORT_SYMBOL_GPL(nf_ct_l3proto_module_put); 132 133 struct nf_conntrack_l4proto * 134 nf_ct_l4proto_find_get(u_int16_t l3num, u_int8_t l4num) 135 { 136 struct nf_conntrack_l4proto *p; 137 138 rcu_read_lock(); 139 p = __nf_ct_l4proto_find(l3num, l4num); 140 if (!try_module_get(p->me)) 141 p = &nf_conntrack_l4proto_generic; 142 rcu_read_unlock(); 143 144 return p; 145 } 146 EXPORT_SYMBOL_GPL(nf_ct_l4proto_find_get); 147 148 void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p) 149 { 150 module_put(p->me); 151 } 152 EXPORT_SYMBOL_GPL(nf_ct_l4proto_put); 153 154 static int kill_l3proto(struct nf_conn *i, void *data) 155 { 156 return nf_ct_l3num(i) == ((struct nf_conntrack_l3proto *)data)->l3proto; 157 } 158 159 static int kill_l4proto(struct nf_conn *i, void *data) 160 { 161 struct nf_conntrack_l4proto *l4proto; 162 l4proto = (struct nf_conntrack_l4proto *)data; 163 return nf_ct_protonum(i) == l4proto->l4proto && 164 nf_ct_l3num(i) == l4proto->l3proto; 165 } 166 167 static struct nf_ip_net *nf_ct_l3proto_net(struct net *net, 168 struct nf_conntrack_l3proto *l3proto) 169 { 170 if (l3proto->l3proto == PF_INET) 171 return &net->ct.nf_ct_proto; 172 else 173 return NULL; 174 } 175 176 static int nf_ct_l3proto_register_sysctl(struct net *net, 177 struct nf_conntrack_l3proto *l3proto) 178 { 179 int err = 0; 180 struct nf_ip_net *in = nf_ct_l3proto_net(net, l3proto); 181 /* nf_conntrack_l3proto_ipv6 doesn't support sysctl */ 182 if (in == NULL) 183 return 0; 184 185 #if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) 186 if (in->ctl_table != NULL) { 187 err = nf_ct_register_sysctl(net, 188 &in->ctl_table_header, 189 l3proto->ctl_table_path, 190 in->ctl_table); 191 if (err < 0) { 192 kfree(in->ctl_table); 193 in->ctl_table = NULL; 194 } 195 } 196 #endif 197 return err; 198 } 199 200 static void nf_ct_l3proto_unregister_sysctl(struct net *net, 201 struct nf_conntrack_l3proto *l3proto) 202 { 203 struct nf_ip_net *in = nf_ct_l3proto_net(net, l3proto); 204 205 if (in == NULL) 206 return; 207 #if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) 208 if (in->ctl_table_header != NULL) 209 nf_ct_unregister_sysctl(&in->ctl_table_header, 210 &in->ctl_table, 211 0); 212 #endif 213 } 214 215 static int 216 nf_conntrack_l3proto_register_net(struct nf_conntrack_l3proto *proto) 217 { 218 int ret = 0; 219 struct nf_conntrack_l3proto *old; 220 221 if (proto->l3proto >= AF_MAX) 222 return -EBUSY; 223 224 if (proto->tuple_to_nlattr && !proto->nlattr_tuple_size) 225 return -EINVAL; 226 227 mutex_lock(&nf_ct_proto_mutex); 228 old = rcu_dereference_protected(nf_ct_l3protos[proto->l3proto], 229 lockdep_is_held(&nf_ct_proto_mutex)); 230 if (old != &nf_conntrack_l3proto_generic) { 231 ret = -EBUSY; 232 goto out_unlock; 233 } 234 235 if (proto->nlattr_tuple_size) 236 proto->nla_size = 3 * proto->nlattr_tuple_size(); 237 238 rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto); 239 240 out_unlock: 241 mutex_unlock(&nf_ct_proto_mutex); 242 return ret; 243 244 } 245 246 int nf_conntrack_l3proto_register(struct net *net, 247 struct nf_conntrack_l3proto *proto) 248 { 249 int ret = 0; 250 251 if (proto->init_net) { 252 ret = proto->init_net(net); 253 if (ret < 0) 254 return ret; 255 } 256 257 ret = nf_ct_l3proto_register_sysctl(net, proto); 258 if (ret < 0) 259 return ret; 260 261 if (net == &init_net) { 262 ret = nf_conntrack_l3proto_register_net(proto); 263 if (ret < 0) 264 nf_ct_l3proto_unregister_sysctl(net, proto); 265 } 266 267 return ret; 268 } 269 EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_register); 270 271 static void 272 nf_conntrack_l3proto_unregister_net(struct nf_conntrack_l3proto *proto) 273 { 274 BUG_ON(proto->l3proto >= AF_MAX); 275 276 mutex_lock(&nf_ct_proto_mutex); 277 BUG_ON(rcu_dereference_protected(nf_ct_l3protos[proto->l3proto], 278 lockdep_is_held(&nf_ct_proto_mutex) 279 ) != proto); 280 rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], 281 &nf_conntrack_l3proto_generic); 282 mutex_unlock(&nf_ct_proto_mutex); 283 284 synchronize_rcu(); 285 } 286 287 void nf_conntrack_l3proto_unregister(struct net *net, 288 struct nf_conntrack_l3proto *proto) 289 { 290 if (net == &init_net) 291 nf_conntrack_l3proto_unregister_net(proto); 292 293 nf_ct_l3proto_unregister_sysctl(net, proto); 294 295 /* Remove all contrack entries for this protocol */ 296 nf_ct_iterate_cleanup(net, kill_l3proto, proto); 297 } 298 EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_unregister); 299 300 static struct nf_proto_net *nf_ct_l4proto_net(struct net *net, 301 struct nf_conntrack_l4proto *l4proto) 302 { 303 if (l4proto->get_net_proto) { 304 /* statically built-in protocols use static per-net */ 305 return l4proto->get_net_proto(net); 306 } else if (l4proto->net_id) { 307 /* ... and loadable protocols use dynamic per-net */ 308 return net_generic(net, *l4proto->net_id); 309 } 310 return NULL; 311 } 312 313 static 314 int nf_ct_l4proto_register_sysctl(struct net *net, 315 struct nf_proto_net *pn, 316 struct nf_conntrack_l4proto *l4proto) 317 { 318 int err = 0; 319 320 #ifdef CONFIG_SYSCTL 321 if (pn->ctl_table != NULL) { 322 err = nf_ct_register_sysctl(net, 323 &pn->ctl_table_header, 324 "net/netfilter", 325 pn->ctl_table); 326 if (err < 0) { 327 if (!pn->users) { 328 kfree(pn->ctl_table); 329 pn->ctl_table = NULL; 330 } 331 } 332 } 333 #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 334 if (l4proto->l3proto != AF_INET6 && pn->ctl_compat_table != NULL) { 335 if (err < 0) { 336 nf_ct_kfree_compat_sysctl_table(pn); 337 goto out; 338 } 339 err = nf_ct_register_sysctl(net, 340 &pn->ctl_compat_header, 341 "net/ipv4/netfilter", 342 pn->ctl_compat_table); 343 if (err == 0) 344 goto out; 345 346 nf_ct_kfree_compat_sysctl_table(pn); 347 nf_ct_unregister_sysctl(&pn->ctl_table_header, 348 &pn->ctl_table, 349 pn->users); 350 } 351 out: 352 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ 353 #endif /* CONFIG_SYSCTL */ 354 return err; 355 } 356 357 static 358 void nf_ct_l4proto_unregister_sysctl(struct net *net, 359 struct nf_proto_net *pn, 360 struct nf_conntrack_l4proto *l4proto) 361 { 362 #ifdef CONFIG_SYSCTL 363 if (pn->ctl_table_header != NULL) 364 nf_ct_unregister_sysctl(&pn->ctl_table_header, 365 &pn->ctl_table, 366 pn->users); 367 368 #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 369 if (l4proto->l3proto != AF_INET6 && pn->ctl_compat_header != NULL) 370 nf_ct_unregister_sysctl(&pn->ctl_compat_header, 371 &pn->ctl_compat_table, 372 0); 373 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ 374 #endif /* CONFIG_SYSCTL */ 375 } 376 377 /* FIXME: Allow NULL functions and sub in pointers to generic for 378 them. --RR */ 379 static int 380 nf_conntrack_l4proto_register_net(struct nf_conntrack_l4proto *l4proto) 381 { 382 int ret = 0; 383 384 if (l4proto->l3proto >= PF_MAX) 385 return -EBUSY; 386 387 if ((l4proto->to_nlattr && !l4proto->nlattr_size) 388 || (l4proto->tuple_to_nlattr && !l4proto->nlattr_tuple_size)) 389 return -EINVAL; 390 391 mutex_lock(&nf_ct_proto_mutex); 392 if (!nf_ct_protos[l4proto->l3proto]) { 393 /* l3proto may be loaded latter. */ 394 struct nf_conntrack_l4proto __rcu **proto_array; 395 int i; 396 397 proto_array = kmalloc(MAX_NF_CT_PROTO * 398 sizeof(struct nf_conntrack_l4proto *), 399 GFP_KERNEL); 400 if (proto_array == NULL) { 401 ret = -ENOMEM; 402 goto out_unlock; 403 } 404 405 for (i = 0; i < MAX_NF_CT_PROTO; i++) 406 RCU_INIT_POINTER(proto_array[i], &nf_conntrack_l4proto_generic); 407 408 /* Before making proto_array visible to lockless readers, 409 * we must make sure its content is committed to memory. 410 */ 411 smp_wmb(); 412 413 nf_ct_protos[l4proto->l3proto] = proto_array; 414 } else if (rcu_dereference_protected( 415 nf_ct_protos[l4proto->l3proto][l4proto->l4proto], 416 lockdep_is_held(&nf_ct_proto_mutex) 417 ) != &nf_conntrack_l4proto_generic) { 418 ret = -EBUSY; 419 goto out_unlock; 420 } 421 422 l4proto->nla_size = 0; 423 if (l4proto->nlattr_size) 424 l4proto->nla_size += l4proto->nlattr_size(); 425 if (l4proto->nlattr_tuple_size) 426 l4proto->nla_size += 3 * l4proto->nlattr_tuple_size(); 427 428 rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], 429 l4proto); 430 out_unlock: 431 mutex_unlock(&nf_ct_proto_mutex); 432 return ret; 433 } 434 435 int nf_conntrack_l4proto_register(struct net *net, 436 struct nf_conntrack_l4proto *l4proto) 437 { 438 int ret = 0; 439 struct nf_proto_net *pn = NULL; 440 441 if (l4proto->init_net) { 442 ret = l4proto->init_net(net, l4proto->l3proto); 443 if (ret < 0) 444 goto out; 445 } 446 447 pn = nf_ct_l4proto_net(net, l4proto); 448 if (pn == NULL) 449 goto out; 450 451 ret = nf_ct_l4proto_register_sysctl(net, pn, l4proto); 452 if (ret < 0) 453 goto out; 454 455 if (net == &init_net) { 456 ret = nf_conntrack_l4proto_register_net(l4proto); 457 if (ret < 0) { 458 nf_ct_l4proto_unregister_sysctl(net, pn, l4proto); 459 goto out; 460 } 461 } 462 463 pn->users++; 464 out: 465 return ret; 466 } 467 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register); 468 469 static void 470 nf_conntrack_l4proto_unregister_net(struct nf_conntrack_l4proto *l4proto) 471 { 472 BUG_ON(l4proto->l3proto >= PF_MAX); 473 474 mutex_lock(&nf_ct_proto_mutex); 475 BUG_ON(rcu_dereference_protected( 476 nf_ct_protos[l4proto->l3proto][l4proto->l4proto], 477 lockdep_is_held(&nf_ct_proto_mutex) 478 ) != l4proto); 479 rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], 480 &nf_conntrack_l4proto_generic); 481 mutex_unlock(&nf_ct_proto_mutex); 482 483 synchronize_rcu(); 484 } 485 486 void nf_conntrack_l4proto_unregister(struct net *net, 487 struct nf_conntrack_l4proto *l4proto) 488 { 489 struct nf_proto_net *pn = NULL; 490 491 if (net == &init_net) 492 nf_conntrack_l4proto_unregister_net(l4proto); 493 494 pn = nf_ct_l4proto_net(net, l4proto); 495 if (pn == NULL) 496 return; 497 498 pn->users--; 499 nf_ct_l4proto_unregister_sysctl(net, pn, l4proto); 500 501 /* Remove all contrack entries for this protocol */ 502 nf_ct_iterate_cleanup(net, kill_l4proto, l4proto); 503 } 504 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_unregister); 505 506 int nf_conntrack_proto_init(struct net *net) 507 { 508 unsigned int i; 509 int err; 510 struct nf_proto_net *pn = nf_ct_l4proto_net(net, 511 &nf_conntrack_l4proto_generic); 512 513 err = nf_conntrack_l4proto_generic.init_net(net, 514 nf_conntrack_l4proto_generic.l3proto); 515 if (err < 0) 516 return err; 517 err = nf_ct_l4proto_register_sysctl(net, 518 pn, 519 &nf_conntrack_l4proto_generic); 520 if (err < 0) 521 return err; 522 523 if (net == &init_net) { 524 for (i = 0; i < AF_MAX; i++) 525 rcu_assign_pointer(nf_ct_l3protos[i], 526 &nf_conntrack_l3proto_generic); 527 } 528 529 pn->users++; 530 return 0; 531 } 532 533 void nf_conntrack_proto_fini(struct net *net) 534 { 535 unsigned int i; 536 struct nf_proto_net *pn = nf_ct_l4proto_net(net, 537 &nf_conntrack_l4proto_generic); 538 539 pn->users--; 540 nf_ct_l4proto_unregister_sysctl(net, 541 pn, 542 &nf_conntrack_l4proto_generic); 543 if (net == &init_net) { 544 /* free l3proto protocol tables */ 545 for (i = 0; i < PF_MAX; i++) 546 kfree(nf_ct_protos[i]); 547 } 548 } 549