Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[NETFILTER]: Add ctnetlink subsystem

Add ctnetlink subsystem for userspace-access to ip_conntrack table.
This allows reading and updating of existing entries, as well as
creating new ones (and new expect's) via nfnetlink.

Please note the 'strange' byte order: nfattr (tag+length) are in host
byte order, while the payload is always guaranteed to be in network
byte order. This allows a simple userspace process to encapsulate netlink
messages into arch-independent udp packets by just processing/swapping the
headers and not knowing anything about the actual payload.

Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Harald Welte and committed by
David S. Miller
080774a2 6f1cf165

+2277 -100
+2 -1
include/linux/netfilter/nfnetlink.h
··· 56 56 u_int16_t res_id; /* resource id */ 57 57 } __attribute__ ((packed)); 58 58 59 - #define NFNETLINK_V1 1 59 + #define NFNETLINK_V0 0 60 60 61 61 #define NFM_NFA(n) ((struct nfattr *)(((char *)(n)) \ 62 62 + NLMSG_ALIGN(sizeof(struct nfgenmsg)))) ··· 81 81 82 82 #ifdef __KERNEL__ 83 83 84 + #include <linux/netlink.h> 84 85 #include <linux/capability.h> 85 86 86 87 struct nfnl_callback
+45 -1
include/linux/netfilter_ipv4/ip_conntrack.h
··· 209 209 /* Current number of expected connections */ 210 210 unsigned int expecting; 211 211 212 + /* Unique ID that identifies this conntrack*/ 213 + unsigned int id; 214 + 212 215 /* Helper, if any. */ 213 216 struct ip_conntrack_helper *helper; 214 217 ··· 260 257 /* Usage count. */ 261 258 atomic_t use; 262 259 260 + /* Unique ID */ 261 + unsigned int id; 262 + 263 263 #ifdef CONFIG_IP_NF_NAT_NEEDED 264 264 /* This is the original per-proto part, used to map the 265 265 * expected connection the way the recipient expects. */ ··· 302 296 } 303 297 304 298 /* decrement reference count on a conntrack */ 305 - extern void ip_conntrack_put(struct ip_conntrack *ct); 299 + static inline void 300 + ip_conntrack_put(struct ip_conntrack *ct) 301 + { 302 + IP_NF_ASSERT(ct); 303 + nf_conntrack_put(&ct->ct_general); 304 + } 306 305 307 306 /* call to create an explicit dependency on ip_conntrack. */ 308 307 extern void need_ip_conntrack(void); ··· 341 330 extern void 342 331 ip_ct_iterate_cleanup(int (*iter)(struct ip_conntrack *i, void *data), 343 332 void *data); 333 + 334 + extern struct ip_conntrack_helper * 335 + __ip_conntrack_helper_find_byname(const char *); 336 + extern struct ip_conntrack_helper * 337 + ip_conntrack_helper_find_get(const struct ip_conntrack_tuple *tuple); 338 + extern void ip_conntrack_helper_put(struct ip_conntrack_helper *helper); 339 + 340 + extern struct ip_conntrack_protocol * 341 + __ip_conntrack_proto_find(u_int8_t protocol); 342 + extern struct ip_conntrack_protocol * 343 + ip_conntrack_proto_find_get(u_int8_t protocol); 344 + extern void ip_conntrack_proto_put(struct ip_conntrack_protocol *proto); 345 + 346 + extern void ip_ct_remove_expectations(struct ip_conntrack *ct); 347 + 348 + extern struct ip_conntrack *ip_conntrack_alloc(struct ip_conntrack_tuple *, 349 + struct ip_conntrack_tuple *); 350 + 351 + extern void ip_conntrack_free(struct ip_conntrack *ct); 352 + 353 + extern void ip_conntrack_hash_insert(struct ip_conntrack *ct); 354 + 355 + extern struct ip_conntrack_expect * 356 + __ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple); 357 + 358 + extern struct ip_conntrack_expect * 359 + ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple); 360 + 361 + extern struct ip_conntrack_tuple_hash * 362 + __ip_conntrack_find(const struct ip_conntrack_tuple *tuple, 363 + const struct ip_conntrack *ignored_conntrack); 364 + 365 + extern void ip_conntrack_flush(void); 344 366 345 367 /* It's confirmed if it is, or has been in the hash table. */ 346 368 static inline int is_confirmed(struct ip_conntrack *ct)
+5
include/linux/netfilter_ipv4/ip_conntrack_core.h
··· 2 2 #define _IP_CONNTRACK_CORE_H 3 3 #include <linux/netfilter.h> 4 4 5 + #define MAX_IP_CT_PROTO 256 6 + extern struct ip_conntrack_protocol *ip_ct_protos[MAX_IP_CT_PROTO]; 7 + 5 8 /* This header is used to share core functionality between the 6 9 standalone connection tracking module, and the compatibility layer's use 7 10 of connection tracking. */ ··· 55 52 struct ip_conntrack_ecache; 56 53 extern void __ip_ct_deliver_cached_events(struct ip_conntrack_ecache *ec); 57 54 #endif 55 + 56 + extern void __ip_ct_expect_unlink_destroy(struct ip_conntrack_expect *exp); 58 57 59 58 extern struct list_head *ip_conntrack_hash; 60 59 extern struct list_head ip_conntrack_expect_list;
+2
include/linux/netfilter_ipv4/ip_conntrack_helper.h
··· 24 24 int (*help)(struct sk_buff **pskb, 25 25 struct ip_conntrack *ct, 26 26 enum ip_conntrack_info conntrackinfo); 27 + 28 + int (*to_nfattr)(struct sk_buff *skb, const struct ip_conntrack *ct); 27 29 }; 28 30 29 31 extern int ip_conntrack_helper_register(struct ip_conntrack_helper *);
+15 -9
include/linux/netfilter_ipv4/ip_conntrack_protocol.h
··· 2 2 #ifndef _IP_CONNTRACK_PROTOCOL_H 3 3 #define _IP_CONNTRACK_PROTOCOL_H 4 4 #include <linux/netfilter_ipv4/ip_conntrack.h> 5 + #include <linux/netfilter/nfnetlink_conntrack.h> 5 6 6 7 struct seq_file; 7 8 ··· 48 47 int (*error)(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, 49 48 unsigned int hooknum); 50 49 50 + /* convert protoinfo to nfnetink attributes */ 51 + int (*to_nfattr)(struct sk_buff *skb, struct nfattr *nfa, 52 + const struct ip_conntrack *ct); 53 + 54 + int (*tuple_to_nfattr)(struct sk_buff *skb, 55 + const struct ip_conntrack_tuple *t); 56 + int (*nfattr_to_tuple)(struct nfattr *tb[], 57 + struct ip_conntrack_tuple *t); 58 + 51 59 /* Module (if any) which this is connected to. */ 52 60 struct module *me; 53 61 }; 54 62 55 - #define MAX_IP_CT_PROTO 256 56 - extern struct ip_conntrack_protocol *ip_ct_protos[MAX_IP_CT_PROTO]; 57 - 58 63 /* Protocol registration. */ 59 64 extern int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto); 60 65 extern void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto); 61 - 62 - static inline struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol) 63 - { 64 - return ip_ct_protos[protocol]; 65 - } 66 - 67 66 /* Existing built-in protocols */ 68 67 extern struct ip_conntrack_protocol ip_conntrack_protocol_tcp; 69 68 extern struct ip_conntrack_protocol ip_conntrack_protocol_udp; ··· 73 72 74 73 /* Log invalid packets */ 75 74 extern unsigned int ip_ct_log_invalid; 75 + 76 + extern int ip_ct_port_tuple_to_nfattr(struct sk_buff *, 77 + const struct ip_conntrack_tuple *); 78 + extern int ip_ct_port_nfattr_to_tuple(struct nfattr *tb[], 79 + struct ip_conntrack_tuple *); 76 80 77 81 #ifdef CONFIG_SYSCTL 78 82 #ifdef DEBUG_INVALID_PACKETS
+18 -7
include/linux/netfilter_ipv4/ip_nat_protocol.h
··· 4 4 #include <linux/init.h> 5 5 #include <linux/list.h> 6 6 7 + #include <linux/netfilter_ipv4/ip_nat.h> 8 + #include <linux/netfilter/nfnetlink_conntrack.h> 9 + 7 10 struct iphdr; 8 11 struct ip_nat_range; 9 12 ··· 17 14 18 15 /* Protocol number. */ 19 16 unsigned int protonum; 17 + 18 + struct module *me; 20 19 21 20 /* Translate a packet to the target according to manip type. 22 21 Return true if succeeded. */ ··· 48 43 49 44 unsigned int (*print_range)(char *buffer, 50 45 const struct ip_nat_range *range); 51 - }; 52 46 53 - #define MAX_IP_NAT_PROTO 256 54 - extern struct ip_nat_protocol *ip_nat_protos[MAX_IP_NAT_PROTO]; 47 + int (*range_to_nfattr)(struct sk_buff *skb, 48 + const struct ip_nat_range *range); 49 + 50 + int (*nfattr_to_range)(struct nfattr *tb[], 51 + struct ip_nat_range *range); 52 + }; 55 53 56 54 /* Protocol registration. */ 57 55 extern int ip_nat_protocol_register(struct ip_nat_protocol *proto); 58 56 extern void ip_nat_protocol_unregister(struct ip_nat_protocol *proto); 59 57 60 - static inline struct ip_nat_protocol *ip_nat_find_proto(u_int8_t protocol) 61 - { 62 - return ip_nat_protos[protocol]; 63 - } 58 + extern struct ip_nat_protocol *ip_nat_proto_find_get(u_int8_t protocol); 59 + extern void ip_nat_proto_put(struct ip_nat_protocol *proto); 64 60 65 61 /* Built-in protocols. */ 66 62 extern struct ip_nat_protocol ip_nat_protocol_tcp; ··· 72 66 extern int init_protocols(void) __init; 73 67 extern void cleanup_protocols(void); 74 68 extern struct ip_nat_protocol *find_nat_proto(u_int16_t protonum); 69 + 70 + extern int ip_nat_port_range_to_nfattr(struct sk_buff *skb, 71 + const struct ip_nat_range *range); 72 + extern int ip_nat_port_nfattr_to_range(struct nfattr *tb[], 73 + struct ip_nat_range *range); 75 74 76 75 #endif /*_IP_NAT_PROTO_H*/
+7
net/ipv4/netfilter/Kconfig
··· 702 702 Allows altering the ARP packet payload: source and destination 703 703 hardware and network addresses. 704 704 705 + config IP_NF_CONNTRACK_NETLINK 706 + tristate 'Connection tracking netlink interface' 707 + depends on IP_NF_CONNTRACK && NETFILTER_NETLINK 708 + help 709 + This option enables support for a netlink-based userspace interface 710 + 711 + 705 712 endmenu 706 713
+4
net/ipv4/netfilter/Makefile
··· 9 9 # connection tracking 10 10 obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o 11 11 12 + # conntrack netlink interface 13 + obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) += ip_conntrack_netlink.o 14 + 15 + 12 16 # SCTP protocol connection tracking 13 17 obj-$(CONFIG_IP_NF_CT_PROTO_SCTP) += ip_conntrack_proto_sctp.o 14 18
+228 -53
net/ipv4/netfilter/ip_conntrack_core.c
··· 50 50 #include <linux/netfilter_ipv4/ip_conntrack_core.h> 51 51 #include <linux/netfilter_ipv4/listhelp.h> 52 52 53 - #define IP_CONNTRACK_VERSION "2.2" 53 + #define IP_CONNTRACK_VERSION "2.3" 54 54 55 55 #if 0 56 56 #define DEBUGP printk ··· 77 77 static LIST_HEAD(unconfirmed); 78 78 static int ip_conntrack_vmalloc; 79 79 80 + static unsigned int ip_conntrack_next_id = 1; 81 + static unsigned int ip_conntrack_expect_next_id = 1; 80 82 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS 81 83 struct notifier_block *ip_conntrack_chain; 82 84 struct notifier_block *ip_conntrack_expect_chain; ··· 156 154 157 155 DEFINE_PER_CPU(struct ip_conntrack_stat, ip_conntrack_stat); 158 156 159 - void 160 - ip_conntrack_put(struct ip_conntrack *ct) 161 - { 162 - IP_NF_ASSERT(ct); 163 - nf_conntrack_put(&ct->ct_general); 164 - } 165 - 166 157 static int ip_conntrack_hash_rnd_initted; 167 158 static unsigned int ip_conntrack_hash_rnd; 168 159 ··· 217 222 exp->master->expecting--; 218 223 } 219 224 225 + void __ip_ct_expect_unlink_destroy(struct ip_conntrack_expect *exp) 226 + { 227 + unlink_expect(exp); 228 + ip_conntrack_expect_put(exp); 229 + } 230 + 220 231 static void expectation_timed_out(unsigned long ul_expect) 221 232 { 222 233 struct ip_conntrack_expect *exp = (void *)ul_expect; ··· 231 230 unlink_expect(exp); 232 231 write_unlock_bh(&ip_conntrack_lock); 233 232 ip_conntrack_expect_put(exp); 233 + } 234 + 235 + struct ip_conntrack_expect * 236 + __ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple) 237 + { 238 + struct ip_conntrack_expect *i; 239 + 240 + list_for_each_entry(i, &ip_conntrack_expect_list, list) { 241 + if (ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) { 242 + atomic_inc(&i->use); 243 + return i; 244 + } 245 + } 246 + return NULL; 247 + } 248 + 249 + /* Just find a expectation corresponding to a tuple. */ 250 + struct ip_conntrack_expect * 251 + ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple) 252 + { 253 + struct ip_conntrack_expect *i; 254 + 255 + read_lock_bh(&ip_conntrack_lock); 256 + i = __ip_conntrack_expect_find(tuple); 257 + read_unlock_bh(&ip_conntrack_lock); 258 + 259 + return i; 234 260 } 235 261 236 262 /* If an expectation for this connection is found, it gets delete from ··· 284 256 } 285 257 286 258 /* delete all expectations for this conntrack */ 287 - static void remove_expectations(struct ip_conntrack *ct) 259 + void ip_ct_remove_expectations(struct ip_conntrack *ct) 288 260 { 289 261 struct ip_conntrack_expect *i, *tmp; 290 262 ··· 314 286 LIST_DELETE(&ip_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]); 315 287 316 288 /* Destroy all pending expectations */ 317 - remove_expectations(ct); 289 + ip_ct_remove_expectations(ct); 318 290 } 319 291 320 292 static void ··· 332 304 /* To make sure we don't get any weird locking issues here: 333 305 * destroy_conntrack() MUST NOT be called with a write lock 334 306 * to ip_conntrack_lock!!! -HW */ 335 - proto = ip_ct_find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum); 307 + proto = __ip_conntrack_proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum); 336 308 if (proto && proto->destroy) 337 309 proto->destroy(ct); 338 310 ··· 344 316 * except TFTP can create an expectation on the first packet, 345 317 * before connection is in the list, so we need to clean here, 346 318 * too. */ 347 - remove_expectations(ct); 319 + ip_ct_remove_expectations(ct); 348 320 349 321 /* We overload first tuple to link into unconfirmed list. */ 350 322 if (!is_confirmed(ct)) { ··· 359 331 ip_conntrack_put(ct->master); 360 332 361 333 DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct); 362 - kmem_cache_free(ip_conntrack_cachep, ct); 363 - atomic_dec(&ip_conntrack_count); 334 + ip_conntrack_free(ct); 364 335 } 365 336 366 337 static void death_by_timeout(unsigned long ul_conntrack) ··· 386 359 && ip_ct_tuple_equal(tuple, &i->tuple); 387 360 } 388 361 389 - static struct ip_conntrack_tuple_hash * 362 + struct ip_conntrack_tuple_hash * 390 363 __ip_conntrack_find(const struct ip_conntrack_tuple *tuple, 391 364 const struct ip_conntrack *ignored_conntrack) 392 365 { ··· 419 392 read_unlock_bh(&ip_conntrack_lock); 420 393 421 394 return h; 395 + } 396 + 397 + static void __ip_conntrack_hash_insert(struct ip_conntrack *ct, 398 + unsigned int hash, 399 + unsigned int repl_hash) 400 + { 401 + ct->id = ++ip_conntrack_next_id; 402 + list_prepend(&ip_conntrack_hash[hash], 403 + &ct->tuplehash[IP_CT_DIR_ORIGINAL].list); 404 + list_prepend(&ip_conntrack_hash[repl_hash], 405 + &ct->tuplehash[IP_CT_DIR_REPLY].list); 406 + } 407 + 408 + void ip_conntrack_hash_insert(struct ip_conntrack *ct) 409 + { 410 + unsigned int hash, repl_hash; 411 + 412 + hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); 413 + repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); 414 + 415 + write_lock_bh(&ip_conntrack_lock); 416 + __ip_conntrack_hash_insert(ct, hash, repl_hash); 417 + write_unlock_bh(&ip_conntrack_lock); 422 418 } 423 419 424 420 /* Confirm a connection given skb; places it in hash table */ ··· 490 440 /* Remove from unconfirmed list */ 491 441 list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); 492 442 493 - list_prepend(&ip_conntrack_hash[hash], 494 - &ct->tuplehash[IP_CT_DIR_ORIGINAL]); 495 - list_prepend(&ip_conntrack_hash[repl_hash], 496 - &ct->tuplehash[IP_CT_DIR_REPLY]); 443 + __ip_conntrack_hash_insert(ct, hash, repl_hash); 497 444 /* Timer relative to confirmation time, not original 498 445 setting time, otherwise we'd get timer wrap in 499 446 weird delay cases. */ ··· 574 527 return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask); 575 528 } 576 529 577 - static struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple) 530 + static struct ip_conntrack_helper * 531 + __ip_conntrack_helper_find( const struct ip_conntrack_tuple *tuple) 578 532 { 579 533 return LIST_FIND(&helpers, helper_cmp, 580 534 struct ip_conntrack_helper *, 581 535 tuple); 582 536 } 583 537 584 - /* Allocate a new conntrack: we return -ENOMEM if classification 585 - failed due to stress. Otherwise it really is unclassifiable. */ 586 - static struct ip_conntrack_tuple_hash * 587 - init_conntrack(const struct ip_conntrack_tuple *tuple, 588 - struct ip_conntrack_protocol *protocol, 589 - struct sk_buff *skb) 538 + struct ip_conntrack_helper * 539 + ip_conntrack_helper_find_get( const struct ip_conntrack_tuple *tuple) 540 + { 541 + struct ip_conntrack_helper *helper; 542 + 543 + /* need ip_conntrack_lock to assure that helper exists until 544 + * try_module_get() is called */ 545 + read_lock_bh(&ip_conntrack_lock); 546 + 547 + helper = __ip_conntrack_helper_find(tuple); 548 + if (helper) { 549 + /* need to increase module usage count to assure helper will 550 + * not go away while the caller is e.g. busy putting a 551 + * conntrack in the hash that uses the helper */ 552 + if (!try_module_get(helper->me)) 553 + helper = NULL; 554 + } 555 + 556 + read_unlock_bh(&ip_conntrack_lock); 557 + 558 + return helper; 559 + } 560 + 561 + void ip_conntrack_helper_put(struct ip_conntrack_helper *helper) 562 + { 563 + module_put(helper->me); 564 + } 565 + 566 + struct ip_conntrack_protocol * 567 + __ip_conntrack_proto_find(u_int8_t protocol) 568 + { 569 + return ip_ct_protos[protocol]; 570 + } 571 + 572 + /* this is guaranteed to always return a valid protocol helper, since 573 + * it falls back to generic_protocol */ 574 + struct ip_conntrack_protocol * 575 + ip_conntrack_proto_find_get(u_int8_t protocol) 576 + { 577 + struct ip_conntrack_protocol *p; 578 + 579 + preempt_disable(); 580 + p = __ip_conntrack_proto_find(protocol); 581 + if (p) { 582 + if (!try_module_get(p->me)) 583 + p = &ip_conntrack_generic_protocol; 584 + } 585 + preempt_enable(); 586 + 587 + return p; 588 + } 589 + 590 + void ip_conntrack_proto_put(struct ip_conntrack_protocol *p) 591 + { 592 + module_put(p->me); 593 + } 594 + 595 + struct ip_conntrack *ip_conntrack_alloc(struct ip_conntrack_tuple *orig, 596 + struct ip_conntrack_tuple *repl) 590 597 { 591 598 struct ip_conntrack *conntrack; 592 - struct ip_conntrack_tuple repl_tuple; 593 - size_t hash; 594 - struct ip_conntrack_expect *exp; 595 599 596 600 if (!ip_conntrack_hash_rnd_initted) { 597 601 get_random_bytes(&ip_conntrack_hash_rnd, 4); 598 602 ip_conntrack_hash_rnd_initted = 1; 599 603 } 600 604 601 - hash = hash_conntrack(tuple); 602 - 603 605 if (ip_conntrack_max 604 606 && atomic_read(&ip_conntrack_count) >= ip_conntrack_max) { 607 + unsigned int hash = hash_conntrack(orig); 605 608 /* Try dropping from this hash chain. */ 606 609 if (!early_drop(&ip_conntrack_hash[hash])) { 607 610 if (net_ratelimit()) ··· 662 565 } 663 566 } 664 567 665 - if (!ip_ct_invert_tuple(&repl_tuple, tuple, protocol)) { 666 - DEBUGP("Can't invert tuple.\n"); 667 - return NULL; 668 - } 669 - 670 568 conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC); 671 569 if (!conntrack) { 672 570 DEBUGP("Can't allocate conntrack.\n"); 673 - return ERR_PTR(-ENOMEM); 571 + return NULL; 674 572 } 675 573 676 574 memset(conntrack, 0, sizeof(*conntrack)); 677 575 atomic_set(&conntrack->ct_general.use, 1); 678 576 conntrack->ct_general.destroy = destroy_conntrack; 679 - conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple; 680 - conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = repl_tuple; 681 - if (!protocol->new(conntrack, skb)) { 682 - kmem_cache_free(ip_conntrack_cachep, conntrack); 683 - return NULL; 684 - } 577 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig; 578 + conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *repl; 685 579 /* Don't set timer yet: wait for confirmation */ 686 580 init_timer(&conntrack->timeout); 687 581 conntrack->timeout.data = (unsigned long)conntrack; 688 582 conntrack->timeout.function = death_by_timeout; 583 + 584 + atomic_inc(&ip_conntrack_count); 585 + 586 + return conntrack; 587 + } 588 + 589 + void 590 + ip_conntrack_free(struct ip_conntrack *conntrack) 591 + { 592 + atomic_dec(&ip_conntrack_count); 593 + kmem_cache_free(ip_conntrack_cachep, conntrack); 594 + } 595 + 596 + /* Allocate a new conntrack: we return -ENOMEM if classification 597 + * failed due to stress. Otherwise it really is unclassifiable */ 598 + static struct ip_conntrack_tuple_hash * 599 + init_conntrack(struct ip_conntrack_tuple *tuple, 600 + struct ip_conntrack_protocol *protocol, 601 + struct sk_buff *skb) 602 + { 603 + struct ip_conntrack *conntrack; 604 + struct ip_conntrack_tuple repl_tuple; 605 + struct ip_conntrack_expect *exp; 606 + 607 + if (!ip_ct_invert_tuple(&repl_tuple, tuple, protocol)) { 608 + DEBUGP("Can't invert tuple.\n"); 609 + return NULL; 610 + } 611 + 612 + if (!(conntrack = ip_conntrack_alloc(tuple, &repl_tuple))) 613 + return NULL; 614 + 615 + if (!protocol->new(conntrack, skb)) { 616 + ip_conntrack_free(conntrack); 617 + return NULL; 618 + } 689 619 690 620 write_lock_bh(&ip_conntrack_lock); 691 621 exp = find_expectation(tuple); ··· 734 610 nf_conntrack_get(&conntrack->master->ct_general); 735 611 CONNTRACK_STAT_INC(expect_new); 736 612 } else { 737 - conntrack->helper = ip_ct_find_helper(&repl_tuple); 613 + conntrack->helper = __ip_conntrack_helper_find(&repl_tuple); 738 614 739 615 CONNTRACK_STAT_INC(new); 740 616 } ··· 742 618 /* Overload tuple linked list to put us in unconfirmed list. */ 743 619 list_add(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list, &unconfirmed); 744 620 745 - atomic_inc(&ip_conntrack_count); 746 621 write_unlock_bh(&ip_conntrack_lock); 747 622 748 623 if (exp) { ··· 852 729 } 853 730 #endif 854 731 855 - proto = ip_ct_find_proto((*pskb)->nh.iph->protocol); 732 + proto = __ip_conntrack_proto_find((*pskb)->nh.iph->protocol); 856 733 857 734 /* It may be an special packet, error, unclean... 858 735 * inverse of the return code tells to the netfilter ··· 900 777 const struct ip_conntrack_tuple *orig) 901 778 { 902 779 return ip_ct_invert_tuple(inverse, orig, 903 - ip_ct_find_proto(orig->dst.protonum)); 780 + __ip_conntrack_proto_find(orig->dst.protonum)); 904 781 } 905 782 906 783 /* Would two expected things clash? */ ··· 980 857 exp->timeout.expires = jiffies + exp->master->helper->timeout * HZ; 981 858 add_timer(&exp->timeout); 982 859 860 + exp->id = ++ip_conntrack_expect_next_id; 861 + atomic_inc(&exp->use); 983 862 CONNTRACK_STAT_INC(expect_create); 984 863 } 985 864 ··· 1061 936 1062 937 conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; 1063 938 if (!conntrack->master && conntrack->expecting == 0) 1064 - conntrack->helper = ip_ct_find_helper(newreply); 939 + conntrack->helper = __ip_conntrack_helper_find(newreply); 1065 940 write_unlock_bh(&ip_conntrack_lock); 1066 941 } 1067 942 ··· 1073 948 write_unlock_bh(&ip_conntrack_lock); 1074 949 1075 950 return 0; 951 + } 952 + 953 + struct ip_conntrack_helper * 954 + __ip_conntrack_helper_find_byname(const char *name) 955 + { 956 + struct ip_conntrack_helper *h; 957 + 958 + list_for_each_entry(h, &helpers, list) { 959 + if (!strcmp(h->name, name)) 960 + return h; 961 + } 962 + 963 + return NULL; 1076 964 } 1077 965 1078 966 static inline int unhelp(struct ip_conntrack_tuple_hash *i, ··· 1162 1024 write_unlock_bh(&ip_conntrack_lock); 1163 1025 } 1164 1026 } 1027 + 1028 + #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ 1029 + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) 1030 + /* Generic function for tcp/udp/sctp/dccp and alike. This needs to be 1031 + * in ip_conntrack_core, since we don't want the protocols to autoload 1032 + * or depend on ctnetlink */ 1033 + int ip_ct_port_tuple_to_nfattr(struct sk_buff *skb, 1034 + const struct ip_conntrack_tuple *tuple) 1035 + { 1036 + NFA_PUT(skb, CTA_PROTO_SRC_PORT, sizeof(u_int16_t), 1037 + &tuple->src.u.tcp.port); 1038 + NFA_PUT(skb, CTA_PROTO_DST_PORT, sizeof(u_int16_t), 1039 + &tuple->dst.u.tcp.port); 1040 + return 0; 1041 + 1042 + nfattr_failure: 1043 + return -1; 1044 + } 1045 + 1046 + int ip_ct_port_nfattr_to_tuple(struct nfattr *tb[], 1047 + struct ip_conntrack_tuple *t) 1048 + { 1049 + if (!tb[CTA_PROTO_SRC_PORT-1] || !tb[CTA_PROTO_DST_PORT-1]) 1050 + return -EINVAL; 1051 + 1052 + t->src.u.tcp.port = 1053 + *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_SRC_PORT-1]); 1054 + t->dst.u.tcp.port = 1055 + *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_DST_PORT-1]); 1056 + 1057 + return 0; 1058 + } 1059 + #endif 1165 1060 1166 1061 /* Returns new sk_buff, or NULL */ 1167 1062 struct sk_buff * ··· 1374 1203 * ip_conntrack_htable_size)); 1375 1204 } 1376 1205 1377 - /* Mishearing the voices in his head, our hero wonders how he's 1378 - supposed to kill the mall. */ 1379 - void ip_conntrack_cleanup(void) 1206 + void ip_conntrack_flush() 1380 1207 { 1381 - ip_ct_attach = NULL; 1382 1208 /* This makes sure all current packets have passed through 1383 1209 netfilter framework. Roll on, two-stage module 1384 1210 delete... */ 1385 1211 synchronize_net(); 1386 - 1212 + 1387 1213 i_see_dead_people: 1388 1214 ip_ct_iterate_cleanup(kill_all, NULL); 1389 1215 if (atomic_read(&ip_conntrack_count) != 0) { ··· 1390 1222 /* wait until all references to ip_conntrack_untracked are dropped */ 1391 1223 while (atomic_read(&ip_conntrack_untracked.ct_general.use) > 1) 1392 1224 schedule(); 1225 + } 1393 1226 1227 + /* Mishearing the voices in his head, our hero wonders how he's 1228 + supposed to kill the mall. */ 1229 + void ip_conntrack_cleanup(void) 1230 + { 1231 + ip_ct_attach = NULL; 1232 + ip_conntrack_flush(); 1394 1233 kmem_cache_destroy(ip_conntrack_cachep); 1395 1234 kmem_cache_destroy(ip_conntrack_expect_cachep); 1396 1235 free_conntrack_hash();
+1588
net/ipv4/netfilter/ip_conntrack_netlink.c
··· 1 + /* Connection tracking via netlink socket. Allows for user space 2 + * protocol helpers and general trouble making from userspace. 3 + * 4 + * (C) 2001 by Jay Schulist <jschlst@samba.org> 5 + * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org> 6 + * (C) 2003 by Patrick Mchardy <kaber@trash.net> 7 + * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net> 8 + * 9 + * I've reworked this stuff to use attributes instead of conntrack 10 + * structures. 5.44 am. I need more tea. --pablo 05/07/11. 11 + * 12 + * Initial connection tracking via netlink development funded and 13 + * generally made possible by Network Robots, Inc. (www.networkrobots.com) 14 + * 15 + * Further development of this code funded by Astaro AG (http://www.astaro.com) 16 + * 17 + * This software may be used and distributed according to the terms 18 + * of the GNU General Public License, incorporated herein by reference. 19 + */ 20 + 21 + #include <linux/init.h> 22 + #include <linux/module.h> 23 + #include <linux/kernel.h> 24 + #include <linux/types.h> 25 + #include <linux/timer.h> 26 + #include <linux/skbuff.h> 27 + #include <linux/errno.h> 28 + #include <linux/netlink.h> 29 + #include <linux/spinlock.h> 30 + #include <linux/notifier.h> 31 + #include <linux/rtnetlink.h> 32 + 33 + #include <linux/netfilter.h> 34 + #include <linux/netfilter_ipv4.h> 35 + #include <linux/netfilter_ipv4/ip_tables.h> 36 + #include <linux/netfilter_ipv4/ip_conntrack.h> 37 + #include <linux/netfilter_ipv4/ip_conntrack_core.h> 38 + #include <linux/netfilter_ipv4/ip_conntrack_helper.h> 39 + #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> 40 + #include <linux/netfilter_ipv4/ip_nat_protocol.h> 41 + 42 + #include <linux/netfilter/nfnetlink.h> 43 + #include <linux/netfilter/nfnetlink_conntrack.h> 44 + 45 + MODULE_LICENSE("GPL"); 46 + 47 + static char __initdata version[] = "0.90"; 48 + 49 + #if 0 50 + #define DEBUGP printk 51 + #else 52 + #define DEBUGP(format, args...) 53 + #endif 54 + 55 + 56 + static inline int 57 + ctnetlink_dump_tuples_proto(struct sk_buff *skb, 58 + const struct ip_conntrack_tuple *tuple) 59 + { 60 + struct ip_conntrack_protocol *proto; 61 + 62 + NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum); 63 + 64 + proto = ip_conntrack_proto_find_get(tuple->dst.protonum); 65 + if (proto && proto->tuple_to_nfattr) 66 + return proto->tuple_to_nfattr(skb, tuple); 67 + 68 + return 0; 69 + 70 + nfattr_failure: 71 + return -1; 72 + } 73 + 74 + static inline int 75 + ctnetlink_dump_tuples(struct sk_buff *skb, 76 + const struct ip_conntrack_tuple *tuple) 77 + { 78 + struct nfattr *nest_parms; 79 + 80 + nest_parms = NFA_NEST(skb, CTA_TUPLE_IP); 81 + NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t), &tuple->src.ip); 82 + NFA_PUT(skb, CTA_IP_V4_DST, sizeof(u_int32_t), &tuple->dst.ip); 83 + NFA_NEST_END(skb, nest_parms); 84 + 85 + nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO); 86 + ctnetlink_dump_tuples_proto(skb, tuple); 87 + NFA_NEST_END(skb, nest_parms); 88 + 89 + return 0; 90 + 91 + nfattr_failure: 92 + return -1; 93 + } 94 + 95 + static inline int 96 + ctnetlink_dump_status(struct sk_buff *skb, const struct ip_conntrack *ct) 97 + { 98 + u_int32_t status = htonl((u_int32_t) ct->status); 99 + NFA_PUT(skb, CTA_STATUS, sizeof(status), &status); 100 + return 0; 101 + 102 + nfattr_failure: 103 + return -1; 104 + } 105 + 106 + static inline int 107 + ctnetlink_dump_timeout(struct sk_buff *skb, const struct ip_conntrack *ct) 108 + { 109 + long timeout_l = ct->timeout.expires - jiffies; 110 + u_int32_t timeout; 111 + 112 + if (timeout_l < 0) 113 + timeout = 0; 114 + else 115 + timeout = htonl(timeout_l / HZ); 116 + 117 + NFA_PUT(skb, CTA_TIMEOUT, sizeof(timeout), &timeout); 118 + return 0; 119 + 120 + nfattr_failure: 121 + return -1; 122 + } 123 + 124 + static inline int 125 + ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct ip_conntrack *ct) 126 + { 127 + struct ip_conntrack_protocol *proto = ip_conntrack_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); 128 + 129 + struct nfattr *nest_proto; 130 + int ret; 131 + 132 + if (!proto || !proto->to_nfattr) 133 + return 0; 134 + 135 + nest_proto = NFA_NEST(skb, CTA_PROTOINFO); 136 + 137 + ret = proto->to_nfattr(skb, nest_proto, ct); 138 + 139 + ip_conntrack_proto_put(proto); 140 + 141 + NFA_NEST_END(skb, nest_proto); 142 + 143 + return ret; 144 + 145 + nfattr_failure: 146 + return -1; 147 + } 148 + 149 + static inline int 150 + ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct ip_conntrack *ct) 151 + { 152 + struct nfattr *nest_helper; 153 + 154 + if (!ct->helper) 155 + return 0; 156 + 157 + nest_helper = NFA_NEST(skb, CTA_HELP); 158 + NFA_PUT(skb, CTA_HELP_NAME, CTA_HELP_MAXNAMESIZE, &ct->helper->name); 159 + 160 + if (ct->helper->to_nfattr) 161 + ct->helper->to_nfattr(skb, ct); 162 + 163 + NFA_NEST_END(skb, nest_helper); 164 + 165 + return 0; 166 + 167 + nfattr_failure: 168 + return -1; 169 + } 170 + 171 + #ifdef CONFIG_IP_NF_CT_ACCT 172 + static inline int 173 + ctnetlink_dump_counters(struct sk_buff *skb, const struct ip_conntrack *ct, 174 + enum ip_conntrack_dir dir) 175 + { 176 + enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG; 177 + struct nfattr *nest_count = NFA_NEST(skb, type); 178 + u_int64_t tmp; 179 + 180 + tmp = cpu_to_be64(ct->counters[dir].packets); 181 + NFA_PUT(skb, CTA_COUNTERS_PACKETS, sizeof(u_int64_t), &tmp); 182 + 183 + tmp = cpu_to_be64(ct->counters[dir].bytes); 184 + NFA_PUT(skb, CTA_COUNTERS_BYTES, sizeof(u_int64_t), &tmp); 185 + 186 + NFA_NEST_END(skb, nest_count); 187 + 188 + return 0; 189 + 190 + nfattr_failure: 191 + return -1; 192 + } 193 + #else 194 + #define ctnetlink_dump_counters(a, b, c) (0) 195 + #endif 196 + 197 + #ifdef CONFIG_IP_NF_CONNTRACK_MARK 198 + static inline int 199 + ctnetlink_dump_mark(struct sk_buff *skb, const struct ip_conntrack *ct) 200 + { 201 + u_int32_t mark = htonl(ct->mark); 202 + 203 + NFA_PUT(skb, CTA_MARK, sizeof(u_int32_t), &mark); 204 + return 0; 205 + 206 + nfattr_failure: 207 + return -1; 208 + } 209 + #else 210 + #define ctnetlink_dump_mark(a, b) (0) 211 + #endif 212 + 213 + static inline int 214 + ctnetlink_dump_id(struct sk_buff *skb, const struct ip_conntrack *ct) 215 + { 216 + u_int32_t id = htonl(ct->id); 217 + NFA_PUT(skb, CTA_ID, sizeof(u_int32_t), &id); 218 + return 0; 219 + 220 + nfattr_failure: 221 + return -1; 222 + } 223 + 224 + static inline int 225 + ctnetlink_dump_use(struct sk_buff *skb, const struct ip_conntrack *ct) 226 + { 227 + unsigned int use = htonl(atomic_read(&ct->ct_general.use)); 228 + 229 + NFA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use); 230 + return 0; 231 + 232 + nfattr_failure: 233 + return -1; 234 + } 235 + 236 + #define tuple(ct, dir) (&(ct)->tuplehash[dir].tuple) 237 + 238 + static int 239 + ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, 240 + int event, int nowait, 241 + const struct ip_conntrack *ct) 242 + { 243 + struct nlmsghdr *nlh; 244 + struct nfgenmsg *nfmsg; 245 + struct nfattr *nest_parms; 246 + unsigned char *b; 247 + 248 + b = skb->tail; 249 + 250 + event |= NFNL_SUBSYS_CTNETLINK << 8; 251 + nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); 252 + nfmsg = NLMSG_DATA(nlh); 253 + 254 + nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; 255 + nfmsg->nfgen_family = AF_INET; 256 + nfmsg->version = NFNETLINK_V0; 257 + nfmsg->res_id = 0; 258 + 259 + nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG); 260 + if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) 261 + goto nfattr_failure; 262 + NFA_NEST_END(skb, nest_parms); 263 + 264 + nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY); 265 + if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) 266 + goto nfattr_failure; 267 + NFA_NEST_END(skb, nest_parms); 268 + 269 + if (ctnetlink_dump_status(skb, ct) < 0 || 270 + ctnetlink_dump_timeout(skb, ct) < 0 || 271 + ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || 272 + ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0 || 273 + ctnetlink_dump_protoinfo(skb, ct) < 0 || 274 + ctnetlink_dump_helpinfo(skb, ct) < 0 || 275 + ctnetlink_dump_mark(skb, ct) < 0 || 276 + ctnetlink_dump_id(skb, ct) < 0 || 277 + ctnetlink_dump_use(skb, ct) < 0) 278 + goto nfattr_failure; 279 + 280 + nlh->nlmsg_len = skb->tail - b; 281 + return skb->len; 282 + 283 + nlmsg_failure: 284 + nfattr_failure: 285 + skb_trim(skb, b - skb->data); 286 + return -1; 287 + } 288 + 289 + #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS 290 + static int ctnetlink_conntrack_event(struct notifier_block *this, 291 + unsigned long events, void *ptr) 292 + { 293 + struct nlmsghdr *nlh; 294 + struct nfgenmsg *nfmsg; 295 + struct nfattr *nest_parms; 296 + struct ip_conntrack *ct = (struct ip_conntrack *)ptr; 297 + struct sk_buff *skb; 298 + unsigned int type; 299 + unsigned char *b; 300 + unsigned int flags = 0, groups; 301 + 302 + /* ignore our fake conntrack entry */ 303 + if (ct == &ip_conntrack_untracked) 304 + return NOTIFY_DONE; 305 + 306 + if (events & IPCT_DESTROY) { 307 + type = IPCTNL_MSG_CT_DELETE; 308 + groups = NF_NETLINK_CONNTRACK_DESTROY; 309 + goto alloc_skb; 310 + } 311 + if (events & (IPCT_NEW | IPCT_RELATED)) { 312 + type = IPCTNL_MSG_CT_NEW; 313 + flags = NLM_F_CREATE|NLM_F_EXCL; 314 + /* dump everything */ 315 + events = ~0UL; 316 + groups = NF_NETLINK_CONNTRACK_NEW; 317 + goto alloc_skb; 318 + } 319 + if (events & (IPCT_STATUS | 320 + IPCT_PROTOINFO | 321 + IPCT_HELPER | 322 + IPCT_HELPINFO | 323 + IPCT_NATINFO)) { 324 + type = IPCTNL_MSG_CT_NEW; 325 + groups = NF_NETLINK_CONNTRACK_UPDATE; 326 + goto alloc_skb; 327 + } 328 + 329 + return NOTIFY_DONE; 330 + 331 + alloc_skb: 332 + /* FIXME: Check if there are any listeners before, don't hurt performance */ 333 + 334 + skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); 335 + if (!skb) 336 + return NOTIFY_DONE; 337 + 338 + b = skb->tail; 339 + 340 + type |= NFNL_SUBSYS_CTNETLINK << 8; 341 + nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg)); 342 + nfmsg = NLMSG_DATA(nlh); 343 + 344 + nlh->nlmsg_flags = flags; 345 + nfmsg->nfgen_family = AF_INET; 346 + nfmsg->version = NFNETLINK_V0; 347 + nfmsg->res_id = 0; 348 + 349 + nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG); 350 + if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) 351 + goto nfattr_failure; 352 + NFA_NEST_END(skb, nest_parms); 353 + 354 + nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY); 355 + if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) 356 + goto nfattr_failure; 357 + NFA_NEST_END(skb, nest_parms); 358 + 359 + /* NAT stuff is now a status flag */ 360 + if ((events & IPCT_STATUS || events & IPCT_NATINFO) 361 + && ctnetlink_dump_status(skb, ct) < 0) 362 + goto nfattr_failure; 363 + if (events & IPCT_REFRESH 364 + && ctnetlink_dump_timeout(skb, ct) < 0) 365 + goto nfattr_failure; 366 + if (events & IPCT_PROTOINFO 367 + && ctnetlink_dump_protoinfo(skb, ct) < 0) 368 + goto nfattr_failure; 369 + if (events & IPCT_HELPINFO 370 + && ctnetlink_dump_helpinfo(skb, ct) < 0) 371 + goto nfattr_failure; 372 + 373 + if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || 374 + ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) 375 + goto nfattr_failure; 376 + 377 + nlh->nlmsg_len = skb->tail - b; 378 + nfnetlink_send(skb, 0, groups, 0); 379 + return NOTIFY_DONE; 380 + 381 + nlmsg_failure: 382 + nfattr_failure: 383 + kfree_skb(skb); 384 + return NOTIFY_DONE; 385 + } 386 + #endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */ 387 + 388 + static int ctnetlink_done(struct netlink_callback *cb) 389 + { 390 + DEBUGP("entered %s\n", __FUNCTION__); 391 + return 0; 392 + } 393 + 394 + static int 395 + ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) 396 + { 397 + struct ip_conntrack *ct = NULL; 398 + struct ip_conntrack_tuple_hash *h; 399 + struct list_head *i; 400 + u_int32_t *id = (u_int32_t *) &cb->args[1]; 401 + 402 + DEBUGP("entered %s, last bucket=%lu id=%u\n", __FUNCTION__, 403 + cb->args[0], *id); 404 + 405 + read_lock_bh(&ip_conntrack_lock); 406 + for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++, *id = 0) { 407 + list_for_each(i, &ip_conntrack_hash[cb->args[0]]) { 408 + h = (struct ip_conntrack_tuple_hash *) i; 409 + if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) 410 + continue; 411 + ct = tuplehash_to_ctrack(h); 412 + if (ct->id <= *id) 413 + continue; 414 + if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, 415 + cb->nlh->nlmsg_seq, 416 + IPCTNL_MSG_CT_NEW, 417 + 1, ct) < 0) 418 + goto out; 419 + *id = ct->id; 420 + } 421 + } 422 + out: 423 + read_unlock_bh(&ip_conntrack_lock); 424 + 425 + DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id); 426 + 427 + return skb->len; 428 + } 429 + 430 + #ifdef CONFIG_IP_NF_CT_ACCT 431 + static int 432 + ctnetlink_dump_table_w(struct sk_buff *skb, struct netlink_callback *cb) 433 + { 434 + struct ip_conntrack *ct = NULL; 435 + struct ip_conntrack_tuple_hash *h; 436 + struct list_head *i; 437 + u_int32_t *id = (u_int32_t *) &cb->args[1]; 438 + 439 + DEBUGP("entered %s, last bucket=%u id=%u\n", __FUNCTION__, 440 + cb->args[0], *id); 441 + 442 + write_lock_bh(&ip_conntrack_lock); 443 + for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++, *id = 0) { 444 + list_for_each(i, &ip_conntrack_hash[cb->args[0]]) { 445 + h = (struct ip_conntrack_tuple_hash *) i; 446 + if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) 447 + continue; 448 + ct = tuplehash_to_ctrack(h); 449 + if (ct->id <= *id) 450 + continue; 451 + if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, 452 + cb->nlh->nlmsg_seq, 453 + IPCTNL_MSG_CT_NEW, 454 + 1, ct) < 0) 455 + goto out; 456 + *id = ct->id; 457 + 458 + memset(&ct->counters, 0, sizeof(ct->counters)); 459 + } 460 + } 461 + out: 462 + write_unlock_bh(&ip_conntrack_lock); 463 + 464 + DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id); 465 + 466 + return skb->len; 467 + } 468 + #endif 469 + 470 + static const int cta_min_ip[CTA_IP_MAX] = { 471 + [CTA_IP_V4_SRC-1] = sizeof(u_int32_t), 472 + [CTA_IP_V4_DST-1] = sizeof(u_int32_t), 473 + }; 474 + 475 + static inline int 476 + ctnetlink_parse_tuple_ip(struct nfattr *attr, struct ip_conntrack_tuple *tuple) 477 + { 478 + struct nfattr *tb[CTA_IP_MAX]; 479 + 480 + DEBUGP("entered %s\n", __FUNCTION__); 481 + 482 + memset(tb, 0, CTA_IP_MAX * sizeof(tb)); 483 + 484 + if (nfattr_parse_nested(tb, CTA_IP_MAX, attr) < 0) 485 + goto nfattr_failure; 486 + 487 + if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip)) 488 + return -EINVAL; 489 + 490 + if (!tb[CTA_IP_V4_SRC-1]) 491 + return -EINVAL; 492 + tuple->src.ip = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]); 493 + 494 + if (!tb[CTA_IP_V4_DST-1]) 495 + return -EINVAL; 496 + tuple->dst.ip = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]); 497 + 498 + DEBUGP("leaving\n"); 499 + 500 + return 0; 501 + 502 + nfattr_failure: 503 + return -1; 504 + } 505 + 506 + static const int cta_min_proto[CTA_PROTO_MAX] = { 507 + [CTA_PROTO_NUM-1] = sizeof(u_int16_t), 508 + [CTA_PROTO_SRC_PORT-1] = sizeof(u_int16_t), 509 + [CTA_PROTO_DST_PORT-1] = sizeof(u_int16_t), 510 + [CTA_PROTO_ICMP_TYPE-1] = sizeof(u_int8_t), 511 + [CTA_PROTO_ICMP_CODE-1] = sizeof(u_int8_t), 512 + [CTA_PROTO_ICMP_ID-1] = sizeof(u_int16_t), 513 + }; 514 + 515 + static inline int 516 + ctnetlink_parse_tuple_proto(struct nfattr *attr, 517 + struct ip_conntrack_tuple *tuple) 518 + { 519 + struct nfattr *tb[CTA_PROTO_MAX]; 520 + struct ip_conntrack_protocol *proto; 521 + int ret = 0; 522 + 523 + DEBUGP("entered %s\n", __FUNCTION__); 524 + 525 + memset(tb, 0, CTA_PROTO_MAX * sizeof(tb)); 526 + 527 + if (nfattr_parse_nested(tb, CTA_PROTO_MAX, attr) < 0) 528 + goto nfattr_failure; 529 + 530 + if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) 531 + return -EINVAL; 532 + 533 + if (!tb[CTA_PROTO_NUM-1]) 534 + return -EINVAL; 535 + tuple->dst.protonum = *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]); 536 + 537 + proto = ip_conntrack_proto_find_get(tuple->dst.protonum); 538 + 539 + if (likely(proto && proto->nfattr_to_tuple)) { 540 + ret = proto->nfattr_to_tuple(tb, tuple); 541 + ip_conntrack_proto_put(proto); 542 + } 543 + 544 + return ret; 545 + 546 + nfattr_failure: 547 + return -1; 548 + } 549 + 550 + static inline int 551 + ctnetlink_parse_tuple(struct nfattr *cda[], struct ip_conntrack_tuple *tuple, 552 + enum ctattr_tuple type) 553 + { 554 + struct nfattr *tb[CTA_TUPLE_MAX]; 555 + int err; 556 + 557 + DEBUGP("entered %s\n", __FUNCTION__); 558 + 559 + memset(tb, 0, CTA_TUPLE_MAX * sizeof(tb)); 560 + memset(tuple, 0, sizeof(*tuple)); 561 + 562 + if (nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]) < 0) 563 + goto nfattr_failure; 564 + 565 + if (!tb[CTA_TUPLE_IP-1]) 566 + return -EINVAL; 567 + 568 + err = ctnetlink_parse_tuple_ip(tb[CTA_TUPLE_IP-1], tuple); 569 + if (err < 0) 570 + return err; 571 + 572 + if (!tb[CTA_TUPLE_PROTO-1]) 573 + return -EINVAL; 574 + 575 + err = ctnetlink_parse_tuple_proto(tb[CTA_TUPLE_PROTO-1], tuple); 576 + if (err < 0) 577 + return err; 578 + 579 + /* orig and expect tuples get DIR_ORIGINAL */ 580 + if (type == CTA_TUPLE_REPLY) 581 + tuple->dst.dir = IP_CT_DIR_REPLY; 582 + else 583 + tuple->dst.dir = IP_CT_DIR_ORIGINAL; 584 + 585 + DUMP_TUPLE(tuple); 586 + 587 + DEBUGP("leaving\n"); 588 + 589 + return 0; 590 + 591 + nfattr_failure: 592 + return -1; 593 + } 594 + 595 + #ifdef CONFIG_IP_NF_NAT_NEEDED 596 + static const int cta_min_protonat[CTA_PROTONAT_MAX] = { 597 + [CTA_PROTONAT_PORT_MIN-1] = sizeof(u_int16_t), 598 + [CTA_PROTONAT_PORT_MAX-1] = sizeof(u_int16_t), 599 + }; 600 + 601 + static int ctnetlink_parse_nat_proto(struct nfattr *attr, 602 + const struct ip_conntrack *ct, 603 + struct ip_nat_range *range) 604 + { 605 + struct nfattr *tb[CTA_PROTONAT_MAX]; 606 + struct ip_nat_protocol *npt; 607 + 608 + DEBUGP("entered %s\n", __FUNCTION__); 609 + 610 + memset(tb, 0, CTA_PROTONAT_MAX * sizeof(tb)); 611 + 612 + if (nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr) < 0) 613 + goto nfattr_failure; 614 + 615 + if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat)) 616 + goto nfattr_failure; 617 + 618 + npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); 619 + if (!npt) 620 + return 0; 621 + 622 + if (!npt->nfattr_to_range) { 623 + ip_nat_proto_put(npt); 624 + return 0; 625 + } 626 + 627 + /* nfattr_to_range returns 1 if it parsed, 0 if not, neg. on error */ 628 + if (npt->nfattr_to_range(tb, range) > 0) 629 + range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED; 630 + 631 + ip_nat_proto_put(npt); 632 + 633 + DEBUGP("leaving\n"); 634 + return 0; 635 + 636 + nfattr_failure: 637 + return -1; 638 + } 639 + 640 + static inline int 641 + ctnetlink_parse_nat(struct nfattr *cda[], 642 + const struct ip_conntrack *ct, struct ip_nat_range *range) 643 + { 644 + struct nfattr *tb[CTA_NAT_MAX]; 645 + int err; 646 + 647 + DEBUGP("entered %s\n", __FUNCTION__); 648 + 649 + memset(tb, 0, CTA_NAT_MAX * sizeof(tb)); 650 + memset(range, 0, sizeof(*range)); 651 + 652 + if (nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]) < 0) 653 + goto nfattr_failure; 654 + 655 + if (tb[CTA_NAT_MINIP-1]) 656 + range->min_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MINIP-1]); 657 + 658 + if (!tb[CTA_NAT_MAXIP-1]) 659 + range->max_ip = range->min_ip; 660 + else 661 + range->max_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MAXIP-1]); 662 + 663 + if (range->min_ip) 664 + range->flags |= IP_NAT_RANGE_MAP_IPS; 665 + 666 + if (!tb[CTA_NAT_PROTO-1]) 667 + return 0; 668 + 669 + err = ctnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range); 670 + if (err < 0) 671 + return err; 672 + 673 + DEBUGP("leaving\n"); 674 + return 0; 675 + 676 + nfattr_failure: 677 + return -1; 678 + } 679 + #endif 680 + 681 + static inline int 682 + ctnetlink_parse_help(struct nfattr *attr, char **helper_name) 683 + { 684 + struct nfattr *tb[CTA_HELP_MAX]; 685 + 686 + DEBUGP("entered %s\n", __FUNCTION__); 687 + memset(tb, 0, CTA_HELP_MAX * sizeof(tb)); 688 + 689 + if (nfattr_parse_nested(tb, CTA_HELP_MAX, attr) < 0) 690 + goto nfattr_failure; 691 + 692 + if (!tb[CTA_HELP_NAME-1]) 693 + return -EINVAL; 694 + 695 + *helper_name = NFA_DATA(tb[CTA_HELP_NAME-1]); 696 + 697 + return 0; 698 + 699 + nfattr_failure: 700 + return -1; 701 + } 702 + 703 + static int 704 + ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, 705 + struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) 706 + { 707 + struct ip_conntrack_tuple_hash *h; 708 + struct ip_conntrack_tuple tuple; 709 + struct ip_conntrack *ct; 710 + int err = 0; 711 + 712 + DEBUGP("entered %s\n", __FUNCTION__); 713 + 714 + if (cda[CTA_TUPLE_ORIG-1]) 715 + err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG); 716 + else if (cda[CTA_TUPLE_REPLY-1]) 717 + err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY); 718 + else { 719 + /* Flush the whole table */ 720 + ip_conntrack_flush(); 721 + return 0; 722 + } 723 + 724 + if (err < 0) 725 + return err; 726 + 727 + h = ip_conntrack_find_get(&tuple, NULL); 728 + if (!h) { 729 + DEBUGP("tuple not found in conntrack hash\n"); 730 + return -ENOENT; 731 + } 732 + 733 + ct = tuplehash_to_ctrack(h); 734 + 735 + if (cda[CTA_ID-1]) { 736 + u_int32_t id = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_ID-1])); 737 + if (ct->id != id) { 738 + ip_conntrack_put(ct); 739 + return -ENOENT; 740 + } 741 + } 742 + if (del_timer(&ct->timeout)) { 743 + ip_conntrack_put(ct); 744 + ct->timeout.function((unsigned long)ct); 745 + return 0; 746 + } 747 + ip_conntrack_put(ct); 748 + DEBUGP("leaving\n"); 749 + 750 + return 0; 751 + } 752 + 753 + static int 754 + ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, 755 + struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) 756 + { 757 + struct ip_conntrack_tuple_hash *h; 758 + struct ip_conntrack_tuple tuple; 759 + struct ip_conntrack *ct; 760 + struct sk_buff *skb2 = NULL; 761 + int err = 0; 762 + 763 + DEBUGP("entered %s\n", __FUNCTION__); 764 + 765 + if (nlh->nlmsg_flags & NLM_F_DUMP) { 766 + struct nfgenmsg *msg = NLMSG_DATA(nlh); 767 + u32 rlen; 768 + 769 + if (msg->nfgen_family != AF_INET) 770 + return -EAFNOSUPPORT; 771 + 772 + if (NFNL_MSG_TYPE(nlh->nlmsg_type) == 773 + IPCTNL_MSG_CT_GET_CTRZERO) { 774 + #ifdef CONFIG_IP_NF_CT_ACCT 775 + if ((*errp = netlink_dump_start(ctnl, skb, nlh, 776 + ctnetlink_dump_table_w, 777 + ctnetlink_done)) != 0) 778 + return -EINVAL; 779 + #else 780 + return -ENOTSUPP; 781 + #endif 782 + } else { 783 + if ((*errp = netlink_dump_start(ctnl, skb, nlh, 784 + ctnetlink_dump_table, 785 + ctnetlink_done)) != 0) 786 + return -EINVAL; 787 + } 788 + 789 + rlen = NLMSG_ALIGN(nlh->nlmsg_len); 790 + if (rlen > skb->len) 791 + rlen = skb->len; 792 + skb_pull(skb, rlen); 793 + return 0; 794 + } 795 + 796 + if (cda[CTA_TUPLE_ORIG-1]) 797 + err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG); 798 + else if (cda[CTA_TUPLE_REPLY-1]) 799 + err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY); 800 + else 801 + return -EINVAL; 802 + 803 + if (err < 0) 804 + return err; 805 + 806 + h = ip_conntrack_find_get(&tuple, NULL); 807 + if (!h) { 808 + DEBUGP("tuple not found in conntrack hash"); 809 + return -ENOENT; 810 + } 811 + DEBUGP("tuple found\n"); 812 + ct = tuplehash_to_ctrack(h); 813 + 814 + err = -ENOMEM; 815 + skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); 816 + if (!skb2) { 817 + ip_conntrack_put(ct); 818 + return -ENOMEM; 819 + } 820 + NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; 821 + 822 + err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, 823 + IPCTNL_MSG_CT_NEW, 1, ct); 824 + ip_conntrack_put(ct); 825 + if (err <= 0) 826 + goto out; 827 + 828 + err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); 829 + if (err < 0) 830 + goto out; 831 + 832 + DEBUGP("leaving\n"); 833 + return 0; 834 + 835 + out: 836 + if (skb2) 837 + kfree_skb(skb2); 838 + return -1; 839 + } 840 + 841 + static inline int 842 + ctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[]) 843 + { 844 + unsigned long d, status = *(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1]); 845 + d = ct->status ^ status; 846 + 847 + if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING)) 848 + /* unchangeable */ 849 + return -EINVAL; 850 + 851 + if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY)) 852 + /* SEEN_REPLY bit can only be set */ 853 + return -EINVAL; 854 + 855 + 856 + if (d & IPS_ASSURED && !(status & IPS_ASSURED)) 857 + /* ASSURED bit can only be set */ 858 + return -EINVAL; 859 + 860 + if (cda[CTA_NAT-1]) { 861 + #ifndef CONFIG_IP_NF_NAT_NEEDED 862 + return -EINVAL; 863 + #else 864 + unsigned int hooknum; 865 + struct ip_nat_range range; 866 + 867 + if (ctnetlink_parse_nat(cda, ct, &range) < 0) 868 + return -EINVAL; 869 + 870 + DEBUGP("NAT: %u.%u.%u.%u-%u.%u.%u.%u:%u-%u\n", 871 + NIPQUAD(range.min_ip), NIPQUAD(range.max_ip), 872 + htons(range.min.all), htons(range.max.all)); 873 + 874 + /* This is tricky but it works. ip_nat_setup_info needs the 875 + * hook number as parameter, so let's do the correct 876 + * conversion and run away */ 877 + if (status & IPS_SRC_NAT_DONE) 878 + hooknum = NF_IP_POST_ROUTING; /* IP_NAT_MANIP_SRC */ 879 + else if (status & IPS_DST_NAT_DONE) 880 + hooknum = NF_IP_PRE_ROUTING; /* IP_NAT_MANIP_DST */ 881 + else 882 + return -EINVAL; /* Missing NAT flags */ 883 + 884 + DEBUGP("NAT status: %lu\n", 885 + status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK)); 886 + 887 + if (ip_nat_initialized(ct, hooknum)) 888 + return -EEXIST; 889 + ip_nat_setup_info(ct, &range, hooknum); 890 + 891 + DEBUGP("NAT status after setup_info: %lu\n", 892 + ct->status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK)); 893 + #endif 894 + } 895 + 896 + /* Be careful here, modifying NAT bits can screw up things, 897 + * so don't let users modify them directly if they don't pass 898 + * ip_nat_range. */ 899 + ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK); 900 + return 0; 901 + } 902 + 903 + 904 + static inline int 905 + ctnetlink_change_helper(struct ip_conntrack *ct, struct nfattr *cda[]) 906 + { 907 + struct ip_conntrack_helper *helper; 908 + char *helpname; 909 + int err; 910 + 911 + DEBUGP("entered %s\n", __FUNCTION__); 912 + 913 + /* don't change helper of sibling connections */ 914 + if (ct->master) 915 + return -EINVAL; 916 + 917 + err = ctnetlink_parse_help(cda[CTA_HELP-1], &helpname); 918 + if (err < 0) 919 + return err; 920 + 921 + helper = __ip_conntrack_helper_find_byname(helpname); 922 + if (!helper) { 923 + if (!strcmp(helpname, "")) 924 + helper = NULL; 925 + else 926 + return -EINVAL; 927 + } 928 + 929 + if (ct->helper) { 930 + if (!helper) { 931 + /* we had a helper before ... */ 932 + ip_ct_remove_expectations(ct); 933 + ct->helper = NULL; 934 + } else { 935 + /* need to zero data of old helper */ 936 + memset(&ct->help, 0, sizeof(ct->help)); 937 + } 938 + } 939 + 940 + ct->helper = helper; 941 + 942 + return 0; 943 + } 944 + 945 + static inline int 946 + ctnetlink_change_timeout(struct ip_conntrack *ct, struct nfattr *cda[]) 947 + { 948 + u_int32_t timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1])); 949 + 950 + if (!del_timer(&ct->timeout)) 951 + return -ETIME; 952 + 953 + ct->timeout.expires = jiffies + timeout * HZ; 954 + add_timer(&ct->timeout); 955 + 956 + return 0; 957 + } 958 + 959 + static int 960 + ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[]) 961 + { 962 + int err; 963 + 964 + DEBUGP("entered %s\n", __FUNCTION__); 965 + 966 + if (cda[CTA_HELP-1]) { 967 + err = ctnetlink_change_helper(ct, cda); 968 + if (err < 0) 969 + return err; 970 + } 971 + 972 + if (cda[CTA_TIMEOUT-1]) { 973 + err = ctnetlink_change_timeout(ct, cda); 974 + if (err < 0) 975 + return err; 976 + } 977 + 978 + if (cda[CTA_STATUS-1]) { 979 + err = ctnetlink_change_status(ct, cda); 980 + if (err < 0) 981 + return err; 982 + } 983 + 984 + DEBUGP("all done\n"); 985 + return 0; 986 + } 987 + 988 + static int 989 + ctnetlink_create_conntrack(struct nfattr *cda[], 990 + struct ip_conntrack_tuple *otuple, 991 + struct ip_conntrack_tuple *rtuple) 992 + { 993 + struct ip_conntrack *ct; 994 + int err = -EINVAL; 995 + 996 + DEBUGP("entered %s\n", __FUNCTION__); 997 + 998 + ct = ip_conntrack_alloc(otuple, rtuple); 999 + if (ct == NULL || IS_ERR(ct)) 1000 + return -ENOMEM; 1001 + 1002 + if (!cda[CTA_TIMEOUT-1]) 1003 + goto err; 1004 + ct->timeout.expires = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1])); 1005 + 1006 + ct->timeout.expires = jiffies + ct->timeout.expires * HZ; 1007 + ct->status |= IPS_CONFIRMED; 1008 + 1009 + err = ctnetlink_change_status(ct, cda); 1010 + if (err < 0) 1011 + goto err; 1012 + 1013 + ct->helper = ip_conntrack_helper_find_get(rtuple); 1014 + 1015 + add_timer(&ct->timeout); 1016 + ip_conntrack_hash_insert(ct); 1017 + 1018 + if (ct->helper) 1019 + ip_conntrack_helper_put(ct->helper); 1020 + 1021 + DEBUGP("conntrack with id %u inserted\n", ct->id); 1022 + return 0; 1023 + 1024 + err: 1025 + ip_conntrack_free(ct); 1026 + return err; 1027 + } 1028 + 1029 + static int 1030 + ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, 1031 + struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) 1032 + { 1033 + struct ip_conntrack_tuple otuple, rtuple; 1034 + struct ip_conntrack_tuple_hash *h = NULL; 1035 + int err = 0; 1036 + 1037 + DEBUGP("entered %s\n", __FUNCTION__); 1038 + 1039 + if (cda[CTA_TUPLE_ORIG-1]) { 1040 + err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG); 1041 + if (err < 0) 1042 + return err; 1043 + } 1044 + 1045 + if (cda[CTA_TUPLE_REPLY-1]) { 1046 + err = ctnetlink_parse_tuple(cda, &rtuple, CTA_TUPLE_REPLY); 1047 + if (err < 0) 1048 + return err; 1049 + } 1050 + 1051 + write_lock_bh(&ip_conntrack_lock); 1052 + if (cda[CTA_TUPLE_ORIG-1]) 1053 + h = __ip_conntrack_find(&otuple, NULL); 1054 + else if (cda[CTA_TUPLE_REPLY-1]) 1055 + h = __ip_conntrack_find(&rtuple, NULL); 1056 + 1057 + if (h == NULL) { 1058 + write_unlock_bh(&ip_conntrack_lock); 1059 + DEBUGP("no such conntrack, create new\n"); 1060 + err = -ENOENT; 1061 + if (nlh->nlmsg_flags & NLM_F_CREATE) 1062 + err = ctnetlink_create_conntrack(cda, &otuple, &rtuple); 1063 + goto out_unlock; 1064 + } else { 1065 + /* we only allow nat config for new conntracks */ 1066 + if (cda[CTA_NAT-1]) { 1067 + err = -EINVAL; 1068 + goto out_unlock; 1069 + } 1070 + } 1071 + 1072 + /* We manipulate the conntrack inside the global conntrack table lock, 1073 + * so there's no need to increase the refcount */ 1074 + DEBUGP("conntrack found\n"); 1075 + err = -EEXIST; 1076 + if (!(nlh->nlmsg_flags & NLM_F_EXCL)) 1077 + err = ctnetlink_change_conntrack(tuplehash_to_ctrack(h), cda); 1078 + 1079 + out_unlock: 1080 + write_unlock_bh(&ip_conntrack_lock); 1081 + return err; 1082 + } 1083 + 1084 + /*********************************************************************** 1085 + * EXPECT 1086 + ***********************************************************************/ 1087 + 1088 + static inline int 1089 + ctnetlink_exp_dump_tuple(struct sk_buff *skb, 1090 + const struct ip_conntrack_tuple *tuple, 1091 + enum ctattr_expect type) 1092 + { 1093 + struct nfattr *nest_parms = NFA_NEST(skb, type); 1094 + 1095 + if (ctnetlink_dump_tuples(skb, tuple) < 0) 1096 + goto nfattr_failure; 1097 + 1098 + NFA_NEST_END(skb, nest_parms); 1099 + 1100 + return 0; 1101 + 1102 + nfattr_failure: 1103 + return -1; 1104 + } 1105 + 1106 + static inline int 1107 + ctnetlink_exp_dump_expect(struct sk_buff *skb, 1108 + const struct ip_conntrack_expect *exp) 1109 + { 1110 + u_int32_t timeout = htonl((exp->timeout.expires - jiffies) / HZ); 1111 + u_int32_t id = htonl(exp->id); 1112 + struct nfattr *nest_parms = NFA_NEST(skb, CTA_EXPECT); 1113 + 1114 + if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0) 1115 + goto nfattr_failure; 1116 + if (ctnetlink_exp_dump_tuple(skb, &exp->mask, CTA_EXPECT_MASK) < 0) 1117 + goto nfattr_failure; 1118 + 1119 + NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(timeout), &timeout); 1120 + NFA_PUT(skb, CTA_EXPECT_ID, sizeof(u_int32_t), &id); 1121 + NFA_NEST_END(skb, nest_parms); 1122 + 1123 + return 0; 1124 + 1125 + nfattr_failure: 1126 + return -1; 1127 + } 1128 + 1129 + static int 1130 + ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq, 1131 + int event, 1132 + int nowait, 1133 + const struct ip_conntrack_expect *exp) 1134 + { 1135 + struct nlmsghdr *nlh; 1136 + struct nfgenmsg *nfmsg; 1137 + unsigned char *b; 1138 + 1139 + b = skb->tail; 1140 + 1141 + event |= NFNL_SUBSYS_CTNETLINK_EXP << 8; 1142 + nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); 1143 + nfmsg = NLMSG_DATA(nlh); 1144 + 1145 + nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; 1146 + nfmsg->nfgen_family = AF_INET; 1147 + nfmsg->version = NFNETLINK_V0; 1148 + nfmsg->res_id = 0; 1149 + 1150 + if (ctnetlink_exp_dump_expect(skb, exp) < 0) 1151 + goto nfattr_failure; 1152 + 1153 + nlh->nlmsg_len = skb->tail - b; 1154 + return skb->len; 1155 + 1156 + nlmsg_failure: 1157 + nfattr_failure: 1158 + skb_trim(skb, b - skb->data); 1159 + return -1; 1160 + } 1161 + 1162 + #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS 1163 + static int ctnetlink_expect_event(struct notifier_block *this, 1164 + unsigned long events, void *ptr) 1165 + { 1166 + struct nlmsghdr *nlh; 1167 + struct nfgenmsg *nfmsg; 1168 + struct ip_conntrack_expect *exp = (struct ip_conntrack_expect *)ptr; 1169 + struct sk_buff *skb; 1170 + unsigned int type; 1171 + unsigned char *b; 1172 + int flags = 0; 1173 + u16 proto; 1174 + 1175 + if (events & IPEXP_NEW) { 1176 + type = IPCTNL_MSG_EXP_NEW; 1177 + flags = NLM_F_CREATE|NLM_F_EXCL; 1178 + } else 1179 + return NOTIFY_DONE; 1180 + 1181 + skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); 1182 + if (!skb) 1183 + return NOTIFY_DONE; 1184 + 1185 + b = skb->tail; 1186 + 1187 + type |= NFNL_SUBSYS_CTNETLINK << 8; 1188 + nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg)); 1189 + nfmsg = NLMSG_DATA(nlh); 1190 + 1191 + nlh->nlmsg_flags = flags; 1192 + nfmsg->nfgen_family = AF_INET; 1193 + nfmsg->version = NFNETLINK_V0; 1194 + nfmsg->res_id = 0; 1195 + 1196 + if (ctnetlink_exp_dump_expect(skb, exp) < 0) 1197 + goto nfattr_failure; 1198 + 1199 + nlh->nlmsg_len = skb->tail - b; 1200 + proto = exp->tuple.dst.protonum; 1201 + nfnetlink_send(skb, 0, NF_NETLINK_CONNTRACK_EXP_NEW, 0); 1202 + return NOTIFY_DONE; 1203 + 1204 + nlmsg_failure: 1205 + nfattr_failure: 1206 + kfree_skb(skb); 1207 + return NOTIFY_DONE; 1208 + } 1209 + #endif 1210 + 1211 + static int 1212 + ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) 1213 + { 1214 + struct ip_conntrack_expect *exp = NULL; 1215 + struct list_head *i; 1216 + u_int32_t *id = (u_int32_t *) &cb->args[0]; 1217 + 1218 + DEBUGP("entered %s, last id=%llu\n", __FUNCTION__, *id); 1219 + 1220 + read_lock_bh(&ip_conntrack_lock); 1221 + list_for_each(i, &ip_conntrack_expect_list) { 1222 + exp = (struct ip_conntrack_expect *) i; 1223 + if (exp->id <= *id) 1224 + continue; 1225 + if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid, 1226 + cb->nlh->nlmsg_seq, 1227 + IPCTNL_MSG_EXP_NEW, 1228 + 1, exp) < 0) 1229 + goto out; 1230 + *id = exp->id; 1231 + } 1232 + out: 1233 + read_unlock_bh(&ip_conntrack_lock); 1234 + 1235 + DEBUGP("leaving, last id=%llu\n", *id); 1236 + 1237 + return skb->len; 1238 + } 1239 + 1240 + static int 1241 + ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, 1242 + struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) 1243 + { 1244 + struct ip_conntrack_tuple tuple; 1245 + struct ip_conntrack_expect *exp; 1246 + struct sk_buff *skb2; 1247 + int err = 0; 1248 + 1249 + DEBUGP("entered %s\n", __FUNCTION__); 1250 + 1251 + if (nlh->nlmsg_flags & NLM_F_DUMP) { 1252 + struct nfgenmsg *msg = NLMSG_DATA(nlh); 1253 + u32 rlen; 1254 + 1255 + if (msg->nfgen_family != AF_INET) 1256 + return -EAFNOSUPPORT; 1257 + 1258 + if ((*errp = netlink_dump_start(ctnl, skb, nlh, 1259 + ctnetlink_exp_dump_table, 1260 + ctnetlink_done)) != 0) 1261 + return -EINVAL; 1262 + rlen = NLMSG_ALIGN(nlh->nlmsg_len); 1263 + if (rlen > skb->len) 1264 + rlen = skb->len; 1265 + skb_pull(skb, rlen); 1266 + return 0; 1267 + } 1268 + 1269 + if (cda[CTA_TUPLE_ORIG-1]) 1270 + err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG); 1271 + else if (cda[CTA_TUPLE_REPLY-1]) 1272 + err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY); 1273 + else 1274 + return -EINVAL; 1275 + 1276 + if (err < 0) 1277 + return err; 1278 + 1279 + exp = ip_conntrack_expect_find_get(&tuple); 1280 + if (!exp) 1281 + return -ENOENT; 1282 + 1283 + err = -ENOMEM; 1284 + skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 1285 + if (!skb2) 1286 + goto out; 1287 + NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; 1288 + 1289 + err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, 1290 + nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, 1291 + 1, exp); 1292 + if (err <= 0) 1293 + goto out; 1294 + 1295 + ip_conntrack_expect_put(exp); 1296 + 1297 + err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); 1298 + if (err < 0) 1299 + goto free; 1300 + 1301 + return err; 1302 + 1303 + out: 1304 + ip_conntrack_expect_put(exp); 1305 + free: 1306 + if (skb2) 1307 + kfree_skb(skb2); 1308 + return err; 1309 + } 1310 + 1311 + static int 1312 + ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, 1313 + struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) 1314 + { 1315 + struct ip_conntrack_expect *exp, *tmp; 1316 + struct ip_conntrack_tuple tuple; 1317 + struct ip_conntrack_helper *h; 1318 + int err; 1319 + 1320 + /* delete by tuple needs either orig or reply tuple */ 1321 + if (cda[CTA_TUPLE_ORIG-1]) 1322 + err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG); 1323 + else if (cda[CTA_TUPLE_REPLY-1]) 1324 + err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY); 1325 + else if (cda[CTA_HELP_NAME-1]) { 1326 + char *name = NFA_DATA(cda[CTA_HELP_NAME-1]); 1327 + 1328 + /* delete all expectations for this helper */ 1329 + write_lock_bh(&ip_conntrack_lock); 1330 + h = __ip_conntrack_helper_find_byname(name); 1331 + if (!h) { 1332 + write_unlock_bh(&ip_conntrack_lock); 1333 + return -EINVAL; 1334 + } 1335 + list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, 1336 + list) { 1337 + if (exp->master->helper == h 1338 + && del_timer(&exp->timeout)) 1339 + __ip_ct_expect_unlink_destroy(exp); 1340 + } 1341 + write_unlock(&ip_conntrack_lock); 1342 + return 0; 1343 + } else { 1344 + /* This basically means we have to flush everything*/ 1345 + write_lock_bh(&ip_conntrack_lock); 1346 + list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, 1347 + list) { 1348 + if (del_timer(&exp->timeout)) 1349 + __ip_ct_expect_unlink_destroy(exp); 1350 + } 1351 + write_unlock_bh(&ip_conntrack_lock); 1352 + return 0; 1353 + } 1354 + 1355 + if (err < 0) 1356 + return err; 1357 + 1358 + /* bump usage count to 2 */ 1359 + exp = ip_conntrack_expect_find_get(&tuple); 1360 + if (!exp) 1361 + return -ENOENT; 1362 + 1363 + if (cda[CTA_EXPECT_ID-1]) { 1364 + u_int32_t id = *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]); 1365 + if (exp->id != ntohl(id)) { 1366 + ip_conntrack_expect_put(exp); 1367 + return -ENOENT; 1368 + } 1369 + } 1370 + 1371 + /* after list removal, usage count == 1 */ 1372 + ip_conntrack_unexpect_related(exp); 1373 + /* have to put what we 'get' above. after this line usage count == 0 */ 1374 + ip_conntrack_expect_put(exp); 1375 + 1376 + return 0; 1377 + } 1378 + static int 1379 + ctnetlink_change_expect(struct ip_conntrack_expect *x, struct nfattr *cda[]) 1380 + { 1381 + return -EOPNOTSUPP; 1382 + } 1383 + 1384 + static int 1385 + ctnetlink_create_expect(struct nfattr *cda[]) 1386 + { 1387 + struct ip_conntrack_tuple tuple, mask, master_tuple; 1388 + struct ip_conntrack_tuple_hash *h = NULL; 1389 + struct ip_conntrack_expect *exp; 1390 + struct ip_conntrack *ct; 1391 + int err = 0; 1392 + 1393 + DEBUGP("entered %s\n", __FUNCTION__); 1394 + 1395 + err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE); 1396 + if (err < 0) 1397 + return err; 1398 + err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASK); 1399 + if (err < 0) 1400 + return err; 1401 + 1402 + if (cda[CTA_TUPLE_ORIG-1]) 1403 + err = ctnetlink_parse_tuple(cda, &master_tuple, CTA_TUPLE_ORIG); 1404 + else if (cda[CTA_TUPLE_REPLY-1]) 1405 + err = ctnetlink_parse_tuple(cda, &master_tuple, 1406 + CTA_TUPLE_REPLY); 1407 + else 1408 + return -EINVAL; 1409 + 1410 + if (err < 0) 1411 + return err; 1412 + 1413 + /* Look for master conntrack of this expectation */ 1414 + h = ip_conntrack_find_get(&master_tuple, NULL); 1415 + if (!h) 1416 + return -ENOENT; 1417 + ct = tuplehash_to_ctrack(h); 1418 + 1419 + if (!ct->helper) { 1420 + /* such conntrack hasn't got any helper, abort */ 1421 + err = -EINVAL; 1422 + goto out; 1423 + } 1424 + 1425 + exp = ip_conntrack_expect_alloc(ct); 1426 + if (!exp) { 1427 + err = -ENOMEM; 1428 + goto out; 1429 + } 1430 + 1431 + exp->expectfn = NULL; 1432 + exp->master = ct; 1433 + memcpy(&exp->tuple, &tuple, sizeof(struct ip_conntrack_tuple)); 1434 + memcpy(&exp->mask, &mask, sizeof(struct ip_conntrack_tuple)); 1435 + 1436 + err = ip_conntrack_expect_related(exp); 1437 + ip_conntrack_expect_put(exp); 1438 + 1439 + out: 1440 + ip_conntrack_put(tuplehash_to_ctrack(h)); 1441 + return err; 1442 + } 1443 + 1444 + static int 1445 + ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, 1446 + struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) 1447 + { 1448 + struct ip_conntrack_tuple tuple; 1449 + struct ip_conntrack_expect *exp; 1450 + int err = 0; 1451 + 1452 + DEBUGP("entered %s\n", __FUNCTION__); 1453 + 1454 + if (!cda[CTA_EXPECT_TUPLE-1] || !cda[CTA_EXPECT_MASK-1]) 1455 + return -EINVAL; 1456 + 1457 + err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE); 1458 + if (err < 0) 1459 + return err; 1460 + 1461 + write_lock_bh(&ip_conntrack_lock); 1462 + exp = __ip_conntrack_expect_find(&tuple); 1463 + 1464 + if (!exp) { 1465 + write_unlock_bh(&ip_conntrack_lock); 1466 + err = -ENOENT; 1467 + if (nlh->nlmsg_flags & NLM_F_CREATE) 1468 + err = ctnetlink_create_expect(cda); 1469 + return err; 1470 + } 1471 + 1472 + err = -EEXIST; 1473 + if (!(nlh->nlmsg_flags & NLM_F_EXCL)) 1474 + err = ctnetlink_change_expect(exp, cda); 1475 + write_unlock_bh(&ip_conntrack_lock); 1476 + 1477 + DEBUGP("leaving\n"); 1478 + 1479 + return err; 1480 + } 1481 + 1482 + #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS 1483 + static struct notifier_block ctnl_notifier = { 1484 + .notifier_call = ctnetlink_conntrack_event, 1485 + }; 1486 + 1487 + static struct notifier_block ctnl_notifier_exp = { 1488 + .notifier_call = ctnetlink_expect_event, 1489 + }; 1490 + #endif 1491 + 1492 + static struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = { 1493 + [IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack, 1494 + .cap_required = CAP_NET_ADMIN }, 1495 + [IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack, 1496 + .cap_required = CAP_NET_ADMIN }, 1497 + [IPCTNL_MSG_CT_DELETE] = { .call = ctnetlink_del_conntrack, 1498 + .cap_required = CAP_NET_ADMIN }, 1499 + [IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack, 1500 + .cap_required = CAP_NET_ADMIN }, 1501 + }; 1502 + 1503 + static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_MAX] = { 1504 + [IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect, 1505 + .cap_required = CAP_NET_ADMIN }, 1506 + [IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect, 1507 + .cap_required = CAP_NET_ADMIN }, 1508 + [IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect, 1509 + .cap_required = CAP_NET_ADMIN }, 1510 + }; 1511 + 1512 + static struct nfnetlink_subsystem ctnl_subsys = { 1513 + .name = "conntrack", 1514 + .subsys_id = NFNL_SUBSYS_CTNETLINK, 1515 + .cb_count = IPCTNL_MSG_MAX, 1516 + .attr_count = CTA_MAX, 1517 + .cb = ctnl_cb, 1518 + }; 1519 + 1520 + static struct nfnetlink_subsystem ctnl_exp_subsys = { 1521 + .name = "conntrack_expect", 1522 + .subsys_id = NFNL_SUBSYS_CTNETLINK_EXP, 1523 + .cb_count = IPCTNL_MSG_EXP_MAX, 1524 + .attr_count = CTA_MAX, 1525 + .cb = ctnl_exp_cb, 1526 + }; 1527 + 1528 + static int __init ctnetlink_init(void) 1529 + { 1530 + int ret; 1531 + 1532 + printk("ctnetlink v%s: registering with nfnetlink.\n", version); 1533 + ret = nfnetlink_subsys_register(&ctnl_subsys); 1534 + if (ret < 0) { 1535 + printk("ctnetlink_init: cannot register with nfnetlink.\n"); 1536 + goto err_out; 1537 + } 1538 + 1539 + ret = nfnetlink_subsys_register(&ctnl_exp_subsys); 1540 + if (ret < 0) { 1541 + printk("ctnetlink_init: cannot register exp with nfnetlink.\n"); 1542 + goto err_unreg_subsys; 1543 + } 1544 + 1545 + #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS 1546 + ret = ip_conntrack_register_notifier(&ctnl_notifier); 1547 + if (ret < 0) { 1548 + printk("ctnetlink_init: cannot register notifier.\n"); 1549 + goto err_unreg_exp_subsys; 1550 + } 1551 + 1552 + ret = ip_conntrack_expect_register_notifier(&ctnl_notifier_exp); 1553 + if (ret < 0) { 1554 + printk("ctnetlink_init: cannot expect register notifier.\n"); 1555 + goto err_unreg_notifier; 1556 + } 1557 + #endif 1558 + 1559 + return 0; 1560 + 1561 + #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS 1562 + err_unreg_notifier: 1563 + ip_conntrack_unregister_notifier(&ctnl_notifier); 1564 + err_unreg_exp_subsys: 1565 + nfnetlink_subsys_unregister(&ctnl_exp_subsys); 1566 + #endif 1567 + err_unreg_subsys: 1568 + nfnetlink_subsys_unregister(&ctnl_subsys); 1569 + err_out: 1570 + return ret; 1571 + } 1572 + 1573 + static void __exit ctnetlink_exit(void) 1574 + { 1575 + printk("ctnetlink: unregistering from nfnetlink.\n"); 1576 + 1577 + #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS 1578 + ip_conntrack_unregister_notifier(&ctnl_notifier_exp); 1579 + ip_conntrack_unregister_notifier(&ctnl_notifier); 1580 + #endif 1581 + 1582 + nfnetlink_subsys_unregister(&ctnl_exp_subsys); 1583 + nfnetlink_subsys_unregister(&ctnl_subsys); 1584 + return; 1585 + } 1586 + 1587 + module_init(ctnetlink_init); 1588 + module_exit(ctnetlink_exit);
+57 -7
net/ipv4/netfilter/ip_conntrack_proto_icmp.c
··· 109 109 return NF_ACCEPT; 110 110 } 111 111 112 + static u_int8_t valid_new[] = { 113 + [ICMP_ECHO] = 1, 114 + [ICMP_TIMESTAMP] = 1, 115 + [ICMP_INFO_REQUEST] = 1, 116 + [ICMP_ADDRESS] = 1 117 + }; 118 + 112 119 /* Called when a new connection for this protocol found. */ 113 120 static int icmp_new(struct ip_conntrack *conntrack, 114 121 const struct sk_buff *skb) 115 122 { 116 - static u_int8_t valid_new[] 117 - = { [ICMP_ECHO] = 1, 118 - [ICMP_TIMESTAMP] = 1, 119 - [ICMP_INFO_REQUEST] = 1, 120 - [ICMP_ADDRESS] = 1 }; 121 - 122 123 if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new) 123 124 || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) { 124 125 /* Can't create a new ICMP `conn' with this. */ ··· 160 159 return NF_ACCEPT; 161 160 } 162 161 163 - innerproto = ip_ct_find_proto(inside->ip.protocol); 162 + innerproto = ip_conntrack_proto_find_get(inside->ip.protocol); 164 163 dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp) + inside->ip.ihl*4; 165 164 /* Are they talking about one of our connections? */ 166 165 if (!ip_ct_get_tuple(&inside->ip, skb, dataoff, &origtuple, innerproto)) { 167 166 DEBUGP("icmp_error: ! get_tuple p=%u", inside->ip.protocol); 167 + ip_conntrack_proto_put(innerproto); 168 168 return NF_ACCEPT; 169 169 } 170 170 ··· 173 171 been preserved inside the ICMP. */ 174 172 if (!ip_ct_invert_tuple(&innertuple, &origtuple, innerproto)) { 175 173 DEBUGP("icmp_error_track: Can't invert tuple\n"); 174 + ip_conntrack_proto_put(innerproto); 176 175 return NF_ACCEPT; 177 176 } 177 + ip_conntrack_proto_put(innerproto); 178 178 179 179 *ctinfo = IP_CT_RELATED; 180 180 ··· 270 266 return icmp_error_message(skb, ctinfo, hooknum); 271 267 } 272 268 269 + #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ 270 + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) 271 + static int icmp_tuple_to_nfattr(struct sk_buff *skb, 272 + const struct ip_conntrack_tuple *t) 273 + { 274 + NFA_PUT(skb, CTA_PROTO_ICMP_ID, sizeof(u_int16_t), 275 + &t->src.u.icmp.id); 276 + NFA_PUT(skb, CTA_PROTO_ICMP_TYPE, sizeof(u_int8_t), 277 + &t->dst.u.icmp.type); 278 + NFA_PUT(skb, CTA_PROTO_ICMP_CODE, sizeof(u_int8_t), 279 + &t->dst.u.icmp.code); 280 + 281 + if (t->dst.u.icmp.type >= sizeof(valid_new) 282 + || !valid_new[t->dst.u.icmp.type]) 283 + return -EINVAL; 284 + 285 + return 0; 286 + 287 + nfattr_failure: 288 + return -1; 289 + } 290 + 291 + static int icmp_nfattr_to_tuple(struct nfattr *tb[], 292 + struct ip_conntrack_tuple *tuple) 293 + { 294 + if (!tb[CTA_PROTO_ICMP_TYPE-1] 295 + || !tb[CTA_PROTO_ICMP_CODE-1] 296 + || !tb[CTA_PROTO_ICMP_ID-1]) 297 + return -1; 298 + 299 + tuple->dst.u.icmp.type = 300 + *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_TYPE-1]); 301 + tuple->dst.u.icmp.code = 302 + *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_CODE-1]); 303 + tuple->src.u.icmp.id = 304 + *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]); 305 + 306 + return 0; 307 + } 308 + #endif 309 + 273 310 struct ip_conntrack_protocol ip_conntrack_protocol_icmp = 274 311 { 275 312 .proto = IPPROTO_ICMP, ··· 322 277 .packet = icmp_packet, 323 278 .new = icmp_new, 324 279 .error = icmp_error, 280 + #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ 281 + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) 282 + .tuple_to_nfattr = icmp_tuple_to_nfattr, 283 + .nfattr_to_tuple = icmp_nfattr_to_tuple, 284 + #endif 325 285 };
+6 -1
net/ipv4/netfilter/ip_conntrack_proto_sctp.c
··· 505 505 .packet = sctp_packet, 506 506 .new = sctp_new, 507 507 .destroy = NULL, 508 - .me = THIS_MODULE 508 + .me = THIS_MODULE, 509 + #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ 510 + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) 511 + .tuple_to_nfattr = ip_ct_port_tuple_to_nfattr, 512 + .nfattr_to_tuple = ip_ct_port_nfattr_to_tuple, 513 + #endif 509 514 }; 510 515 511 516 #ifdef CONFIG_SYSCTL
+23
net/ipv4/netfilter/ip_conntrack_proto_tcp.c
··· 336 336 return seq_printf(s, "%s ", tcp_conntrack_names[state]); 337 337 } 338 338 339 + #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ 340 + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) 341 + static int tcp_to_nfattr(struct sk_buff *skb, struct nfattr *nfa, 342 + const struct ip_conntrack *ct) 343 + { 344 + read_lock_bh(&tcp_lock); 345 + NFA_PUT(skb, CTA_PROTOINFO_TCP_STATE, sizeof(u_int8_t), 346 + &ct->proto.tcp.state); 347 + read_unlock_bh(&tcp_lock); 348 + 349 + return 0; 350 + 351 + nfattr_failure: 352 + return -1; 353 + } 354 + #endif 355 + 339 356 static unsigned int get_conntrack_index(const struct tcphdr *tcph) 340 357 { 341 358 if (tcph->rst) return TCP_RST_SET; ··· 1117 1100 .packet = tcp_packet, 1118 1101 .new = tcp_new, 1119 1102 .error = tcp_error, 1103 + #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ 1104 + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) 1105 + .to_nfattr = tcp_to_nfattr, 1106 + .tuple_to_nfattr = ip_ct_port_tuple_to_nfattr, 1107 + .nfattr_to_tuple = ip_ct_port_nfattr_to_tuple, 1108 + #endif 1120 1109 };
+5
net/ipv4/netfilter/ip_conntrack_proto_udp.c
··· 145 145 .packet = udp_packet, 146 146 .new = udp_new, 147 147 .error = udp_error, 148 + #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ 149 + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) 150 + .tuple_to_nfattr = ip_ct_port_tuple_to_nfattr, 151 + .nfattr_to_tuple = ip_ct_port_nfattr_to_tuple, 152 + #endif 148 153 };
+31 -7
net/ipv4/netfilter/ip_conntrack_standalone.c
··· 5 5 */ 6 6 7 7 /* (C) 1999-2001 Paul `Rusty' Russell 8 - * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> 8 + * (C) 2002-2005 Netfilter Core Team <coreteam@netfilter.org> 9 9 * 10 10 * This program is free software; you can redistribute it and/or modify 11 11 * it under the terms of the GNU General Public License version 2 as ··· 147 147 if (DIRECTION(hash)) 148 148 return 0; 149 149 150 - proto = ip_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL] 151 - .tuple.dst.protonum); 150 + proto = __ip_conntrack_proto_find(conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); 152 151 IP_NF_ASSERT(proto); 153 152 154 153 if (seq_printf(s, "%-8s %u %ld ", ··· 282 283 seq_printf(s, "proto=%u ", expect->tuple.dst.protonum); 283 284 284 285 print_tuple(s, &expect->tuple, 285 - ip_ct_find_proto(expect->tuple.dst.protonum)); 286 + __ip_conntrack_proto_find(expect->tuple.dst.protonum)); 286 287 return seq_putc(s, '\n'); 287 288 } 288 289 ··· 991 992 EXPORT_SYMBOL(ip_conntrack_helper_unregister); 992 993 EXPORT_SYMBOL(ip_ct_iterate_cleanup); 993 994 EXPORT_SYMBOL(ip_ct_refresh_acct); 994 - EXPORT_SYMBOL(ip_ct_protos); 995 - EXPORT_SYMBOL(ip_ct_find_proto); 995 + 996 996 EXPORT_SYMBOL(ip_conntrack_expect_alloc); 997 997 EXPORT_SYMBOL(ip_conntrack_expect_put); 998 + EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get); 998 999 EXPORT_SYMBOL(ip_conntrack_expect_related); 999 1000 EXPORT_SYMBOL(ip_conntrack_unexpect_related); 1001 + EXPORT_SYMBOL_GPL(ip_conntrack_expect_list); 1002 + EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find); 1003 + EXPORT_SYMBOL_GPL(__ip_ct_expect_unlink_destroy); 1004 + 1000 1005 EXPORT_SYMBOL(ip_conntrack_tuple_taken); 1001 1006 EXPORT_SYMBOL(ip_ct_gather_frags); 1002 1007 EXPORT_SYMBOL(ip_conntrack_htable_size); ··· 1008 1005 EXPORT_SYMBOL(ip_conntrack_hash); 1009 1006 EXPORT_SYMBOL(ip_conntrack_untracked); 1010 1007 EXPORT_SYMBOL_GPL(ip_conntrack_find_get); 1011 - EXPORT_SYMBOL_GPL(ip_conntrack_put); 1012 1008 #ifdef CONFIG_IP_NF_NAT_NEEDED 1013 1009 EXPORT_SYMBOL(ip_conntrack_tcp_update); 1010 + #endif 1011 + 1012 + EXPORT_SYMBOL_GPL(ip_conntrack_flush); 1013 + EXPORT_SYMBOL_GPL(__ip_conntrack_find); 1014 + 1015 + EXPORT_SYMBOL_GPL(ip_conntrack_alloc); 1016 + EXPORT_SYMBOL_GPL(ip_conntrack_free); 1017 + EXPORT_SYMBOL_GPL(ip_conntrack_hash_insert); 1018 + 1019 + EXPORT_SYMBOL_GPL(ip_ct_remove_expectations); 1020 + 1021 + EXPORT_SYMBOL_GPL(ip_conntrack_helper_find_get); 1022 + EXPORT_SYMBOL_GPL(ip_conntrack_helper_put); 1023 + EXPORT_SYMBOL_GPL(__ip_conntrack_helper_find_byname); 1024 + 1025 + EXPORT_SYMBOL_GPL(ip_conntrack_proto_find_get); 1026 + EXPORT_SYMBOL_GPL(ip_conntrack_proto_put); 1027 + EXPORT_SYMBOL_GPL(__ip_conntrack_proto_find); 1028 + #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ 1029 + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) 1030 + EXPORT_SYMBOL_GPL(ip_ct_port_tuple_to_nfattr); 1031 + EXPORT_SYMBOL_GPL(ip_ct_port_nfattr_to_tuple); 1014 1032 #endif
+92 -7
net/ipv4/netfilter/ip_nat_core.c
··· 47 47 static unsigned int ip_nat_htable_size; 48 48 49 49 static struct list_head *bysource; 50 + 51 + #define MAX_IP_NAT_PROTO 256 50 52 struct ip_nat_protocol *ip_nat_protos[MAX_IP_NAT_PROTO]; 51 53 54 + static inline struct ip_nat_protocol * 55 + __ip_nat_proto_find(u_int8_t protonum) 56 + { 57 + return ip_nat_protos[protonum]; 58 + } 59 + 60 + struct ip_nat_protocol * 61 + ip_nat_proto_find_get(u_int8_t protonum) 62 + { 63 + struct ip_nat_protocol *p; 64 + 65 + /* we need to disable preemption to make sure 'p' doesn't get 66 + * removed until we've grabbed the reference */ 67 + preempt_disable(); 68 + p = __ip_nat_proto_find(protonum); 69 + if (p) { 70 + if (!try_module_get(p->me)) 71 + p = &ip_nat_unknown_protocol; 72 + } 73 + preempt_enable(); 74 + 75 + return p; 76 + } 77 + 78 + void 79 + ip_nat_proto_put(struct ip_nat_protocol *p) 80 + { 81 + module_put(p->me); 82 + } 52 83 53 84 /* We keep an extra hash for each conntrack, for fast searching. */ 54 85 static inline unsigned int ··· 134 103 in_range(const struct ip_conntrack_tuple *tuple, 135 104 const struct ip_nat_range *range) 136 105 { 137 - struct ip_nat_protocol *proto = ip_nat_find_proto(tuple->dst.protonum); 106 + struct ip_nat_protocol *proto = 107 + __ip_nat_proto_find(tuple->dst.protonum); 138 108 139 109 /* If we are supposed to map IPs, then we must be in the 140 110 range specified, otherwise let this drag us onto a new src IP. */ ··· 248 216 struct ip_conntrack *conntrack, 249 217 enum ip_nat_manip_type maniptype) 250 218 { 251 - struct ip_nat_protocol *proto 252 - = ip_nat_find_proto(orig_tuple->dst.protonum); 219 + struct ip_nat_protocol *proto; 253 220 254 221 /* 1) If this srcip/proto/src-proto-part is currently mapped, 255 222 and that same mapping gives a unique tuple within the given ··· 273 242 /* 3) The per-protocol part of the manip is made to map into 274 243 the range to make a unique tuple. */ 275 244 245 + proto = ip_nat_proto_find_get(orig_tuple->dst.protonum); 246 + 276 247 /* Only bother mapping if it's not already in range and unique */ 277 248 if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) 278 249 || proto->in_range(tuple, maniptype, &range->min, &range->max)) 279 - && !ip_nat_used_tuple(tuple, conntrack)) 250 + && !ip_nat_used_tuple(tuple, conntrack)) { 251 + ip_nat_proto_put(proto); 280 252 return; 253 + } 281 254 282 255 /* Last change: get protocol to try to obtain unique tuple. */ 283 256 proto->unique_tuple(tuple, range, maniptype, conntrack); 257 + 258 + ip_nat_proto_put(proto); 284 259 } 285 260 286 261 unsigned int ··· 357 320 enum ip_nat_manip_type maniptype) 358 321 { 359 322 struct iphdr *iph; 323 + struct ip_nat_protocol *p; 360 324 361 325 if (!skb_ip_make_writable(pskb, iphdroff + sizeof(*iph))) 362 326 return 0; ··· 365 327 iph = (void *)(*pskb)->data + iphdroff; 366 328 367 329 /* Manipulate protcol part. */ 368 - if (!ip_nat_find_proto(proto)->manip_pkt(pskb, iphdroff, 369 - target, maniptype)) 330 + p = ip_nat_proto_find_get(proto); 331 + if (!p->manip_pkt(pskb, iphdroff, target, maniptype)) { 332 + ip_nat_proto_put(p); 370 333 return 0; 334 + } 335 + ip_nat_proto_put(p); 371 336 372 337 iph = (void *)(*pskb)->data + iphdroff; 373 338 ··· 466 425 467 426 if (!ip_ct_get_tuple(&inside->ip, *pskb, (*pskb)->nh.iph->ihl*4 + 468 427 sizeof(struct icmphdr) + inside->ip.ihl*4, 469 - &inner, ip_ct_find_proto(inside->ip.protocol))) 428 + &inner, 429 + __ip_conntrack_proto_find(inside->ip.protocol))) 470 430 return 0; 471 431 472 432 /* Change inner back to look like incoming packet. We do the ··· 536 494 /* Someone could be still looking at the proto in a bh. */ 537 495 synchronize_net(); 538 496 } 497 + 498 + #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ 499 + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) 500 + int 501 + ip_nat_port_range_to_nfattr(struct sk_buff *skb, 502 + const struct ip_nat_range *range) 503 + { 504 + NFA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(u_int16_t), 505 + &range->min.tcp.port); 506 + NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(u_int16_t), 507 + &range->max.tcp.port); 508 + 509 + return 0; 510 + 511 + nfattr_failure: 512 + return -1; 513 + } 514 + 515 + int 516 + ip_nat_port_nfattr_to_range(struct nfattr *tb[], struct ip_nat_range *range) 517 + { 518 + int ret = 0; 519 + 520 + /* we have to return whether we actually parsed something or not */ 521 + 522 + if (tb[CTA_PROTONAT_PORT_MIN-1]) { 523 + ret = 1; 524 + range->min.tcp.port = 525 + *(u_int16_t *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]); 526 + } 527 + 528 + if (!tb[CTA_PROTONAT_PORT_MAX-1]) { 529 + if (ret) 530 + range->max.tcp.port = range->min.tcp.port; 531 + } else { 532 + ret = 1; 533 + range->max.tcp.port = 534 + *(u_int16_t *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]); 535 + } 536 + 537 + return ret; 538 + } 539 + #endif 539 540 540 541 int __init ip_nat_init(void) 541 542 {
+7 -2
net/ipv4/netfilter/ip_nat_proto_icmp.c
··· 107 107 } 108 108 109 109 struct ip_nat_protocol ip_nat_protocol_icmp 110 - = { "ICMP", IPPROTO_ICMP, 110 + = { "ICMP", IPPROTO_ICMP, THIS_MODULE, 111 111 icmp_manip_pkt, 112 112 icmp_in_range, 113 113 icmp_unique_tuple, 114 114 icmp_print, 115 - icmp_print_range 115 + icmp_print_range, 116 + #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ 117 + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) 118 + ip_nat_port_range_to_nfattr, 119 + ip_nat_port_nfattr_to_range, 120 + #endif 116 121 };
+8 -2
net/ipv4/netfilter/ip_nat_proto_tcp.c
··· 12 12 #include <linux/ip.h> 13 13 #include <linux/tcp.h> 14 14 #include <linux/if.h> 15 + #include <linux/netfilter/nfnetlink_conntrack.h> 15 16 #include <linux/netfilter_ipv4/ip_nat.h> 16 17 #include <linux/netfilter_ipv4/ip_nat_rule.h> 17 18 #include <linux/netfilter_ipv4/ip_nat_protocol.h> ··· 171 170 } 172 171 173 172 struct ip_nat_protocol ip_nat_protocol_tcp 174 - = { "TCP", IPPROTO_TCP, 173 + = { "TCP", IPPROTO_TCP, THIS_MODULE, 175 174 tcp_manip_pkt, 176 175 tcp_in_range, 177 176 tcp_unique_tuple, 178 177 tcp_print, 179 - tcp_print_range 178 + tcp_print_range, 179 + #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ 180 + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) 181 + ip_nat_port_range_to_nfattr, 182 + ip_nat_port_nfattr_to_range, 183 + #endif 180 184 };
+7 -2
net/ipv4/netfilter/ip_nat_proto_udp.c
··· 157 157 } 158 158 159 159 struct ip_nat_protocol ip_nat_protocol_udp 160 - = { "UDP", IPPROTO_UDP, 160 + = { "UDP", IPPROTO_UDP, THIS_MODULE, 161 161 udp_manip_pkt, 162 162 udp_in_range, 163 163 udp_unique_tuple, 164 164 udp_print, 165 - udp_print_range 165 + udp_print_range, 166 + #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ 167 + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) 168 + ip_nat_port_range_to_nfattr, 169 + ip_nat_port_nfattr_to_range, 170 + #endif 166 171 };
+1 -1
net/ipv4/netfilter/ip_nat_proto_unknown.c
··· 61 61 } 62 62 63 63 struct ip_nat_protocol ip_nat_unknown_protocol = { 64 - "unknown", 0, 64 + "unknown", 0, THIS_MODULE, 65 65 unknown_manip_pkt, 66 66 unknown_in_range, 67 67 unknown_unique_tuple,
+2
net/ipv4/netfilter/ip_nat_standalone.c
··· 394 394 EXPORT_SYMBOL(ip_nat_setup_info); 395 395 EXPORT_SYMBOL(ip_nat_protocol_register); 396 396 EXPORT_SYMBOL(ip_nat_protocol_unregister); 397 + EXPORT_SYMBOL_GPL(ip_nat_proto_find_get); 398 + EXPORT_SYMBOL_GPL(ip_nat_proto_put); 397 399 EXPORT_SYMBOL(ip_nat_cheat_check); 398 400 EXPORT_SYMBOL(ip_nat_mangle_tcp_packet); 399 401 EXPORT_SYMBOL(ip_nat_mangle_udp_packet);
+1
net/netfilter/nfnetlink.c
··· 121 121 nfa->nfa_type = attrtype; 122 122 nfa->nfa_len = size; 123 123 memcpy(NFA_DATA(nfa), data, attrlen); 124 + memset(NFA_DATA(nfa) + attrlen, 0, NFA_ALIGN(size) - size); 124 125 } 125 126 126 127 int nfattr_parse(struct nfattr *tb[], int maxattr, struct nfattr *nfa, int len)