ct.c

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 /** @} */