Home | History | Annotate | Download | only in netfilter
      1 /*
      2  * lib/netfilter/ct.c	Conntrack
      3  *
      4  *	This library is free software; you can redistribute it and/or
      5  *	modify it under the terms of the GNU Lesser General Public
      6  *	License as published by the Free Software Foundation version 2.1
      7  *	of the License.
      8  *
      9  * Copyright (c) 2003-2008 Thomas Graf <tgraf (at) suug.ch>
     10  * Copyright (c) 2007 Philip Craig <philipc (at) snapgear.com>
     11  * Copyright (c) 2007 Secure Computing Corporation
     12  * Copyright (c= 2008 Patrick McHardy <kaber (at) trash.net>
     13  */
     14 
     15 /**
     16  * @ingroup nfnl
     17  * @defgroup ct Conntrack
     18  * @brief
     19  * @{
     20  */
     21 
     22 #include <byteswap.h>
     23 #include <sys/types.h>
     24 #include <linux/netfilter/nfnetlink_conntrack.h>
     25 
     26 #include <netlink-local.h>
     27 #include <netlink/attr.h>
     28 #include <netlink/netfilter/nfnl.h>
     29 #include <netlink/netfilter/ct.h>
     30 
     31 static struct nl_cache_ops nfnl_ct_ops;
     32 
     33 #if __BYTE_ORDER == __BIG_ENDIAN
     34 static uint64_t ntohll(uint64_t x)
     35 {
     36 	return x;
     37 }
     38 #elif __BYTE_ORDER == __LITTLE_ENDIAN
     39 static uint64_t ntohll(uint64_t x)
     40 {
     41 	return __bswap_64(x);
     42 }
     43 #endif
     44 
     45 static struct nla_policy ct_policy[CTA_MAX+1] = {
     46 	[CTA_TUPLE_ORIG]	= { .type = NLA_NESTED },
     47 	[CTA_TUPLE_REPLY]	= { .type = NLA_NESTED },
     48 	[CTA_STATUS]		= { .type = NLA_U32 },
     49 	[CTA_PROTOINFO]		= { .type = NLA_NESTED },
     50 	//[CTA_HELP]
     51 	//[CTA_NAT_SRC]
     52 	[CTA_TIMEOUT]		= { .type = NLA_U32 },
     53 	[CTA_MARK]		= { .type = NLA_U32 },
     54 	[CTA_COUNTERS_ORIG]	= { .type = NLA_NESTED },
     55 	[CTA_COUNTERS_REPLY]	= { .type = NLA_NESTED },
     56 	[CTA_USE]		= { .type = NLA_U32 },
     57 	[CTA_ID]		= { .type = NLA_U32 },
     58 	//[CTA_NAT_DST]
     59 };
     60 
     61 static struct nla_policy ct_tuple_policy[CTA_TUPLE_MAX+1] = {
     62 	[CTA_TUPLE_IP]		= { .type = NLA_NESTED },
     63 	[CTA_TUPLE_PROTO]	= { .type = NLA_NESTED },
     64 };
     65 
     66 static struct nla_policy ct_ip_policy[CTA_IP_MAX+1] = {
     67 	[CTA_IP_V4_SRC]		= { .type = NLA_U32 },
     68 	[CTA_IP_V4_DST]		= { .type = NLA_U32 },
     69 	[CTA_IP_V6_SRC]		= { .minlen = 16 },
     70 	[CTA_IP_V6_DST]		= { .minlen = 16 },
     71 };
     72 
     73 static struct nla_policy ct_proto_policy[CTA_PROTO_MAX+1] = {
     74 	[CTA_PROTO_NUM]		= { .type = NLA_U8 },
     75 	[CTA_PROTO_SRC_PORT]	= { .type = NLA_U16 },
     76 	[CTA_PROTO_DST_PORT]	= { .type = NLA_U16 },
     77 	[CTA_PROTO_ICMP_ID]	= { .type = NLA_U16 },
     78 	[CTA_PROTO_ICMP_TYPE]	= { .type = NLA_U8 },
     79 	[CTA_PROTO_ICMP_CODE]	= { .type = NLA_U8 },
     80 	[CTA_PROTO_ICMPV6_ID]	= { .type = NLA_U16 },
     81 	[CTA_PROTO_ICMPV6_TYPE]	= { .type = NLA_U8 },
     82 	[CTA_PROTO_ICMPV6_CODE]	= { .type = NLA_U8 },
     83 };
     84 
     85 static struct nla_policy ct_protoinfo_policy[CTA_PROTOINFO_MAX+1] = {
     86 	[CTA_PROTOINFO_TCP]	= { .type = NLA_NESTED },
     87 };
     88 
     89 static struct nla_policy ct_protoinfo_tcp_policy[CTA_PROTOINFO_TCP_MAX+1] = {
     90 	[CTA_PROTOINFO_TCP_STATE]		= { .type = NLA_U8 },
     91 	[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]	= { .type = NLA_U8 },
     92 	[CTA_PROTOINFO_TCP_WSCALE_REPLY]	= { .type = NLA_U8 },
     93 	[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]	= { .minlen = 2 },
     94 	[CTA_PROTOINFO_TCP_FLAGS_REPLY]		= { .minlen = 2 },
     95 
     96 };
     97 
     98 static struct nla_policy ct_counters_policy[CTA_COUNTERS_MAX+1] = {
     99 	[CTA_COUNTERS_PACKETS]	= { .type = NLA_U64 },
    100 	[CTA_COUNTERS_BYTES]	= { .type = NLA_U64 },
    101 	[CTA_COUNTERS32_PACKETS]= { .type = NLA_U32 },
    102 	[CTA_COUNTERS32_BYTES]	= { .type = NLA_U32 },
    103 };
    104 
    105 static int ct_parse_ip(struct nfnl_ct *ct, int repl, struct nlattr *attr)
    106 {
    107 	struct nlattr *tb[CTA_IP_MAX+1];
    108 	struct nl_addr *addr;
    109 	int err;
    110 
    111         err = nla_parse_nested(tb, CTA_IP_MAX, attr, ct_ip_policy);
    112 	if (err < 0)
    113 		goto errout;
    114 
    115 	if (tb[CTA_IP_V4_SRC]) {
    116 		addr = nl_addr_alloc_attr(tb[CTA_IP_V4_SRC], AF_INET);
    117 		if (addr == NULL)
    118 			goto errout_enomem;
    119 		err = nfnl_ct_set_src(ct, repl, addr);
    120 		nl_addr_put(addr);
    121 		if (err < 0)
    122 			goto errout;
    123 	}
    124 	if (tb[CTA_IP_V4_DST]) {
    125 		addr = nl_addr_alloc_attr(tb[CTA_IP_V4_DST], AF_INET);
    126 		if (addr == NULL)
    127 			goto errout_enomem;
    128 		err = nfnl_ct_set_dst(ct, repl, addr);
    129 		nl_addr_put(addr);
    130 		if (err < 0)
    131 			goto errout;
    132 	}
    133 	if (tb[CTA_IP_V6_SRC]) {
    134 		addr = nl_addr_alloc_attr(tb[CTA_IP_V6_SRC], AF_INET6);
    135 		if (addr == NULL)
    136 			goto errout_enomem;
    137 		err = nfnl_ct_set_src(ct, repl, addr);
    138 		nl_addr_put(addr);
    139 		if (err < 0)
    140 			goto errout;
    141 	}
    142 	if (tb[CTA_IP_V6_DST]) {
    143 		addr = nl_addr_alloc_attr(tb[CTA_IP_V6_DST], AF_INET6);
    144 		if (addr == NULL)
    145 			goto errout_enomem;
    146 		err = nfnl_ct_set_dst(ct, repl, addr);
    147 		nl_addr_put(addr);
    148 		if (err < 0)
    149 			goto errout;
    150 	}
    151 
    152 	return 0;
    153 
    154 errout_enomem:
    155 	err = -NLE_NOMEM;
    156 errout:
    157 	return err;
    158 }
    159 
    160 static int ct_parse_proto(struct nfnl_ct *ct, int repl, struct nlattr *attr)
    161 {
    162 	struct nlattr *tb[CTA_PROTO_MAX+1];
    163 	int err;
    164 
    165 	err = nla_parse_nested(tb, CTA_PROTO_MAX, attr, ct_proto_policy);
    166 	if (err < 0)
    167 		return err;
    168 
    169 	if (!repl && tb[CTA_PROTO_NUM])
    170 		nfnl_ct_set_proto(ct, nla_get_u8(tb[CTA_PROTO_NUM]));
    171 	if (tb[CTA_PROTO_SRC_PORT])
    172 		nfnl_ct_set_src_port(ct, repl,
    173 			ntohs(nla_get_u16(tb[CTA_PROTO_SRC_PORT])));
    174 	if (tb[CTA_PROTO_DST_PORT])
    175 		nfnl_ct_set_dst_port(ct, repl,
    176 			ntohs(nla_get_u16(tb[CTA_PROTO_DST_PORT])));
    177 	if (tb[CTA_PROTO_ICMP_ID])
    178 		nfnl_ct_set_icmp_id(ct, repl,
    179 			ntohs(nla_get_u16(tb[CTA_PROTO_ICMP_ID])));
    180 	if (tb[CTA_PROTO_ICMP_TYPE])
    181 		nfnl_ct_set_icmp_type(ct, repl,
    182 				nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]));
    183 	if (tb[CTA_PROTO_ICMP_CODE])
    184 		nfnl_ct_set_icmp_code(ct, repl,
    185 				nla_get_u8(tb[CTA_PROTO_ICMP_CODE]));
    186 
    187 	return 0;
    188 }
    189 
    190 static int ct_parse_tuple(struct nfnl_ct *ct, int repl, struct nlattr *attr)
    191 {
    192 	struct nlattr *tb[CTA_TUPLE_MAX+1];
    193 	int err;
    194 
    195 	err = nla_parse_nested(tb, CTA_TUPLE_MAX, attr, ct_tuple_policy);
    196 	if (err < 0)
    197 		return err;
    198 
    199 	if (tb[CTA_TUPLE_IP]) {
    200 		err = ct_parse_ip(ct, repl, tb[CTA_TUPLE_IP]);
    201 		if (err < 0)
    202 			return err;
    203 	}
    204 
    205 	if (tb[CTA_TUPLE_PROTO]) {
    206 		err = ct_parse_proto(ct, repl, tb[CTA_TUPLE_PROTO]);
    207 		if (err < 0)
    208 			return err;
    209 	}
    210 
    211 	return 0;
    212 }
    213 
    214 static int ct_parse_protoinfo_tcp(struct nfnl_ct *ct, struct nlattr *attr)
    215 {
    216 	struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1];
    217 	int err;
    218 
    219 	err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr,
    220 			       ct_protoinfo_tcp_policy);
    221 	if (err < 0)
    222 		return err;
    223 
    224 	if (tb[CTA_PROTOINFO_TCP_STATE])
    225 		nfnl_ct_set_tcp_state(ct,
    226 				nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]));
    227 
    228 	return 0;
    229 }
    230 
    231 static int ct_parse_protoinfo(struct nfnl_ct *ct, struct nlattr *attr)
    232 {
    233 	struct nlattr *tb[CTA_PROTOINFO_MAX+1];
    234 	int err;
    235 
    236 	err = nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr,
    237 			       ct_protoinfo_policy);
    238 	if (err < 0)
    239 		return err;
    240 
    241 	if (tb[CTA_PROTOINFO_TCP]) {
    242 		err = ct_parse_protoinfo_tcp(ct, tb[CTA_PROTOINFO_TCP]);
    243 		if (err < 0)
    244 			return err;
    245 	}
    246 
    247 	return 0;
    248 }
    249 
    250 static int ct_parse_counters(struct nfnl_ct *ct, int repl, struct nlattr *attr)
    251 {
    252 	struct nlattr *tb[CTA_COUNTERS_MAX+1];
    253 	int err;
    254 
    255 	err = nla_parse_nested(tb, CTA_COUNTERS_MAX, attr, ct_counters_policy);
    256 	if (err < 0)
    257 		return err;
    258 
    259 	if (tb[CTA_COUNTERS_PACKETS])
    260 		nfnl_ct_set_packets(ct, repl,
    261 			ntohll(nla_get_u64(tb[CTA_COUNTERS_PACKETS])));
    262 	if (tb[CTA_COUNTERS32_PACKETS])
    263 		nfnl_ct_set_packets(ct, repl,
    264 			ntohl(nla_get_u32(tb[CTA_COUNTERS32_PACKETS])));
    265 	if (tb[CTA_COUNTERS_BYTES])
    266 		nfnl_ct_set_bytes(ct, repl,
    267 			ntohll(nla_get_u64(tb[CTA_COUNTERS_BYTES])));
    268 	if (tb[CTA_COUNTERS32_BYTES])
    269 		nfnl_ct_set_bytes(ct, repl,
    270 			ntohl(nla_get_u32(tb[CTA_COUNTERS32_BYTES])));
    271 
    272 	return 0;
    273 }
    274 
    275 int nfnlmsg_ct_group(struct nlmsghdr *nlh)
    276 {
    277 	switch (nfnlmsg_subtype(nlh)) {
    278 	case IPCTNL_MSG_CT_NEW:
    279 		if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL))
    280 			return NFNLGRP_CONNTRACK_NEW;
    281 		else
    282 			return NFNLGRP_CONNTRACK_UPDATE;
    283 	case IPCTNL_MSG_CT_DELETE:
    284 		return NFNLGRP_CONNTRACK_DESTROY;
    285 	default:
    286 		return NFNLGRP_NONE;
    287 	}
    288 }
    289 
    290 int nfnlmsg_ct_parse(struct nlmsghdr *nlh, struct nfnl_ct **result)
    291 {
    292 	struct nfnl_ct *ct;
    293 	struct nlattr *tb[CTA_MAX+1];
    294 	int err;
    295 
    296 	ct = nfnl_ct_alloc();
    297 	if (!ct)
    298 		return -NLE_NOMEM;
    299 
    300 	ct->ce_msgtype = nlh->nlmsg_type;
    301 
    302 	err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_MAX,
    303 			  ct_policy);
    304 	if (err < 0)
    305 		goto errout;
    306 
    307 	nfnl_ct_set_family(ct, nfnlmsg_family(nlh));
    308 
    309 	if (tb[CTA_TUPLE_ORIG]) {
    310 		err = ct_parse_tuple(ct, 0, tb[CTA_TUPLE_ORIG]);
    311 		if (err < 0)
    312 			goto errout;
    313 	}
    314 	if (tb[CTA_TUPLE_REPLY]) {
    315 		err = ct_parse_tuple(ct, 1, tb[CTA_TUPLE_REPLY]);
    316 		if (err < 0)
    317 			goto errout;
    318 	}
    319 
    320 	if (tb[CTA_PROTOINFO]) {
    321 		err = ct_parse_protoinfo(ct, tb[CTA_PROTOINFO]);
    322 		if (err < 0)
    323 			goto errout;
    324 	}
    325 
    326 	if (tb[CTA_STATUS])
    327 		nfnl_ct_set_status(ct, ntohl(nla_get_u32(tb[CTA_STATUS])));
    328 	if (tb[CTA_TIMEOUT])
    329 		nfnl_ct_set_timeout(ct, ntohl(nla_get_u32(tb[CTA_TIMEOUT])));
    330 	if (tb[CTA_MARK])
    331 		nfnl_ct_set_mark(ct, ntohl(nla_get_u32(tb[CTA_MARK])));
    332 	if (tb[CTA_USE])
    333 		nfnl_ct_set_use(ct, ntohl(nla_get_u32(tb[CTA_USE])));
    334 	if (tb[CTA_ID])
    335 		nfnl_ct_set_id(ct, ntohl(nla_get_u32(tb[CTA_ID])));
    336 
    337 	if (tb[CTA_COUNTERS_ORIG]) {
    338 		err = ct_parse_counters(ct, 0, tb[CTA_COUNTERS_ORIG]);
    339 		if (err < 0)
    340 			goto errout;
    341 	}
    342 
    343 	if (tb[CTA_COUNTERS_REPLY]) {
    344 		err = ct_parse_counters(ct, 1, tb[CTA_COUNTERS_REPLY]);
    345 		if (err < 0)
    346 			goto errout;
    347 	}
    348 
    349 	*result = ct;
    350 	return 0;
    351 
    352 errout:
    353 	nfnl_ct_put(ct);
    354 	return err;
    355 }
    356 
    357 static int ct_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
    358 			 struct nlmsghdr *nlh, struct nl_parser_param *pp)
    359 {
    360 	struct nfnl_ct *ct;
    361 	int err;
    362 
    363 	if ((err = nfnlmsg_ct_parse(nlh, &ct)) < 0)
    364 		goto errout;
    365 
    366 	err = pp->pp_cb((struct nl_object *) ct, pp);
    367 errout:
    368 	nfnl_ct_put(ct);
    369 	return err;
    370 }
    371 
    372 int nfnl_ct_dump_request(struct nl_sock *sk)
    373 {
    374 	return nfnl_send_simple(sk, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET,
    375 				NLM_F_DUMP, AF_UNSPEC, 0);
    376 }
    377 
    378 static int ct_request_update(struct nl_cache *cache, struct nl_sock *sk)
    379 {
    380 	return nfnl_ct_dump_request(sk);
    381 }
    382 
    383 static int nfnl_ct_build_tuple(struct nl_msg *msg, const struct nfnl_ct *ct,
    384 			       int repl)
    385 {
    386 	struct nlattr *tuple, *ip, *proto;
    387 	struct nl_addr *addr;
    388 	int family;
    389 
    390 	family = nfnl_ct_get_family(ct);
    391 
    392 	tuple = nla_nest_start(msg, repl ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG);
    393 	if (!tuple)
    394 		goto nla_put_failure;
    395 
    396 	ip = nla_nest_start(msg, CTA_TUPLE_IP);
    397 	if (!ip)
    398 		goto nla_put_failure;
    399 
    400 	addr = nfnl_ct_get_src(ct, repl);
    401 	if (addr)
    402 		NLA_PUT_ADDR(msg,
    403 			     family == AF_INET ? CTA_IP_V4_SRC : CTA_IP_V6_SRC,
    404 			     addr);
    405 
    406 	addr = nfnl_ct_get_dst(ct, repl);
    407 	if (addr)
    408 		NLA_PUT_ADDR(msg,
    409 			     family == AF_INET ? CTA_IP_V4_DST : CTA_IP_V6_DST,
    410 			     addr);
    411 
    412 	nla_nest_end(msg, ip);
    413 
    414 	proto = nla_nest_start(msg, CTA_TUPLE_PROTO);
    415 	if (!proto)
    416 		goto nla_put_failure;
    417 
    418 	if (nfnl_ct_test_proto(ct))
    419 		NLA_PUT_U8(msg, CTA_PROTO_NUM, nfnl_ct_get_proto(ct));
    420 
    421 	if (nfnl_ct_test_src_port(ct, repl))
    422 		NLA_PUT_U16(msg, CTA_PROTO_SRC_PORT,
    423 			htons(nfnl_ct_get_src_port(ct, repl)));
    424 
    425 	if (nfnl_ct_test_dst_port(ct, repl))
    426 		NLA_PUT_U16(msg, CTA_PROTO_DST_PORT,
    427 			htons(nfnl_ct_get_dst_port(ct, repl)));
    428 
    429 	if (nfnl_ct_test_icmp_id(ct, repl))
    430 		NLA_PUT_U16(msg, CTA_PROTO_ICMP_ID,
    431 			htons(nfnl_ct_get_icmp_id(ct, repl)));
    432 
    433 	if (nfnl_ct_test_icmp_type(ct, repl))
    434 		NLA_PUT_U8(msg, CTA_PROTO_ICMP_TYPE,
    435 			    nfnl_ct_get_icmp_type(ct, repl));
    436 
    437 	if (nfnl_ct_test_icmp_code(ct, repl))
    438 		NLA_PUT_U8(msg, CTA_PROTO_ICMP_CODE,
    439 			    nfnl_ct_get_icmp_code(ct, repl));
    440 
    441 	nla_nest_end(msg, proto);
    442 
    443 	nla_nest_end(msg, tuple);
    444 	return 0;
    445 
    446 nla_put_failure:
    447 	return -NLE_MSGSIZE;
    448 }
    449 
    450 static int nfnl_ct_build_message(const struct nfnl_ct *ct, int cmd, int flags,
    451 				 struct nl_msg **result)
    452 {
    453 	struct nl_msg *msg;
    454 	int err;
    455 
    456 	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_CTNETLINK, cmd, flags,
    457 				   nfnl_ct_get_family(ct), 0);
    458 	if (msg == NULL)
    459 		return -NLE_NOMEM;
    460 
    461 	if ((err = nfnl_ct_build_tuple(msg, ct, 0)) < 0)
    462 		goto err_out;
    463 
    464 	*result = msg;
    465 	return 0;
    466 
    467 err_out:
    468 	nlmsg_free(msg);
    469 	return err;
    470 }
    471 
    472 int nfnl_ct_build_add_request(const struct nfnl_ct *ct, int flags,
    473 			      struct nl_msg **result)
    474 {
    475 	return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_NEW, flags, result);
    476 }
    477 
    478 int nfnl_ct_add(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
    479 {
    480 	struct nl_msg *msg;
    481 	int err;
    482 
    483 	if ((err = nfnl_ct_build_add_request(ct, flags, &msg)) < 0)
    484 		return err;
    485 
    486 	err = nl_send_auto_complete(sk, msg);
    487 	nlmsg_free(msg);
    488 	if (err < 0)
    489 		return err;
    490 
    491 	return wait_for_ack(sk);
    492 }
    493 
    494 int nfnl_ct_build_delete_request(const struct nfnl_ct *ct, int flags,
    495 				 struct nl_msg **result)
    496 {
    497 	return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_DELETE, flags, result);
    498 }
    499 
    500 int nfnl_ct_del(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
    501 {
    502 	struct nl_msg *msg;
    503 	int err;
    504 
    505 	if ((err = nfnl_ct_build_delete_request(ct, flags, &msg)) < 0)
    506 		return err;
    507 
    508 	err = nl_send_auto_complete(sk, msg);
    509 	nlmsg_free(msg);
    510 	if (err < 0)
    511 		return err;
    512 
    513 	return wait_for_ack(sk);
    514 }
    515 
    516 int nfnl_ct_build_query_request(const struct nfnl_ct *ct, int flags,
    517 				struct nl_msg **result)
    518 {
    519 	return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_GET, flags, result);
    520 }
    521 
    522 int nfnl_ct_query(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
    523 {
    524 	struct nl_msg *msg;
    525 	int err;
    526 
    527 	if ((err = nfnl_ct_build_query_request(ct, flags, &msg)) < 0)
    528 		return err;
    529 
    530 	err = nl_send_auto_complete(sk, msg);
    531 	nlmsg_free(msg);
    532 	if (err < 0)
    533 		return err;
    534 
    535 	return wait_for_ack(sk);
    536 }
    537 
    538 /**
    539  * @name Cache Management
    540  * @{
    541  */
    542 
    543 /**
    544  * Build a conntrack cache holding all conntrack currently in the kernel
    545  * @arg sk		Netlink socket.
    546  * @arg result		Pointer to store resulting cache.
    547  *
    548  * Allocates a new cache, initializes it properly and updates it to
    549  * contain all conntracks currently in the kernel.
    550  *
    551  * @return 0 on success or a negative error code.
    552  */
    553 int nfnl_ct_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
    554 {
    555 	return nl_cache_alloc_and_fill(&nfnl_ct_ops, sk, result);
    556 }
    557 
    558 /** @} */
    559 
    560 /**
    561  * @name Conntrack Addition
    562  * @{
    563  */
    564 
    565 /** @} */
    566 
    567 static struct nl_af_group ct_groups[] = {
    568 	{ AF_UNSPEC, NFNLGRP_CONNTRACK_NEW },
    569 	{ AF_UNSPEC, NFNLGRP_CONNTRACK_UPDATE },
    570 	{ AF_UNSPEC, NFNLGRP_CONNTRACK_DESTROY },
    571 	{ END_OF_GROUP_LIST },
    572 };
    573 
    574 #define NFNLMSG_CT_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_CTNETLINK, (type))
    575 static struct nl_cache_ops nfnl_ct_ops = {
    576 	.co_name		= "netfilter/ct",
    577 	.co_hdrsize		= NFNL_HDRLEN,
    578 	.co_msgtypes		= {
    579 		{ NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_NEW), NL_ACT_NEW, "new" },
    580 		{ NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_GET), NL_ACT_GET, "get" },
    581 		{ NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_DELETE), NL_ACT_DEL, "del" },
    582 		END_OF_MSGTYPES_LIST,
    583 	},
    584 	.co_protocol		= NETLINK_NETFILTER,
    585 	.co_groups		= ct_groups,
    586 	.co_request_update	= ct_request_update,
    587 	.co_msg_parser		= ct_msg_parser,
    588 	.co_obj_ops		= &ct_obj_ops,
    589 };
    590 
    591 static void __init ct_init(void)
    592 {
    593 	nl_cache_mngt_register(&nfnl_ct_ops);
    594 }
    595 
    596 static void __exit ct_exit(void)
    597 {
    598 	nl_cache_mngt_unregister(&nfnl_ct_ops);
    599 }
    600 
    601 /** @} */
    602