summaryrefslogtreecommitdiffstats
path: root/lib/netfilter/ct.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/netfilter/ct.c')
-rw-r--r--lib/netfilter/ct.c237
1 files changed, 186 insertions, 51 deletions
diff --git a/lib/netfilter/ct.c b/lib/netfilter/ct.c
index e9df924..9d61b6c 100644
--- a/lib/netfilter/ct.c
+++ b/lib/netfilter/ct.c
@@ -6,9 +6,10 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
* Copyright (c) 2007 Secure Computing Corporation
+ * Copyright (c= 2008 Patrick McHardy <kaber@trash.net>
*/
/**
@@ -112,36 +113,36 @@ static int ct_parse_ip(struct nfnl_ct *ct, int repl, struct nlattr *attr)
goto errout;
if (tb[CTA_IP_V4_SRC]) {
- addr = nla_get_addr(tb[CTA_IP_V4_SRC], AF_INET);
+ addr = nl_addr_alloc_attr(tb[CTA_IP_V4_SRC], AF_INET);
if (addr == NULL)
- goto errout_errno;
+ goto errout_enomem;
err = nfnl_ct_set_src(ct, repl, addr);
nl_addr_put(addr);
if (err < 0)
goto errout;
}
if (tb[CTA_IP_V4_DST]) {
- addr = nla_get_addr(tb[CTA_IP_V4_DST], AF_INET);
+ addr = nl_addr_alloc_attr(tb[CTA_IP_V4_DST], AF_INET);
if (addr == NULL)
- goto errout_errno;
+ goto errout_enomem;
err = nfnl_ct_set_dst(ct, repl, addr);
nl_addr_put(addr);
if (err < 0)
goto errout;
}
if (tb[CTA_IP_V6_SRC]) {
- addr = nla_get_addr(tb[CTA_IP_V6_SRC], AF_INET6);
+ addr = nl_addr_alloc_attr(tb[CTA_IP_V6_SRC], AF_INET6);
if (addr == NULL)
- goto errout_errno;
+ goto errout_enomem;
err = nfnl_ct_set_src(ct, repl, addr);
nl_addr_put(addr);
if (err < 0)
goto errout;
}
if (tb[CTA_IP_V6_DST]) {
- addr = nla_get_addr(tb[CTA_IP_V6_DST], AF_INET6);
+ addr = nl_addr_alloc_attr(tb[CTA_IP_V6_DST], AF_INET6);
if (addr == NULL)
- goto errout_errno;
+ goto errout_enomem;
err = nfnl_ct_set_dst(ct, repl, addr);
nl_addr_put(addr);
if (err < 0)
@@ -150,8 +151,8 @@ static int ct_parse_ip(struct nfnl_ct *ct, int repl, struct nlattr *attr)
return 0;
-errout_errno:
- return nl_get_errno();
+errout_enomem:
+ err = -NLE_NOMEM;
errout:
return err;
}
@@ -169,13 +170,13 @@ static int ct_parse_proto(struct nfnl_ct *ct, int repl, struct nlattr *attr)
nfnl_ct_set_proto(ct, nla_get_u8(tb[CTA_PROTO_NUM]));
if (tb[CTA_PROTO_SRC_PORT])
nfnl_ct_set_src_port(ct, repl,
- nla_get_u16(tb[CTA_PROTO_SRC_PORT]));
+ ntohs(nla_get_u16(tb[CTA_PROTO_SRC_PORT])));
if (tb[CTA_PROTO_DST_PORT])
nfnl_ct_set_dst_port(ct, repl,
- nla_get_u16(tb[CTA_PROTO_DST_PORT]));
+ ntohs(nla_get_u16(tb[CTA_PROTO_DST_PORT])));
if (tb[CTA_PROTO_ICMP_ID])
nfnl_ct_set_icmp_id(ct, repl,
- nla_get_u16(tb[CTA_PROTO_ICMP_ID]));
+ ntohs(nla_get_u16(tb[CTA_PROTO_ICMP_ID])));
if (tb[CTA_PROTO_ICMP_TYPE])
nfnl_ct_set_icmp_type(ct, repl,
nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]));
@@ -286,7 +287,7 @@ int nfnlmsg_ct_group(struct nlmsghdr *nlh)
}
}
-struct nfnl_ct *nfnlmsg_ct_parse(struct nlmsghdr *nlh)
+int nfnlmsg_ct_parse(struct nlmsghdr *nlh, struct nfnl_ct **result)
{
struct nfnl_ct *ct;
struct nlattr *tb[CTA_MAX+1];
@@ -294,7 +295,7 @@ struct nfnl_ct *nfnlmsg_ct_parse(struct nlmsghdr *nlh)
ct = nfnl_ct_alloc();
if (!ct)
- return NULL;
+ return -NLE_NOMEM;
ct->ce_msgtype = nlh->nlmsg_type;
@@ -345,11 +346,12 @@ struct nfnl_ct *nfnlmsg_ct_parse(struct nlmsghdr *nlh)
goto errout;
}
- return ct;
+ *result = ct;
+ return 0;
errout:
nfnl_ct_put(ct);
- return NULL;
+ return err;
}
static int ct_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
@@ -358,34 +360,179 @@ static int ct_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
struct nfnl_ct *ct;
int err;
- ct = nfnlmsg_ct_parse(nlh);
- if (ct == NULL)
- goto errout_errno;
-
- err = pp->pp_cb((struct nl_object *) ct, pp);
- if (err < 0)
+ if ((err = nfnlmsg_ct_parse(nlh, &ct)) < 0)
goto errout;
- err = P_ACCEPT;
-
+ err = pp->pp_cb((struct nl_object *) ct, pp);
errout:
nfnl_ct_put(ct);
return err;
-
-errout_errno:
- err = nl_get_errno();
- goto errout;
}
-int nfnl_ct_dump_request(struct nl_handle *h)
+int nfnl_ct_dump_request(struct nl_sock *sk)
{
- return nfnl_send_simple(h, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET,
+ return nfnl_send_simple(sk, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET,
NLM_F_DUMP, AF_UNSPEC, 0);
}
-static int ct_request_update(struct nl_cache *c, struct nl_handle *h)
+static int ct_request_update(struct nl_cache *cache, struct nl_sock *sk)
+{
+ return nfnl_ct_dump_request(sk);
+}
+
+static int nfnl_ct_build_tuple(struct nl_msg *msg, const struct nfnl_ct *ct,
+ int repl)
+{
+ struct nlattr *tuple, *ip, *proto;
+ struct nl_addr *addr;
+ int family;
+
+ family = nfnl_ct_get_family(ct);
+
+ tuple = nla_nest_start(msg, repl ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG);
+ if (!tuple)
+ goto nla_put_failure;
+
+ ip = nla_nest_start(msg, CTA_TUPLE_IP);
+ if (!ip)
+ goto nla_put_failure;
+
+ addr = nfnl_ct_get_src(ct, repl);
+ if (addr)
+ NLA_PUT_ADDR(msg,
+ family == AF_INET ? CTA_IP_V4_SRC : CTA_IP_V6_SRC,
+ addr);
+
+ addr = nfnl_ct_get_dst(ct, repl);
+ if (addr)
+ NLA_PUT_ADDR(msg,
+ family == AF_INET ? CTA_IP_V4_DST : CTA_IP_V6_DST,
+ addr);
+
+ nla_nest_end(msg, ip);
+
+ proto = nla_nest_start(msg, CTA_TUPLE_PROTO);
+ if (!proto)
+ goto nla_put_failure;
+
+ if (nfnl_ct_test_proto(ct))
+ NLA_PUT_U8(msg, CTA_PROTO_NUM, nfnl_ct_get_proto(ct));
+
+ if (nfnl_ct_test_src_port(ct, repl))
+ NLA_PUT_U16(msg, CTA_PROTO_SRC_PORT,
+ htons(nfnl_ct_get_src_port(ct, repl)));
+
+ if (nfnl_ct_test_dst_port(ct, repl))
+ NLA_PUT_U16(msg, CTA_PROTO_DST_PORT,
+ htons(nfnl_ct_get_dst_port(ct, repl)));
+
+ if (nfnl_ct_test_icmp_id(ct, repl))
+ NLA_PUT_U16(msg, CTA_PROTO_ICMP_ID,
+ htons(nfnl_ct_get_icmp_id(ct, repl)));
+
+ if (nfnl_ct_test_icmp_type(ct, repl))
+ NLA_PUT_U8(msg, CTA_PROTO_ICMP_TYPE,
+ nfnl_ct_get_icmp_type(ct, repl));
+
+ if (nfnl_ct_test_icmp_code(ct, repl))
+ NLA_PUT_U8(msg, CTA_PROTO_ICMP_CODE,
+ nfnl_ct_get_icmp_code(ct, repl));
+
+ nla_nest_end(msg, proto);
+
+ nla_nest_end(msg, tuple);
+ return 0;
+
+nla_put_failure:
+ return -NLE_MSGSIZE;
+}
+
+static int nfnl_ct_build_message(const struct nfnl_ct *ct, int cmd, int flags,
+ struct nl_msg **result)
+{
+ struct nl_msg *msg;
+ int err;
+
+ msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_CTNETLINK, cmd, flags,
+ nfnl_ct_get_family(ct), 0);
+ if (msg == NULL)
+ return -NLE_NOMEM;
+
+ if ((err = nfnl_ct_build_tuple(msg, ct, 0)) < 0)
+ goto err_out;
+
+ *result = msg;
+ return 0;
+
+err_out:
+ nlmsg_free(msg);
+ return err;
+}
+
+int nfnl_ct_build_add_request(const struct nfnl_ct *ct, int flags,
+ struct nl_msg **result)
+{
+ return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_NEW, flags, result);
+}
+
+int nfnl_ct_add(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
{
- return nfnl_ct_dump_request(h);
+ struct nl_msg *msg;
+ int err;
+
+ if ((err = nfnl_ct_build_add_request(ct, flags, &msg)) < 0)
+ return err;
+
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
+ if (err < 0)
+ return err;
+
+ return wait_for_ack(sk);
+}
+
+int nfnl_ct_build_delete_request(const struct nfnl_ct *ct, int flags,
+ struct nl_msg **result)
+{
+ return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_DELETE, flags, result);
+}
+
+int nfnl_ct_del(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
+{
+ struct nl_msg *msg;
+ int err;
+
+ if ((err = nfnl_ct_build_delete_request(ct, flags, &msg)) < 0)
+ return err;
+
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
+ if (err < 0)
+ return err;
+
+ return wait_for_ack(sk);
+}
+
+int nfnl_ct_build_query_request(const struct nfnl_ct *ct, int flags,
+ struct nl_msg **result)
+{
+ return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_GET, flags, result);
+}
+
+int nfnl_ct_query(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
+{
+ struct nl_msg *msg;
+ int err;
+
+ if ((err = nfnl_ct_build_query_request(ct, flags, &msg)) < 0)
+ return err;
+
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
+ if (err < 0)
+ return err;
+
+ return wait_for_ack(sk);
}
/**
@@ -395,29 +542,17 @@ static int ct_request_update(struct nl_cache *c, struct nl_handle *h)
/**
* Build a conntrack cache holding all conntrack currently in the kernel
- * @arg handle netlink handle
+ * @arg sk Netlink socket.
+ * @arg result Pointer to store resulting cache.
*
* Allocates a new cache, initializes it properly and updates it to
* contain all conntracks currently in the kernel.
*
- * @note The caller is responsible for destroying and freeing the
- * cache after using it.
- * @return The cache or NULL if an error has occured.
+ * @return 0 on success or a negative error code.
*/
-struct nl_cache *nfnl_ct_alloc_cache(struct nl_handle *handle)
+int nfnl_ct_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
{
- struct nl_cache *cache;
-
- cache = nl_cache_alloc(&nfnl_ct_ops);
- if (!cache)
- return NULL;
-
- if (handle && nl_cache_refill(handle, cache) < 0) {
- free(cache);
- return NULL;
- }
-
- return cache;
+ return nl_cache_alloc_and_fill(&nfnl_ct_ops, sk, result);
}
/** @} */