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