libnl 1.1
lib/netfilter/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-2006 Thomas Graf <tgraf@suug.ch>
00010  * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
00011  * Copyright (c) 2007 Secure Computing Corporation
00012  */
00013 
00014 /**
00015  * @ingroup nfnl
00016  * @defgroup ct Conntrack
00017  * @brief
00018  * @{
00019  */
00020 
00021 #include <byteswap.h>
00022 #include <sys/types.h>
00023 #include <linux/netfilter/nfnetlink_conntrack.h>
00024 
00025 #include <netlink-local.h>
00026 #include <netlink/attr.h>
00027 #include <netlink/netfilter/nfnl.h>
00028 #include <netlink/netfilter/ct.h>
00029 
00030 static struct nl_cache_ops nfnl_ct_ops;
00031 
00032 #if __BYTE_ORDER == __BIG_ENDIAN
00033 static uint64_t ntohll(uint64_t x)
00034 {
00035         return x;
00036 }
00037 #elif __BYTE_ORDER == __LITTLE_ENDIAN
00038 static uint64_t ntohll(uint64_t x)
00039 {
00040         return __bswap_64(x);
00041 }
00042 #endif
00043 
00044 static struct nla_policy ct_policy[CTA_MAX+1] = {
00045         [CTA_TUPLE_ORIG]        = { .type = NLA_NESTED },
00046         [CTA_TUPLE_REPLY]       = { .type = NLA_NESTED },
00047         [CTA_STATUS]            = { .type = NLA_U32 },
00048         [CTA_PROTOINFO]         = { .type = NLA_NESTED },
00049         //[CTA_HELP]
00050         //[CTA_NAT_SRC]
00051         [CTA_TIMEOUT]           = { .type = NLA_U32 },
00052         [CTA_MARK]              = { .type = NLA_U32 },
00053         [CTA_COUNTERS_ORIG]     = { .type = NLA_NESTED },
00054         [CTA_COUNTERS_REPLY]    = { .type = NLA_NESTED },
00055         [CTA_USE]               = { .type = NLA_U32 },
00056         [CTA_ID]                = { .type = NLA_U32 },
00057         //[CTA_NAT_DST]
00058 };
00059 
00060 static struct nla_policy ct_tuple_policy[CTA_TUPLE_MAX+1] = {
00061         [CTA_TUPLE_IP]          = { .type = NLA_NESTED },
00062         [CTA_TUPLE_PROTO]       = { .type = NLA_NESTED },
00063 };
00064 
00065 static struct nla_policy ct_ip_policy[CTA_IP_MAX+1] = {
00066         [CTA_IP_V4_SRC]         = { .type = NLA_U32 },
00067         [CTA_IP_V4_DST]         = { .type = NLA_U32 },
00068         [CTA_IP_V6_SRC]         = { .minlen = 16 },
00069         [CTA_IP_V6_DST]         = { .minlen = 16 },
00070 };
00071 
00072 static struct nla_policy ct_proto_policy[CTA_PROTO_MAX+1] = {
00073         [CTA_PROTO_NUM]         = { .type = NLA_U8 },
00074         [CTA_PROTO_SRC_PORT]    = { .type = NLA_U16 },
00075         [CTA_PROTO_DST_PORT]    = { .type = NLA_U16 },
00076         [CTA_PROTO_ICMP_ID]     = { .type = NLA_U16 },
00077         [CTA_PROTO_ICMP_TYPE]   = { .type = NLA_U8 },
00078         [CTA_PROTO_ICMP_CODE]   = { .type = NLA_U8 },
00079         [CTA_PROTO_ICMPV6_ID]   = { .type = NLA_U16 },
00080         [CTA_PROTO_ICMPV6_TYPE] = { .type = NLA_U8 },
00081         [CTA_PROTO_ICMPV6_CODE] = { .type = NLA_U8 },
00082 };
00083 
00084 static struct nla_policy ct_protoinfo_policy[CTA_PROTOINFO_MAX+1] = {
00085         [CTA_PROTOINFO_TCP]     = { .type = NLA_NESTED },
00086 };
00087 
00088 static struct nla_policy ct_protoinfo_tcp_policy[CTA_PROTOINFO_TCP_MAX+1] = {
00089         [CTA_PROTOINFO_TCP_STATE]               = { .type = NLA_U8 },
00090         [CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]     = { .type = NLA_U8 },
00091         [CTA_PROTOINFO_TCP_WSCALE_REPLY]        = { .type = NLA_U8 },
00092         [CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]      = { .minlen = 2 },
00093         [CTA_PROTOINFO_TCP_FLAGS_REPLY]         = { .minlen = 2 },
00094 
00095 };
00096 
00097 static struct nla_policy ct_counters_policy[CTA_COUNTERS_MAX+1] = {
00098         [CTA_COUNTERS_PACKETS]  = { .type = NLA_U64 },
00099         [CTA_COUNTERS_BYTES]    = { .type = NLA_U64 },
00100         [CTA_COUNTERS32_PACKETS]= { .type = NLA_U32 },
00101         [CTA_COUNTERS32_BYTES]  = { .type = NLA_U32 },
00102 };
00103 
00104 static int ct_parse_ip(struct nfnl_ct *ct, int repl, struct nlattr *attr)
00105 {
00106         struct nlattr *tb[CTA_IP_MAX+1];
00107         struct nl_addr *addr;
00108         int err;
00109 
00110         err = nla_parse_nested(tb, CTA_IP_MAX, attr, ct_ip_policy);
00111         if (err < 0)
00112                 goto errout;
00113 
00114         if (tb[CTA_IP_V4_SRC]) {
00115                 addr = nla_get_addr(tb[CTA_IP_V4_SRC], AF_INET);
00116                 if (addr == NULL)
00117                         goto errout_errno;
00118                 err = nfnl_ct_set_src(ct, repl, addr);
00119                 nl_addr_put(addr);
00120                 if (err < 0)
00121                         goto errout;
00122         }
00123         if (tb[CTA_IP_V4_DST]) {
00124                 addr = nla_get_addr(tb[CTA_IP_V4_DST], AF_INET);
00125                 if (addr == NULL)
00126                         goto errout_errno;
00127                 err = nfnl_ct_set_dst(ct, repl, addr);
00128                 nl_addr_put(addr);
00129                 if (err < 0)
00130                         goto errout;
00131         }
00132         if (tb[CTA_IP_V6_SRC]) {
00133                 addr = nla_get_addr(tb[CTA_IP_V6_SRC], AF_INET6);
00134                 if (addr == NULL)
00135                         goto errout_errno;
00136                 err = nfnl_ct_set_src(ct, repl, addr);
00137                 nl_addr_put(addr);
00138                 if (err < 0)
00139                         goto errout;
00140         }
00141         if (tb[CTA_IP_V6_DST]) {
00142                 addr = nla_get_addr(tb[CTA_IP_V6_DST], AF_INET6);
00143                 if (addr == NULL)
00144                         goto errout_errno;
00145                 err = nfnl_ct_set_dst(ct, repl, addr);
00146                 nl_addr_put(addr);
00147                 if (err < 0)
00148                         goto errout;
00149         }
00150 
00151         return 0;
00152 
00153 errout_errno:
00154         return nl_get_errno();
00155 errout:
00156         return err;
00157 }
00158 
00159 static int ct_parse_proto(struct nfnl_ct *ct, int repl, struct nlattr *attr)
00160 {
00161         struct nlattr *tb[CTA_PROTO_MAX+1];
00162         int err;
00163 
00164         err = nla_parse_nested(tb, CTA_PROTO_MAX, attr, ct_proto_policy);
00165         if (err < 0)
00166                 return err;
00167 
00168         if (!repl && tb[CTA_PROTO_NUM])
00169                 nfnl_ct_set_proto(ct, nla_get_u8(tb[CTA_PROTO_NUM]));
00170         if (tb[CTA_PROTO_SRC_PORT])
00171                 nfnl_ct_set_src_port(ct, repl,
00172                                 nla_get_u16(tb[CTA_PROTO_SRC_PORT]));
00173         if (tb[CTA_PROTO_DST_PORT])
00174                 nfnl_ct_set_dst_port(ct, repl,
00175                                 nla_get_u16(tb[CTA_PROTO_DST_PORT]));
00176         if (tb[CTA_PROTO_ICMP_ID])
00177                 nfnl_ct_set_icmp_id(ct, repl,
00178                                 nla_get_u16(tb[CTA_PROTO_ICMP_ID]));
00179         if (tb[CTA_PROTO_ICMP_TYPE])
00180                 nfnl_ct_set_icmp_type(ct, repl,
00181                                 nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]));
00182         if (tb[CTA_PROTO_ICMP_CODE])
00183                 nfnl_ct_set_icmp_code(ct, repl,
00184                                 nla_get_u8(tb[CTA_PROTO_ICMP_CODE]));
00185 
00186         return 0;
00187 }
00188 
00189 static int ct_parse_tuple(struct nfnl_ct *ct, int repl, struct nlattr *attr)
00190 {
00191         struct nlattr *tb[CTA_TUPLE_MAX+1];
00192         int err;
00193 
00194         err = nla_parse_nested(tb, CTA_TUPLE_MAX, attr, ct_tuple_policy);
00195         if (err < 0)
00196                 return err;
00197 
00198         if (tb[CTA_TUPLE_IP]) {
00199                 err = ct_parse_ip(ct, repl, tb[CTA_TUPLE_IP]);
00200                 if (err < 0)
00201                         return err;
00202         }
00203 
00204         if (tb[CTA_TUPLE_PROTO]) {
00205                 err = ct_parse_proto(ct, repl, tb[CTA_TUPLE_PROTO]);
00206                 if (err < 0)
00207                         return err;
00208         }
00209 
00210         return 0;
00211 }
00212 
00213 static int ct_parse_protoinfo_tcp(struct nfnl_ct *ct, struct nlattr *attr)
00214 {
00215         struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1];
00216         int err;
00217 
00218         err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr,
00219                                ct_protoinfo_tcp_policy);
00220         if (err < 0)
00221                 return err;
00222 
00223         if (tb[CTA_PROTOINFO_TCP_STATE])
00224                 nfnl_ct_set_tcp_state(ct,
00225                                 nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]));
00226 
00227         return 0;
00228 }
00229 
00230 static int ct_parse_protoinfo(struct nfnl_ct *ct, struct nlattr *attr)
00231 {
00232         struct nlattr *tb[CTA_PROTOINFO_MAX+1];
00233         int err;
00234 
00235         err = nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr,
00236                                ct_protoinfo_policy);
00237         if (err < 0)
00238                 return err;
00239 
00240         if (tb[CTA_PROTOINFO_TCP]) {
00241                 err = ct_parse_protoinfo_tcp(ct, tb[CTA_PROTOINFO_TCP]);
00242                 if (err < 0)
00243                         return err;
00244         }
00245 
00246         return 0;
00247 }
00248 
00249 static int ct_parse_counters(struct nfnl_ct *ct, int repl, struct nlattr *attr)
00250 {
00251         struct nlattr *tb[CTA_COUNTERS_MAX+1];
00252         int err;
00253 
00254         err = nla_parse_nested(tb, CTA_COUNTERS_MAX, attr, ct_counters_policy);
00255         if (err < 0)
00256                 return err;
00257 
00258         if (tb[CTA_COUNTERS_PACKETS])
00259                 nfnl_ct_set_packets(ct, repl,
00260                         ntohll(nla_get_u64(tb[CTA_COUNTERS_PACKETS])));
00261         if (tb[CTA_COUNTERS32_PACKETS])
00262                 nfnl_ct_set_packets(ct, repl,
00263                         ntohl(nla_get_u32(tb[CTA_COUNTERS32_PACKETS])));
00264         if (tb[CTA_COUNTERS_BYTES])
00265                 nfnl_ct_set_bytes(ct, repl,
00266                         ntohll(nla_get_u64(tb[CTA_COUNTERS_BYTES])));
00267         if (tb[CTA_COUNTERS32_BYTES])
00268                 nfnl_ct_set_bytes(ct, repl,
00269                         ntohl(nla_get_u32(tb[CTA_COUNTERS32_BYTES])));
00270 
00271         return 0;
00272 }
00273 
00274 int nfnlmsg_ct_group(struct nlmsghdr *nlh)
00275 {
00276         switch (nfnlmsg_subtype(nlh)) {
00277         case IPCTNL_MSG_CT_NEW:
00278                 if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL))
00279                         return NFNLGRP_CONNTRACK_NEW;
00280                 else
00281                         return NFNLGRP_CONNTRACK_UPDATE;
00282         case IPCTNL_MSG_CT_DELETE:
00283                 return NFNLGRP_CONNTRACK_DESTROY;
00284         default:
00285                 return NFNLGRP_NONE;
00286         }
00287 }
00288 
00289 struct nfnl_ct *nfnlmsg_ct_parse(struct nlmsghdr *nlh)
00290 {
00291         struct nfnl_ct *ct;
00292         struct nlattr *tb[CTA_MAX+1];
00293         int err;
00294 
00295         ct = nfnl_ct_alloc();
00296         if (!ct)
00297                 return NULL;
00298 
00299         ct->ce_msgtype = nlh->nlmsg_type;
00300 
00301         err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_MAX,
00302                           ct_policy);
00303         if (err < 0)
00304                 goto errout;
00305 
00306         nfnl_ct_set_family(ct, nfnlmsg_family(nlh));
00307 
00308         if (tb[CTA_TUPLE_ORIG]) {
00309                 err = ct_parse_tuple(ct, 0, tb[CTA_TUPLE_ORIG]);
00310                 if (err < 0)
00311                         goto errout;
00312         }
00313         if (tb[CTA_TUPLE_REPLY]) {
00314                 err = ct_parse_tuple(ct, 1, tb[CTA_TUPLE_REPLY]);
00315                 if (err < 0)
00316                         goto errout;
00317         }
00318 
00319         if (tb[CTA_PROTOINFO]) {
00320                 err = ct_parse_protoinfo(ct, tb[CTA_PROTOINFO]);
00321                 if (err < 0)
00322                         goto errout;
00323         }
00324 
00325         if (tb[CTA_STATUS])
00326                 nfnl_ct_set_status(ct, ntohl(nla_get_u32(tb[CTA_STATUS])));
00327         if (tb[CTA_TIMEOUT])
00328                 nfnl_ct_set_timeout(ct, ntohl(nla_get_u32(tb[CTA_TIMEOUT])));
00329         if (tb[CTA_MARK])
00330                 nfnl_ct_set_mark(ct, ntohl(nla_get_u32(tb[CTA_MARK])));
00331         if (tb[CTA_USE])
00332                 nfnl_ct_set_use(ct, ntohl(nla_get_u32(tb[CTA_USE])));
00333         if (tb[CTA_ID])
00334                 nfnl_ct_set_id(ct, ntohl(nla_get_u32(tb[CTA_ID])));
00335 
00336         if (tb[CTA_COUNTERS_ORIG]) {
00337                 err = ct_parse_counters(ct, 0, tb[CTA_COUNTERS_ORIG]);
00338                 if (err < 0)
00339                         goto errout;
00340         }
00341 
00342         if (tb[CTA_COUNTERS_REPLY]) {
00343                 err = ct_parse_counters(ct, 1, tb[CTA_COUNTERS_REPLY]);
00344                 if (err < 0)
00345                         goto errout;
00346         }
00347 
00348         return ct;
00349 
00350 errout:
00351         nfnl_ct_put(ct);
00352         return NULL;
00353 }
00354 
00355 static int ct_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00356                          struct nlmsghdr *nlh, struct nl_parser_param *pp)
00357 {
00358         struct nfnl_ct *ct;
00359         int err;
00360 
00361         ct = nfnlmsg_ct_parse(nlh);
00362         if (ct == NULL)
00363                 goto errout_errno;
00364 
00365         err = pp->pp_cb((struct nl_object *) ct, pp);
00366         if (err < 0)
00367                 goto errout;
00368 
00369         err = P_ACCEPT;
00370 
00371 errout:
00372         nfnl_ct_put(ct);
00373         return err;
00374 
00375 errout_errno:
00376         err = nl_get_errno();
00377         goto errout;
00378 }
00379 
00380 int nfnl_ct_dump_request(struct nl_handle *h)
00381 {
00382         return nfnl_send_simple(h, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET,
00383                                 NLM_F_DUMP, AF_UNSPEC, 0);
00384 }
00385 
00386 static int ct_request_update(struct nl_cache *c, struct nl_handle *h)
00387 {
00388         return nfnl_ct_dump_request(h);
00389 }
00390 
00391 /**
00392  * @name Cache Management
00393  * @{
00394  */
00395 
00396 /**
00397  * Build a conntrack cache holding all conntrack currently in the kernel
00398  * @arg handle          netlink handle
00399  *
00400  * Allocates a new cache, initializes it properly and updates it to
00401  * contain all conntracks currently in the kernel.
00402  *
00403  * @note The caller is responsible for destroying and freeing the
00404  *       cache after using it.
00405  * @return The cache or NULL if an error has occured.
00406  */
00407 struct nl_cache *nfnl_ct_alloc_cache(struct nl_handle *handle)
00408 {
00409         struct nl_cache *cache;
00410 
00411         cache = nl_cache_alloc(&nfnl_ct_ops);
00412         if (!cache)
00413                 return NULL;
00414 
00415         if (handle && nl_cache_refill(handle, cache) < 0) {
00416                 free(cache);
00417                 return NULL;
00418         }
00419 
00420         return cache;
00421 }
00422 
00423 /** @} */
00424 
00425 /**
00426  * @name Conntrack Addition
00427  * @{
00428  */
00429 
00430 /** @} */
00431 
00432 static struct nl_af_group ct_groups[] = {
00433         { AF_UNSPEC, NFNLGRP_CONNTRACK_NEW },
00434         { AF_UNSPEC, NFNLGRP_CONNTRACK_UPDATE },
00435         { AF_UNSPEC, NFNLGRP_CONNTRACK_DESTROY },
00436         { END_OF_GROUP_LIST },
00437 };
00438 
00439 #define NFNLMSG_CT_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_CTNETLINK, (type))
00440 static struct nl_cache_ops nfnl_ct_ops = {
00441         .co_name                = "netfilter/ct",
00442         .co_hdrsize             = NFNL_HDRLEN,
00443         .co_msgtypes            = {
00444                 { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_NEW), NL_ACT_NEW, "new" },
00445                 { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_GET), NL_ACT_GET, "get" },
00446                 { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_DELETE), NL_ACT_DEL, "del" },
00447                 END_OF_MSGTYPES_LIST,
00448         },
00449         .co_protocol            = NETLINK_NETFILTER,
00450         .co_groups              = ct_groups,
00451         .co_request_update      = ct_request_update,
00452         .co_msg_parser          = ct_msg_parser,
00453         .co_obj_ops             = &ct_obj_ops,
00454 };
00455 
00456 static void __init ct_init(void)
00457 {
00458         nl_cache_mngt_register(&nfnl_ct_ops);
00459 }
00460 
00461 static void __exit ct_exit(void)
00462 {
00463         nl_cache_mngt_unregister(&nfnl_ct_ops);
00464 }
00465 
00466 /** @} */