libnl
3.2.3
|
00001 /* 00002 * lib/netfilter/ct.c Conntrack 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation version 2.1 00007 * of the License. 00008 * 00009 * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> 00010 * Copyright (c) 2007 Philip Craig <philipc@snapgear.com> 00011 * Copyright (c) 2007 Secure Computing Corporation 00012 * Copyright (c= 2008 Patrick McHardy <kaber@trash.net> 00013 */ 00014 00015 /** 00016 * @ingroup nfnl 00017 * @defgroup ct Conntrack 00018 * @brief 00019 * @{ 00020 */ 00021 00022 #include <byteswap.h> 00023 #include <sys/types.h> 00024 #include <linux/netfilter/nfnetlink_conntrack.h> 00025 00026 #include <netlink-local.h> 00027 #include <netlink/attr.h> 00028 #include <netlink/netfilter/nfnl.h> 00029 #include <netlink/netfilter/ct.h> 00030 00031 static struct nl_cache_ops nfnl_ct_ops; 00032 00033 #if __BYTE_ORDER == __BIG_ENDIAN 00034 static uint64_t ntohll(uint64_t x) 00035 { 00036 return x; 00037 } 00038 #elif __BYTE_ORDER == __LITTLE_ENDIAN 00039 static uint64_t ntohll(uint64_t x) 00040 { 00041 return __bswap_64(x); 00042 } 00043 #endif 00044 00045 static struct nla_policy ct_policy[CTA_MAX+1] = { 00046 [CTA_TUPLE_ORIG] = { .type = NLA_NESTED }, 00047 [CTA_TUPLE_REPLY] = { .type = NLA_NESTED }, 00048 [CTA_STATUS] = { .type = NLA_U32 }, 00049 [CTA_PROTOINFO] = { .type = NLA_NESTED }, 00050 //[CTA_HELP] 00051 //[CTA_NAT_SRC] 00052 [CTA_TIMEOUT] = { .type = NLA_U32 }, 00053 [CTA_MARK] = { .type = NLA_U32 }, 00054 [CTA_COUNTERS_ORIG] = { .type = NLA_NESTED }, 00055 [CTA_COUNTERS_REPLY] = { .type = NLA_NESTED }, 00056 [CTA_USE] = { .type = NLA_U32 }, 00057 [CTA_ID] = { .type = NLA_U32 }, 00058 //[CTA_NAT_DST] 00059 }; 00060 00061 static struct nla_policy ct_tuple_policy[CTA_TUPLE_MAX+1] = { 00062 [CTA_TUPLE_IP] = { .type = NLA_NESTED }, 00063 [CTA_TUPLE_PROTO] = { .type = NLA_NESTED }, 00064 }; 00065 00066 static struct nla_policy ct_ip_policy[CTA_IP_MAX+1] = { 00067 [CTA_IP_V4_SRC] = { .type = NLA_U32 }, 00068 [CTA_IP_V4_DST] = { .type = NLA_U32 }, 00069 [CTA_IP_V6_SRC] = { .minlen = 16 }, 00070 [CTA_IP_V6_DST] = { .minlen = 16 }, 00071 }; 00072 00073 static struct nla_policy ct_proto_policy[CTA_PROTO_MAX+1] = { 00074 [CTA_PROTO_NUM] = { .type = NLA_U8 }, 00075 [CTA_PROTO_SRC_PORT] = { .type = NLA_U16 }, 00076 [CTA_PROTO_DST_PORT] = { .type = NLA_U16 }, 00077 [CTA_PROTO_ICMP_ID] = { .type = NLA_U16 }, 00078 [CTA_PROTO_ICMP_TYPE] = { .type = NLA_U8 }, 00079 [CTA_PROTO_ICMP_CODE] = { .type = NLA_U8 }, 00080 [CTA_PROTO_ICMPV6_ID] = { .type = NLA_U16 }, 00081 [CTA_PROTO_ICMPV6_TYPE] = { .type = NLA_U8 }, 00082 [CTA_PROTO_ICMPV6_CODE] = { .type = NLA_U8 }, 00083 }; 00084 00085 static struct nla_policy ct_protoinfo_policy[CTA_PROTOINFO_MAX+1] = { 00086 [CTA_PROTOINFO_TCP] = { .type = NLA_NESTED }, 00087 }; 00088 00089 static struct nla_policy ct_protoinfo_tcp_policy[CTA_PROTOINFO_TCP_MAX+1] = { 00090 [CTA_PROTOINFO_TCP_STATE] = { .type = NLA_U8 }, 00091 [CTA_PROTOINFO_TCP_WSCALE_ORIGINAL] = { .type = NLA_U8 }, 00092 [CTA_PROTOINFO_TCP_WSCALE_REPLY] = { .type = NLA_U8 }, 00093 [CTA_PROTOINFO_TCP_FLAGS_ORIGINAL] = { .minlen = 2 }, 00094 [CTA_PROTOINFO_TCP_FLAGS_REPLY] = { .minlen = 2 }, 00095 00096 }; 00097 00098 static struct nla_policy ct_counters_policy[CTA_COUNTERS_MAX+1] = { 00099 [CTA_COUNTERS_PACKETS] = { .type = NLA_U64 }, 00100 [CTA_COUNTERS_BYTES] = { .type = NLA_U64 }, 00101 [CTA_COUNTERS32_PACKETS]= { .type = NLA_U32 }, 00102 [CTA_COUNTERS32_BYTES] = { .type = NLA_U32 }, 00103 }; 00104 00105 static int ct_parse_ip(struct nfnl_ct *ct, int repl, struct nlattr *attr) 00106 { 00107 struct nlattr *tb[CTA_IP_MAX+1]; 00108 struct nl_addr *addr; 00109 int err; 00110 00111 err = nla_parse_nested(tb, CTA_IP_MAX, attr, ct_ip_policy); 00112 if (err < 0) 00113 goto errout; 00114 00115 if (tb[CTA_IP_V4_SRC]) { 00116 addr = nl_addr_alloc_attr(tb[CTA_IP_V4_SRC], AF_INET); 00117 if (addr == NULL) 00118 goto errout_enomem; 00119 err = nfnl_ct_set_src(ct, repl, addr); 00120 nl_addr_put(addr); 00121 if (err < 0) 00122 goto errout; 00123 } 00124 if (tb[CTA_IP_V4_DST]) { 00125 addr = nl_addr_alloc_attr(tb[CTA_IP_V4_DST], AF_INET); 00126 if (addr == NULL) 00127 goto errout_enomem; 00128 err = nfnl_ct_set_dst(ct, repl, addr); 00129 nl_addr_put(addr); 00130 if (err < 0) 00131 goto errout; 00132 } 00133 if (tb[CTA_IP_V6_SRC]) { 00134 addr = nl_addr_alloc_attr(tb[CTA_IP_V6_SRC], AF_INET6); 00135 if (addr == NULL) 00136 goto errout_enomem; 00137 err = nfnl_ct_set_src(ct, repl, addr); 00138 nl_addr_put(addr); 00139 if (err < 0) 00140 goto errout; 00141 } 00142 if (tb[CTA_IP_V6_DST]) { 00143 addr = nl_addr_alloc_attr(tb[CTA_IP_V6_DST], AF_INET6); 00144 if (addr == NULL) 00145 goto errout_enomem; 00146 err = nfnl_ct_set_dst(ct, repl, addr); 00147 nl_addr_put(addr); 00148 if (err < 0) 00149 goto errout; 00150 } 00151 00152 return 0; 00153 00154 errout_enomem: 00155 err = -NLE_NOMEM; 00156 errout: 00157 return err; 00158 } 00159 00160 static int ct_parse_proto(struct nfnl_ct *ct, int repl, struct nlattr *attr) 00161 { 00162 struct nlattr *tb[CTA_PROTO_MAX+1]; 00163 int err; 00164 00165 err = nla_parse_nested(tb, CTA_PROTO_MAX, attr, ct_proto_policy); 00166 if (err < 0) 00167 return err; 00168 00169 if (!repl && tb[CTA_PROTO_NUM]) 00170 nfnl_ct_set_proto(ct, nla_get_u8(tb[CTA_PROTO_NUM])); 00171 if (tb[CTA_PROTO_SRC_PORT]) 00172 nfnl_ct_set_src_port(ct, repl, 00173 ntohs(nla_get_u16(tb[CTA_PROTO_SRC_PORT]))); 00174 if (tb[CTA_PROTO_DST_PORT]) 00175 nfnl_ct_set_dst_port(ct, repl, 00176 ntohs(nla_get_u16(tb[CTA_PROTO_DST_PORT]))); 00177 if (tb[CTA_PROTO_ICMP_ID]) 00178 nfnl_ct_set_icmp_id(ct, repl, 00179 ntohs(nla_get_u16(tb[CTA_PROTO_ICMP_ID]))); 00180 if (tb[CTA_PROTO_ICMP_TYPE]) 00181 nfnl_ct_set_icmp_type(ct, repl, 00182 nla_get_u8(tb[CTA_PROTO_ICMP_TYPE])); 00183 if (tb[CTA_PROTO_ICMP_CODE]) 00184 nfnl_ct_set_icmp_code(ct, repl, 00185 nla_get_u8(tb[CTA_PROTO_ICMP_CODE])); 00186 00187 return 0; 00188 } 00189 00190 static int ct_parse_tuple(struct nfnl_ct *ct, int repl, struct nlattr *attr) 00191 { 00192 struct nlattr *tb[CTA_TUPLE_MAX+1]; 00193 int err; 00194 00195 err = nla_parse_nested(tb, CTA_TUPLE_MAX, attr, ct_tuple_policy); 00196 if (err < 0) 00197 return err; 00198 00199 if (tb[CTA_TUPLE_IP]) { 00200 err = ct_parse_ip(ct, repl, tb[CTA_TUPLE_IP]); 00201 if (err < 0) 00202 return err; 00203 } 00204 00205 if (tb[CTA_TUPLE_PROTO]) { 00206 err = ct_parse_proto(ct, repl, tb[CTA_TUPLE_PROTO]); 00207 if (err < 0) 00208 return err; 00209 } 00210 00211 return 0; 00212 } 00213 00214 static int ct_parse_protoinfo_tcp(struct nfnl_ct *ct, struct nlattr *attr) 00215 { 00216 struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1]; 00217 int err; 00218 00219 err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr, 00220 ct_protoinfo_tcp_policy); 00221 if (err < 0) 00222 return err; 00223 00224 if (tb[CTA_PROTOINFO_TCP_STATE]) 00225 nfnl_ct_set_tcp_state(ct, 00226 nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE])); 00227 00228 return 0; 00229 } 00230 00231 static int ct_parse_protoinfo(struct nfnl_ct *ct, struct nlattr *attr) 00232 { 00233 struct nlattr *tb[CTA_PROTOINFO_MAX+1]; 00234 int err; 00235 00236 err = nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr, 00237 ct_protoinfo_policy); 00238 if (err < 0) 00239 return err; 00240 00241 if (tb[CTA_PROTOINFO_TCP]) { 00242 err = ct_parse_protoinfo_tcp(ct, tb[CTA_PROTOINFO_TCP]); 00243 if (err < 0) 00244 return err; 00245 } 00246 00247 return 0; 00248 } 00249 00250 static int ct_parse_counters(struct nfnl_ct *ct, int repl, struct nlattr *attr) 00251 { 00252 struct nlattr *tb[CTA_COUNTERS_MAX+1]; 00253 int err; 00254 00255 err = nla_parse_nested(tb, CTA_COUNTERS_MAX, attr, ct_counters_policy); 00256 if (err < 0) 00257 return err; 00258 00259 if (tb[CTA_COUNTERS_PACKETS]) 00260 nfnl_ct_set_packets(ct, repl, 00261 ntohll(nla_get_u64(tb[CTA_COUNTERS_PACKETS]))); 00262 if (tb[CTA_COUNTERS32_PACKETS]) 00263 nfnl_ct_set_packets(ct, repl, 00264 ntohl(nla_get_u32(tb[CTA_COUNTERS32_PACKETS]))); 00265 if (tb[CTA_COUNTERS_BYTES]) 00266 nfnl_ct_set_bytes(ct, repl, 00267 ntohll(nla_get_u64(tb[CTA_COUNTERS_BYTES]))); 00268 if (tb[CTA_COUNTERS32_BYTES]) 00269 nfnl_ct_set_bytes(ct, repl, 00270 ntohl(nla_get_u32(tb[CTA_COUNTERS32_BYTES]))); 00271 00272 return 0; 00273 } 00274 00275 int nfnlmsg_ct_group(struct nlmsghdr *nlh) 00276 { 00277 switch (nfnlmsg_subtype(nlh)) { 00278 case IPCTNL_MSG_CT_NEW: 00279 if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL)) 00280 return NFNLGRP_CONNTRACK_NEW; 00281 else 00282 return NFNLGRP_CONNTRACK_UPDATE; 00283 case IPCTNL_MSG_CT_DELETE: 00284 return NFNLGRP_CONNTRACK_DESTROY; 00285 default: 00286 return NFNLGRP_NONE; 00287 } 00288 } 00289 00290 int nfnlmsg_ct_parse(struct nlmsghdr *nlh, struct nfnl_ct **result) 00291 { 00292 struct nfnl_ct *ct; 00293 struct nlattr *tb[CTA_MAX+1]; 00294 int err; 00295 00296 ct = nfnl_ct_alloc(); 00297 if (!ct) 00298 return -NLE_NOMEM; 00299 00300 ct->ce_msgtype = nlh->nlmsg_type; 00301 00302 err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_MAX, 00303 ct_policy); 00304 if (err < 0) 00305 goto errout; 00306 00307 nfnl_ct_set_family(ct, nfnlmsg_family(nlh)); 00308 00309 if (tb[CTA_TUPLE_ORIG]) { 00310 err = ct_parse_tuple(ct, 0, tb[CTA_TUPLE_ORIG]); 00311 if (err < 0) 00312 goto errout; 00313 } 00314 if (tb[CTA_TUPLE_REPLY]) { 00315 err = ct_parse_tuple(ct, 1, tb[CTA_TUPLE_REPLY]); 00316 if (err < 0) 00317 goto errout; 00318 } 00319 00320 if (tb[CTA_PROTOINFO]) { 00321 err = ct_parse_protoinfo(ct, tb[CTA_PROTOINFO]); 00322 if (err < 0) 00323 goto errout; 00324 } 00325 00326 if (tb[CTA_STATUS]) 00327 nfnl_ct_set_status(ct, ntohl(nla_get_u32(tb[CTA_STATUS]))); 00328 if (tb[CTA_TIMEOUT]) 00329 nfnl_ct_set_timeout(ct, ntohl(nla_get_u32(tb[CTA_TIMEOUT]))); 00330 if (tb[CTA_MARK]) 00331 nfnl_ct_set_mark(ct, ntohl(nla_get_u32(tb[CTA_MARK]))); 00332 if (tb[CTA_USE]) 00333 nfnl_ct_set_use(ct, ntohl(nla_get_u32(tb[CTA_USE]))); 00334 if (tb[CTA_ID]) 00335 nfnl_ct_set_id(ct, ntohl(nla_get_u32(tb[CTA_ID]))); 00336 00337 if (tb[CTA_COUNTERS_ORIG]) { 00338 err = ct_parse_counters(ct, 0, tb[CTA_COUNTERS_ORIG]); 00339 if (err < 0) 00340 goto errout; 00341 } 00342 00343 if (tb[CTA_COUNTERS_REPLY]) { 00344 err = ct_parse_counters(ct, 1, tb[CTA_COUNTERS_REPLY]); 00345 if (err < 0) 00346 goto errout; 00347 } 00348 00349 *result = ct; 00350 return 0; 00351 00352 errout: 00353 nfnl_ct_put(ct); 00354 return err; 00355 } 00356 00357 static int ct_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, 00358 struct nlmsghdr *nlh, struct nl_parser_param *pp) 00359 { 00360 struct nfnl_ct *ct; 00361 int err; 00362 00363 if ((err = nfnlmsg_ct_parse(nlh, &ct)) < 0) 00364 goto errout; 00365 00366 err = pp->pp_cb((struct nl_object *) ct, pp); 00367 errout: 00368 nfnl_ct_put(ct); 00369 return err; 00370 } 00371 00372 int nfnl_ct_dump_request(struct nl_sock *sk) 00373 { 00374 return nfnl_send_simple(sk, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET, 00375 NLM_F_DUMP, AF_UNSPEC, 0); 00376 } 00377 00378 static int ct_request_update(struct nl_cache *cache, struct nl_sock *sk) 00379 { 00380 return nfnl_ct_dump_request(sk); 00381 } 00382 00383 static int nfnl_ct_build_tuple(struct nl_msg *msg, const struct nfnl_ct *ct, 00384 int repl) 00385 { 00386 struct nlattr *tuple, *ip, *proto; 00387 struct nl_addr *addr; 00388 int family; 00389 00390 family = nfnl_ct_get_family(ct); 00391 00392 tuple = nla_nest_start(msg, repl ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG); 00393 if (!tuple) 00394 goto nla_put_failure; 00395 00396 ip = nla_nest_start(msg, CTA_TUPLE_IP); 00397 if (!ip) 00398 goto nla_put_failure; 00399 00400 addr = nfnl_ct_get_src(ct, repl); 00401 if (addr) 00402 NLA_PUT_ADDR(msg, 00403 family == AF_INET ? CTA_IP_V4_SRC : CTA_IP_V6_SRC, 00404 addr); 00405 00406 addr = nfnl_ct_get_dst(ct, repl); 00407 if (addr) 00408 NLA_PUT_ADDR(msg, 00409 family == AF_INET ? CTA_IP_V4_DST : CTA_IP_V6_DST, 00410 addr); 00411 00412 nla_nest_end(msg, ip); 00413 00414 proto = nla_nest_start(msg, CTA_TUPLE_PROTO); 00415 if (!proto) 00416 goto nla_put_failure; 00417 00418 if (nfnl_ct_test_proto(ct)) 00419 NLA_PUT_U8(msg, CTA_PROTO_NUM, nfnl_ct_get_proto(ct)); 00420 00421 if (nfnl_ct_test_src_port(ct, repl)) 00422 NLA_PUT_U16(msg, CTA_PROTO_SRC_PORT, 00423 htons(nfnl_ct_get_src_port(ct, repl))); 00424 00425 if (nfnl_ct_test_dst_port(ct, repl)) 00426 NLA_PUT_U16(msg, CTA_PROTO_DST_PORT, 00427 htons(nfnl_ct_get_dst_port(ct, repl))); 00428 00429 if (nfnl_ct_test_icmp_id(ct, repl)) 00430 NLA_PUT_U16(msg, CTA_PROTO_ICMP_ID, 00431 htons(nfnl_ct_get_icmp_id(ct, repl))); 00432 00433 if (nfnl_ct_test_icmp_type(ct, repl)) 00434 NLA_PUT_U8(msg, CTA_PROTO_ICMP_TYPE, 00435 nfnl_ct_get_icmp_type(ct, repl)); 00436 00437 if (nfnl_ct_test_icmp_code(ct, repl)) 00438 NLA_PUT_U8(msg, CTA_PROTO_ICMP_CODE, 00439 nfnl_ct_get_icmp_code(ct, repl)); 00440 00441 nla_nest_end(msg, proto); 00442 00443 nla_nest_end(msg, tuple); 00444 return 0; 00445 00446 nla_put_failure: 00447 return -NLE_MSGSIZE; 00448 } 00449 00450 static int nfnl_ct_build_message(const struct nfnl_ct *ct, int cmd, int flags, 00451 struct nl_msg **result) 00452 { 00453 struct nl_msg *msg; 00454 int err; 00455 00456 msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_CTNETLINK, cmd, flags, 00457 nfnl_ct_get_family(ct), 0); 00458 if (msg == NULL) 00459 return -NLE_NOMEM; 00460 00461 if ((err = nfnl_ct_build_tuple(msg, ct, 0)) < 0) 00462 goto err_out; 00463 00464 *result = msg; 00465 return 0; 00466 00467 err_out: 00468 nlmsg_free(msg); 00469 return err; 00470 } 00471 00472 int nfnl_ct_build_add_request(const struct nfnl_ct *ct, int flags, 00473 struct nl_msg **result) 00474 { 00475 return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_NEW, flags, result); 00476 } 00477 00478 int nfnl_ct_add(struct nl_sock *sk, const struct nfnl_ct *ct, int flags) 00479 { 00480 struct nl_msg *msg; 00481 int err; 00482 00483 if ((err = nfnl_ct_build_add_request(ct, flags, &msg)) < 0) 00484 return err; 00485 00486 err = nl_send_auto_complete(sk, msg); 00487 nlmsg_free(msg); 00488 if (err < 0) 00489 return err; 00490 00491 return wait_for_ack(sk); 00492 } 00493 00494 int nfnl_ct_build_delete_request(const struct nfnl_ct *ct, int flags, 00495 struct nl_msg **result) 00496 { 00497 return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_DELETE, flags, result); 00498 } 00499 00500 int nfnl_ct_del(struct nl_sock *sk, const struct nfnl_ct *ct, int flags) 00501 { 00502 struct nl_msg *msg; 00503 int err; 00504 00505 if ((err = nfnl_ct_build_delete_request(ct, flags, &msg)) < 0) 00506 return err; 00507 00508 err = nl_send_auto_complete(sk, msg); 00509 nlmsg_free(msg); 00510 if (err < 0) 00511 return err; 00512 00513 return wait_for_ack(sk); 00514 } 00515 00516 int nfnl_ct_build_query_request(const struct nfnl_ct *ct, int flags, 00517 struct nl_msg **result) 00518 { 00519 return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_GET, flags, result); 00520 } 00521 00522 int nfnl_ct_query(struct nl_sock *sk, const struct nfnl_ct *ct, int flags) 00523 { 00524 struct nl_msg *msg; 00525 int err; 00526 00527 if ((err = nfnl_ct_build_query_request(ct, flags, &msg)) < 0) 00528 return err; 00529 00530 err = nl_send_auto_complete(sk, msg); 00531 nlmsg_free(msg); 00532 if (err < 0) 00533 return err; 00534 00535 return wait_for_ack(sk); 00536 } 00537 00538 /** 00539 * @name Cache Management 00540 * @{ 00541 */ 00542 00543 /** 00544 * Build a conntrack cache holding all conntrack currently in the kernel 00545 * @arg sk Netlink socket. 00546 * @arg result Pointer to store resulting cache. 00547 * 00548 * Allocates a new cache, initializes it properly and updates it to 00549 * contain all conntracks currently in the kernel. 00550 * 00551 * @return 0 on success or a negative error code. 00552 */ 00553 int nfnl_ct_alloc_cache(struct nl_sock *sk, struct nl_cache **result) 00554 { 00555 return nl_cache_alloc_and_fill(&nfnl_ct_ops, sk, result); 00556 } 00557 00558 /** @} */ 00559 00560 /** 00561 * @name Conntrack Addition 00562 * @{ 00563 */ 00564 00565 /** @} */ 00566 00567 static struct nl_af_group ct_groups[] = { 00568 { AF_UNSPEC, NFNLGRP_CONNTRACK_NEW }, 00569 { AF_UNSPEC, NFNLGRP_CONNTRACK_UPDATE }, 00570 { AF_UNSPEC, NFNLGRP_CONNTRACK_DESTROY }, 00571 { END_OF_GROUP_LIST }, 00572 }; 00573 00574 #define NFNLMSG_CT_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_CTNETLINK, (type)) 00575 static struct nl_cache_ops nfnl_ct_ops = { 00576 .co_name = "netfilter/ct", 00577 .co_hdrsize = NFNL_HDRLEN, 00578 .co_msgtypes = { 00579 { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_NEW), NL_ACT_NEW, "new" }, 00580 { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_GET), NL_ACT_GET, "get" }, 00581 { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_DELETE), NL_ACT_DEL, "del" }, 00582 END_OF_MSGTYPES_LIST, 00583 }, 00584 .co_protocol = NETLINK_NETFILTER, 00585 .co_groups = ct_groups, 00586 .co_request_update = ct_request_update, 00587 .co_msg_parser = ct_msg_parser, 00588 .co_obj_ops = &ct_obj_ops, 00589 }; 00590 00591 static void __init ct_init(void) 00592 { 00593 nl_cache_mngt_register(&nfnl_ct_ops); 00594 } 00595 00596 static void __exit ct_exit(void) 00597 { 00598 nl_cache_mngt_unregister(&nfnl_ct_ops); 00599 } 00600 00601 /** @} */