144d362409d5469aed47d19e7908d19bd194493aThomas Graf/*
244d362409d5469aed47d19e7908d19bd194493aThomas Graf * lib/netfilter/ct.c	Conntrack
344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
444d362409d5469aed47d19e7908d19bd194493aThomas Graf *	This library is free software; you can redistribute it and/or
544d362409d5469aed47d19e7908d19bd194493aThomas Graf *	modify it under the terms of the GNU Lesser General Public
644d362409d5469aed47d19e7908d19bd194493aThomas Graf *	License as published by the Free Software Foundation version 2.1
744d362409d5469aed47d19e7908d19bd194493aThomas Graf *	of the License.
844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
98a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
1044d362409d5469aed47d19e7908d19bd194493aThomas Graf * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
1144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Copyright (c) 2007 Secure Computing Corporation
12596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy * Copyright (c= 2008 Patrick McHardy <kaber@trash.net>
1344d362409d5469aed47d19e7908d19bd194493aThomas Graf */
1444d362409d5469aed47d19e7908d19bd194493aThomas Graf
1544d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
1644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @ingroup nfnl
1744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @defgroup ct Conntrack
1844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @brief
1944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
2044d362409d5469aed47d19e7908d19bd194493aThomas Graf */
2144d362409d5469aed47d19e7908d19bd194493aThomas Graf
2244d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <byteswap.h>
2344d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <sys/types.h>
2444d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <linux/netfilter/nfnetlink_conntrack.h>
2544d362409d5469aed47d19e7908d19bd194493aThomas Graf
2644d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink-local.h>
2744d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/attr.h>
2844d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/netfilter/nfnl.h>
2944d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/netfilter/ct.h>
3044d362409d5469aed47d19e7908d19bd194493aThomas Graf
3144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nl_cache_ops nfnl_ct_ops;
3244d362409d5469aed47d19e7908d19bd194493aThomas Graf
3344d362409d5469aed47d19e7908d19bd194493aThomas Graf#if __BYTE_ORDER == __BIG_ENDIAN
3444d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic uint64_t ntohll(uint64_t x)
3544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
3644d362409d5469aed47d19e7908d19bd194493aThomas Graf	return x;
3744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
3844d362409d5469aed47d19e7908d19bd194493aThomas Graf#elif __BYTE_ORDER == __LITTLE_ENDIAN
3944d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic uint64_t ntohll(uint64_t x)
4044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
4144d362409d5469aed47d19e7908d19bd194493aThomas Graf	return __bswap_64(x);
4244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
4344d362409d5469aed47d19e7908d19bd194493aThomas Graf#endif
4444d362409d5469aed47d19e7908d19bd194493aThomas Graf
4544d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nla_policy ct_policy[CTA_MAX+1] = {
4644d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_TUPLE_ORIG]	= { .type = NLA_NESTED },
4744d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_TUPLE_REPLY]	= { .type = NLA_NESTED },
4844d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_STATUS]		= { .type = NLA_U32 },
4944d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_PROTOINFO]		= { .type = NLA_NESTED },
5044d362409d5469aed47d19e7908d19bd194493aThomas Graf	//[CTA_HELP]
5144d362409d5469aed47d19e7908d19bd194493aThomas Graf	//[CTA_NAT_SRC]
5244d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_TIMEOUT]		= { .type = NLA_U32 },
5344d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_MARK]		= { .type = NLA_U32 },
5444d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_COUNTERS_ORIG]	= { .type = NLA_NESTED },
5544d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_COUNTERS_REPLY]	= { .type = NLA_NESTED },
5644d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_USE]		= { .type = NLA_U32 },
5744d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_ID]		= { .type = NLA_U32 },
5844d362409d5469aed47d19e7908d19bd194493aThomas Graf	//[CTA_NAT_DST]
5944d362409d5469aed47d19e7908d19bd194493aThomas Graf};
6044d362409d5469aed47d19e7908d19bd194493aThomas Graf
6144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nla_policy ct_tuple_policy[CTA_TUPLE_MAX+1] = {
6244d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_TUPLE_IP]		= { .type = NLA_NESTED },
6344d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_TUPLE_PROTO]	= { .type = NLA_NESTED },
6444d362409d5469aed47d19e7908d19bd194493aThomas Graf};
6544d362409d5469aed47d19e7908d19bd194493aThomas Graf
6644d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nla_policy ct_ip_policy[CTA_IP_MAX+1] = {
6744d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_IP_V4_SRC]		= { .type = NLA_U32 },
6844d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_IP_V4_DST]		= { .type = NLA_U32 },
6944d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_IP_V6_SRC]		= { .minlen = 16 },
7044d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_IP_V6_DST]		= { .minlen = 16 },
7144d362409d5469aed47d19e7908d19bd194493aThomas Graf};
7244d362409d5469aed47d19e7908d19bd194493aThomas Graf
7344d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nla_policy ct_proto_policy[CTA_PROTO_MAX+1] = {
7444d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_PROTO_NUM]		= { .type = NLA_U8 },
7544d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_PROTO_SRC_PORT]	= { .type = NLA_U16 },
7644d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_PROTO_DST_PORT]	= { .type = NLA_U16 },
7744d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_PROTO_ICMP_ID]	= { .type = NLA_U16 },
7844d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_PROTO_ICMP_TYPE]	= { .type = NLA_U8 },
7944d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_PROTO_ICMP_CODE]	= { .type = NLA_U8 },
8044d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_PROTO_ICMPV6_ID]	= { .type = NLA_U16 },
8144d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_PROTO_ICMPV6_TYPE]	= { .type = NLA_U8 },
8244d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_PROTO_ICMPV6_CODE]	= { .type = NLA_U8 },
8344d362409d5469aed47d19e7908d19bd194493aThomas Graf};
8444d362409d5469aed47d19e7908d19bd194493aThomas Graf
8544d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nla_policy ct_protoinfo_policy[CTA_PROTOINFO_MAX+1] = {
8644d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_PROTOINFO_TCP]	= { .type = NLA_NESTED },
8744d362409d5469aed47d19e7908d19bd194493aThomas Graf};
8844d362409d5469aed47d19e7908d19bd194493aThomas Graf
8944d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nla_policy ct_protoinfo_tcp_policy[CTA_PROTOINFO_TCP_MAX+1] = {
9044d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_PROTOINFO_TCP_STATE]		= { .type = NLA_U8 },
9144d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]	= { .type = NLA_U8 },
9244d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_PROTOINFO_TCP_WSCALE_REPLY]	= { .type = NLA_U8 },
9344d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]	= { .minlen = 2 },
9444d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_PROTOINFO_TCP_FLAGS_REPLY]		= { .minlen = 2 },
9544d362409d5469aed47d19e7908d19bd194493aThomas Graf
9644d362409d5469aed47d19e7908d19bd194493aThomas Graf};
9744d362409d5469aed47d19e7908d19bd194493aThomas Graf
9844d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nla_policy ct_counters_policy[CTA_COUNTERS_MAX+1] = {
9944d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_COUNTERS_PACKETS]	= { .type = NLA_U64 },
10044d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_COUNTERS_BYTES]	= { .type = NLA_U64 },
10144d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_COUNTERS32_PACKETS]= { .type = NLA_U32 },
10244d362409d5469aed47d19e7908d19bd194493aThomas Graf	[CTA_COUNTERS32_BYTES]	= { .type = NLA_U32 },
10344d362409d5469aed47d19e7908d19bd194493aThomas Graf};
10444d362409d5469aed47d19e7908d19bd194493aThomas Graf
10544d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int ct_parse_ip(struct nfnl_ct *ct, int repl, struct nlattr *attr)
10644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
10744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nlattr *tb[CTA_IP_MAX+1];
10844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_addr *addr;
10944d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
11044d362409d5469aed47d19e7908d19bd194493aThomas Graf
11144d362409d5469aed47d19e7908d19bd194493aThomas Graf        err = nla_parse_nested(tb, CTA_IP_MAX, attr, ct_ip_policy);
11244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (err < 0)
11344d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto errout;
11444d362409d5469aed47d19e7908d19bd194493aThomas Graf
11544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_IP_V4_SRC]) {
116eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		addr = nl_addr_alloc_attr(tb[CTA_IP_V4_SRC], AF_INET);
11744d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (addr == NULL)
118eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			goto errout_enomem;
11944d362409d5469aed47d19e7908d19bd194493aThomas Graf		err = nfnl_ct_set_src(ct, repl, addr);
12044d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_put(addr);
12144d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (err < 0)
12244d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
12344d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
12444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_IP_V4_DST]) {
125eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		addr = nl_addr_alloc_attr(tb[CTA_IP_V4_DST], AF_INET);
12644d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (addr == NULL)
127eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			goto errout_enomem;
12844d362409d5469aed47d19e7908d19bd194493aThomas Graf		err = nfnl_ct_set_dst(ct, repl, addr);
12944d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_put(addr);
13044d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (err < 0)
13144d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
13244d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
13344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_IP_V6_SRC]) {
134eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		addr = nl_addr_alloc_attr(tb[CTA_IP_V6_SRC], AF_INET6);
13544d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (addr == NULL)
136eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			goto errout_enomem;
13744d362409d5469aed47d19e7908d19bd194493aThomas Graf		err = nfnl_ct_set_src(ct, repl, addr);
13844d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_put(addr);
13944d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (err < 0)
14044d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
14144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
14244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_IP_V6_DST]) {
143eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		addr = nl_addr_alloc_attr(tb[CTA_IP_V6_DST], AF_INET6);
14444d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (addr == NULL)
145eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			goto errout_enomem;
14644d362409d5469aed47d19e7908d19bd194493aThomas Graf		err = nfnl_ct_set_dst(ct, repl, addr);
14744d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_put(addr);
14844d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (err < 0)
14944d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
15044d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
15144d362409d5469aed47d19e7908d19bd194493aThomas Graf
15244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
15344d362409d5469aed47d19e7908d19bd194493aThomas Graf
154eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graferrout_enomem:
1558a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	err = -NLE_NOMEM;
15644d362409d5469aed47d19e7908d19bd194493aThomas Graferrout:
15744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return err;
15844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
15944d362409d5469aed47d19e7908d19bd194493aThomas Graf
16044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int ct_parse_proto(struct nfnl_ct *ct, int repl, struct nlattr *attr)
16144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
16244d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nlattr *tb[CTA_PROTO_MAX+1];
16344d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
16444d362409d5469aed47d19e7908d19bd194493aThomas Graf
16544d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = nla_parse_nested(tb, CTA_PROTO_MAX, attr, ct_proto_policy);
16644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (err < 0)
16744d362409d5469aed47d19e7908d19bd194493aThomas Graf		return err;
16844d362409d5469aed47d19e7908d19bd194493aThomas Graf
16944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!repl && tb[CTA_PROTO_NUM])
17044d362409d5469aed47d19e7908d19bd194493aThomas Graf		nfnl_ct_set_proto(ct, nla_get_u8(tb[CTA_PROTO_NUM]));
17144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_PROTO_SRC_PORT])
17244d362409d5469aed47d19e7908d19bd194493aThomas Graf		nfnl_ct_set_src_port(ct, repl,
173337fbd24cad1f5cf9c8b4287a75f2c69f088adceThomas Graf			ntohs(nla_get_u16(tb[CTA_PROTO_SRC_PORT])));
17444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_PROTO_DST_PORT])
17544d362409d5469aed47d19e7908d19bd194493aThomas Graf		nfnl_ct_set_dst_port(ct, repl,
176337fbd24cad1f5cf9c8b4287a75f2c69f088adceThomas Graf			ntohs(nla_get_u16(tb[CTA_PROTO_DST_PORT])));
17744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_PROTO_ICMP_ID])
17844d362409d5469aed47d19e7908d19bd194493aThomas Graf		nfnl_ct_set_icmp_id(ct, repl,
179337fbd24cad1f5cf9c8b4287a75f2c69f088adceThomas Graf			ntohs(nla_get_u16(tb[CTA_PROTO_ICMP_ID])));
18044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_PROTO_ICMP_TYPE])
18144d362409d5469aed47d19e7908d19bd194493aThomas Graf		nfnl_ct_set_icmp_type(ct, repl,
18244d362409d5469aed47d19e7908d19bd194493aThomas Graf				nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]));
18344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_PROTO_ICMP_CODE])
18444d362409d5469aed47d19e7908d19bd194493aThomas Graf		nfnl_ct_set_icmp_code(ct, repl,
18544d362409d5469aed47d19e7908d19bd194493aThomas Graf				nla_get_u8(tb[CTA_PROTO_ICMP_CODE]));
18644d362409d5469aed47d19e7908d19bd194493aThomas Graf
18744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
18844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
18944d362409d5469aed47d19e7908d19bd194493aThomas Graf
19044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int ct_parse_tuple(struct nfnl_ct *ct, int repl, struct nlattr *attr)
19144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
19244d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nlattr *tb[CTA_TUPLE_MAX+1];
19344d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
19444d362409d5469aed47d19e7908d19bd194493aThomas Graf
19544d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = nla_parse_nested(tb, CTA_TUPLE_MAX, attr, ct_tuple_policy);
19644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (err < 0)
19744d362409d5469aed47d19e7908d19bd194493aThomas Graf		return err;
19844d362409d5469aed47d19e7908d19bd194493aThomas Graf
19944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_TUPLE_IP]) {
20044d362409d5469aed47d19e7908d19bd194493aThomas Graf		err = ct_parse_ip(ct, repl, tb[CTA_TUPLE_IP]);
20144d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (err < 0)
20244d362409d5469aed47d19e7908d19bd194493aThomas Graf			return err;
20344d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
20444d362409d5469aed47d19e7908d19bd194493aThomas Graf
20544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_TUPLE_PROTO]) {
20644d362409d5469aed47d19e7908d19bd194493aThomas Graf		err = ct_parse_proto(ct, repl, tb[CTA_TUPLE_PROTO]);
20744d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (err < 0)
20844d362409d5469aed47d19e7908d19bd194493aThomas Graf			return err;
20944d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
21044d362409d5469aed47d19e7908d19bd194493aThomas Graf
21144d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
21244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
21344d362409d5469aed47d19e7908d19bd194493aThomas Graf
21444d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int ct_parse_protoinfo_tcp(struct nfnl_ct *ct, struct nlattr *attr)
21544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
21644d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1];
21744d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
21844d362409d5469aed47d19e7908d19bd194493aThomas Graf
21944d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr,
22044d362409d5469aed47d19e7908d19bd194493aThomas Graf			       ct_protoinfo_tcp_policy);
22144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (err < 0)
22244d362409d5469aed47d19e7908d19bd194493aThomas Graf		return err;
22344d362409d5469aed47d19e7908d19bd194493aThomas Graf
22444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_PROTOINFO_TCP_STATE])
22544d362409d5469aed47d19e7908d19bd194493aThomas Graf		nfnl_ct_set_tcp_state(ct,
22644d362409d5469aed47d19e7908d19bd194493aThomas Graf				nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]));
22744d362409d5469aed47d19e7908d19bd194493aThomas Graf
22844d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
22944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
23044d362409d5469aed47d19e7908d19bd194493aThomas Graf
23144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int ct_parse_protoinfo(struct nfnl_ct *ct, struct nlattr *attr)
23244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
23344d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nlattr *tb[CTA_PROTOINFO_MAX+1];
23444d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
23544d362409d5469aed47d19e7908d19bd194493aThomas Graf
23644d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr,
23744d362409d5469aed47d19e7908d19bd194493aThomas Graf			       ct_protoinfo_policy);
23844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (err < 0)
23944d362409d5469aed47d19e7908d19bd194493aThomas Graf		return err;
24044d362409d5469aed47d19e7908d19bd194493aThomas Graf
24144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_PROTOINFO_TCP]) {
24244d362409d5469aed47d19e7908d19bd194493aThomas Graf		err = ct_parse_protoinfo_tcp(ct, tb[CTA_PROTOINFO_TCP]);
24344d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (err < 0)
24444d362409d5469aed47d19e7908d19bd194493aThomas Graf			return err;
24544d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
24644d362409d5469aed47d19e7908d19bd194493aThomas Graf
24744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
24844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
24944d362409d5469aed47d19e7908d19bd194493aThomas Graf
25044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int ct_parse_counters(struct nfnl_ct *ct, int repl, struct nlattr *attr)
25144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
25244d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nlattr *tb[CTA_COUNTERS_MAX+1];
25344d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
25444d362409d5469aed47d19e7908d19bd194493aThomas Graf
25544d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = nla_parse_nested(tb, CTA_COUNTERS_MAX, attr, ct_counters_policy);
25644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (err < 0)
25744d362409d5469aed47d19e7908d19bd194493aThomas Graf		return err;
25844d362409d5469aed47d19e7908d19bd194493aThomas Graf
25944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_COUNTERS_PACKETS])
26044d362409d5469aed47d19e7908d19bd194493aThomas Graf		nfnl_ct_set_packets(ct, repl,
26144d362409d5469aed47d19e7908d19bd194493aThomas Graf			ntohll(nla_get_u64(tb[CTA_COUNTERS_PACKETS])));
26244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_COUNTERS32_PACKETS])
26344d362409d5469aed47d19e7908d19bd194493aThomas Graf		nfnl_ct_set_packets(ct, repl,
26444d362409d5469aed47d19e7908d19bd194493aThomas Graf			ntohl(nla_get_u32(tb[CTA_COUNTERS32_PACKETS])));
26544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_COUNTERS_BYTES])
26644d362409d5469aed47d19e7908d19bd194493aThomas Graf		nfnl_ct_set_bytes(ct, repl,
26744d362409d5469aed47d19e7908d19bd194493aThomas Graf			ntohll(nla_get_u64(tb[CTA_COUNTERS_BYTES])));
26844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_COUNTERS32_BYTES])
26944d362409d5469aed47d19e7908d19bd194493aThomas Graf		nfnl_ct_set_bytes(ct, repl,
27044d362409d5469aed47d19e7908d19bd194493aThomas Graf			ntohl(nla_get_u32(tb[CTA_COUNTERS32_BYTES])));
27144d362409d5469aed47d19e7908d19bd194493aThomas Graf
27244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
27344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
27444d362409d5469aed47d19e7908d19bd194493aThomas Graf
27544d362409d5469aed47d19e7908d19bd194493aThomas Grafint nfnlmsg_ct_group(struct nlmsghdr *nlh)
27644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
27744d362409d5469aed47d19e7908d19bd194493aThomas Graf	switch (nfnlmsg_subtype(nlh)) {
27844d362409d5469aed47d19e7908d19bd194493aThomas Graf	case IPCTNL_MSG_CT_NEW:
27944d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL))
28044d362409d5469aed47d19e7908d19bd194493aThomas Graf			return NFNLGRP_CONNTRACK_NEW;
28144d362409d5469aed47d19e7908d19bd194493aThomas Graf		else
28244d362409d5469aed47d19e7908d19bd194493aThomas Graf			return NFNLGRP_CONNTRACK_UPDATE;
28344d362409d5469aed47d19e7908d19bd194493aThomas Graf	case IPCTNL_MSG_CT_DELETE:
28444d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NFNLGRP_CONNTRACK_DESTROY;
28544d362409d5469aed47d19e7908d19bd194493aThomas Graf	default:
28644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NFNLGRP_NONE;
28744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
28844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
28944d362409d5469aed47d19e7908d19bd194493aThomas Graf
2908a3efffa5b3fde252675239914118664d36a2c24Thomas Grafint nfnlmsg_ct_parse(struct nlmsghdr *nlh, struct nfnl_ct **result)
29144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
29244d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nfnl_ct *ct;
29344d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nlattr *tb[CTA_MAX+1];
29444d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
29544d362409d5469aed47d19e7908d19bd194493aThomas Graf
29644d362409d5469aed47d19e7908d19bd194493aThomas Graf	ct = nfnl_ct_alloc();
29744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!ct)
2988a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
29944d362409d5469aed47d19e7908d19bd194493aThomas Graf
30044d362409d5469aed47d19e7908d19bd194493aThomas Graf	ct->ce_msgtype = nlh->nlmsg_type;
30144d362409d5469aed47d19e7908d19bd194493aThomas Graf
30244d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_MAX,
30344d362409d5469aed47d19e7908d19bd194493aThomas Graf			  ct_policy);
30444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (err < 0)
30544d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto errout;
30644d362409d5469aed47d19e7908d19bd194493aThomas Graf
30744d362409d5469aed47d19e7908d19bd194493aThomas Graf	nfnl_ct_set_family(ct, nfnlmsg_family(nlh));
30844d362409d5469aed47d19e7908d19bd194493aThomas Graf
30944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_TUPLE_ORIG]) {
31044d362409d5469aed47d19e7908d19bd194493aThomas Graf		err = ct_parse_tuple(ct, 0, tb[CTA_TUPLE_ORIG]);
31144d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (err < 0)
31244d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
31344d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
31444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_TUPLE_REPLY]) {
31544d362409d5469aed47d19e7908d19bd194493aThomas Graf		err = ct_parse_tuple(ct, 1, tb[CTA_TUPLE_REPLY]);
31644d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (err < 0)
31744d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
31844d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
31944d362409d5469aed47d19e7908d19bd194493aThomas Graf
32044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_PROTOINFO]) {
32144d362409d5469aed47d19e7908d19bd194493aThomas Graf		err = ct_parse_protoinfo(ct, tb[CTA_PROTOINFO]);
32244d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (err < 0)
32344d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
32444d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
32544d362409d5469aed47d19e7908d19bd194493aThomas Graf
32644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_STATUS])
32744d362409d5469aed47d19e7908d19bd194493aThomas Graf		nfnl_ct_set_status(ct, ntohl(nla_get_u32(tb[CTA_STATUS])));
32844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_TIMEOUT])
32944d362409d5469aed47d19e7908d19bd194493aThomas Graf		nfnl_ct_set_timeout(ct, ntohl(nla_get_u32(tb[CTA_TIMEOUT])));
33044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_MARK])
33144d362409d5469aed47d19e7908d19bd194493aThomas Graf		nfnl_ct_set_mark(ct, ntohl(nla_get_u32(tb[CTA_MARK])));
33244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_USE])
33344d362409d5469aed47d19e7908d19bd194493aThomas Graf		nfnl_ct_set_use(ct, ntohl(nla_get_u32(tb[CTA_USE])));
33444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_ID])
33544d362409d5469aed47d19e7908d19bd194493aThomas Graf		nfnl_ct_set_id(ct, ntohl(nla_get_u32(tb[CTA_ID])));
33644d362409d5469aed47d19e7908d19bd194493aThomas Graf
33744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_COUNTERS_ORIG]) {
33844d362409d5469aed47d19e7908d19bd194493aThomas Graf		err = ct_parse_counters(ct, 0, tb[CTA_COUNTERS_ORIG]);
33944d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (err < 0)
34044d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
34144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
34244d362409d5469aed47d19e7908d19bd194493aThomas Graf
34344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[CTA_COUNTERS_REPLY]) {
34444d362409d5469aed47d19e7908d19bd194493aThomas Graf		err = ct_parse_counters(ct, 1, tb[CTA_COUNTERS_REPLY]);
34544d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (err < 0)
34644d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
34744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
34844d362409d5469aed47d19e7908d19bd194493aThomas Graf
3498a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	*result = ct;
3508a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return 0;
35144d362409d5469aed47d19e7908d19bd194493aThomas Graf
35244d362409d5469aed47d19e7908d19bd194493aThomas Graferrout:
35344d362409d5469aed47d19e7908d19bd194493aThomas Graf	nfnl_ct_put(ct);
3548a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return err;
35544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
35644d362409d5469aed47d19e7908d19bd194493aThomas Graf
35744d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int ct_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
3583040a1d6254465bed9e44e4d1bf279c2c50cd16aThomas Graf			 struct nlmsghdr *nlh, struct nl_parser_param *pp)
35944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
36044d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nfnl_ct *ct;
36144d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
36244d362409d5469aed47d19e7908d19bd194493aThomas Graf
3638a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	if ((err = nfnlmsg_ct_parse(nlh, &ct)) < 0)
3648a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		goto errout;
36544d362409d5469aed47d19e7908d19bd194493aThomas Graf
36644d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = pp->pp_cb((struct nl_object *) ct, pp);
36744d362409d5469aed47d19e7908d19bd194493aThomas Graferrout:
36844d362409d5469aed47d19e7908d19bd194493aThomas Graf	nfnl_ct_put(ct);
36944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return err;
37044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
37144d362409d5469aed47d19e7908d19bd194493aThomas Graf
3721155370f520cb64657e25153255cf7dc1424317fThomas Grafint nfnl_ct_dump_request(struct nl_sock *sk)
37344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
3741155370f520cb64657e25153255cf7dc1424317fThomas Graf	return nfnl_send_simple(sk, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET,
37544d362409d5469aed47d19e7908d19bd194493aThomas Graf				NLM_F_DUMP, AF_UNSPEC, 0);
37644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
37744d362409d5469aed47d19e7908d19bd194493aThomas Graf
3781155370f520cb64657e25153255cf7dc1424317fThomas Grafstatic int ct_request_update(struct nl_cache *cache, struct nl_sock *sk)
37944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
3801155370f520cb64657e25153255cf7dc1424317fThomas Graf	return nfnl_ct_dump_request(sk);
38144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
38244d362409d5469aed47d19e7908d19bd194493aThomas Graf
383596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardystatic int nfnl_ct_build_tuple(struct nl_msg *msg, const struct nfnl_ct *ct,
384596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy			       int repl)
385596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy{
386596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	struct nlattr *tuple, *ip, *proto;
387596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	struct nl_addr *addr;
388596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	int family;
389596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
390596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	family = nfnl_ct_get_family(ct);
391596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
392596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	tuple = nla_nest_start(msg, repl ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG);
393596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	if (!tuple)
394596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy		goto nla_put_failure;
395596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
396596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	ip = nla_nest_start(msg, CTA_TUPLE_IP);
397596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	if (!ip)
398596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy		goto nla_put_failure;
399596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
400596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	addr = nfnl_ct_get_src(ct, repl);
401596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	if (addr)
402596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy		NLA_PUT_ADDR(msg,
403596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy			     family == AF_INET ? CTA_IP_V4_SRC : CTA_IP_V6_SRC,
404596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy			     addr);
405596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
406596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	addr = nfnl_ct_get_dst(ct, repl);
407596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	if (addr)
408596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy		NLA_PUT_ADDR(msg,
409596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy			     family == AF_INET ? CTA_IP_V4_DST : CTA_IP_V6_DST,
410596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy			     addr);
411596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
412596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	nla_nest_end(msg, ip);
413596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
414596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	proto = nla_nest_start(msg, CTA_TUPLE_PROTO);
415596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	if (!proto)
416596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy		goto nla_put_failure;
417596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
418596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	if (nfnl_ct_test_proto(ct))
419596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy		NLA_PUT_U8(msg, CTA_PROTO_NUM, nfnl_ct_get_proto(ct));
420596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
421596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	if (nfnl_ct_test_src_port(ct, repl))
422596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy		NLA_PUT_U16(msg, CTA_PROTO_SRC_PORT,
423337fbd24cad1f5cf9c8b4287a75f2c69f088adceThomas Graf			htons(nfnl_ct_get_src_port(ct, repl)));
424596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
425596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	if (nfnl_ct_test_dst_port(ct, repl))
426596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy		NLA_PUT_U16(msg, CTA_PROTO_DST_PORT,
427337fbd24cad1f5cf9c8b4287a75f2c69f088adceThomas Graf			htons(nfnl_ct_get_dst_port(ct, repl)));
428596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
429596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	if (nfnl_ct_test_icmp_id(ct, repl))
430596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy		NLA_PUT_U16(msg, CTA_PROTO_ICMP_ID,
431337fbd24cad1f5cf9c8b4287a75f2c69f088adceThomas Graf			htons(nfnl_ct_get_icmp_id(ct, repl)));
432596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
433596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	if (nfnl_ct_test_icmp_type(ct, repl))
434596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy		NLA_PUT_U8(msg, CTA_PROTO_ICMP_TYPE,
435596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy			    nfnl_ct_get_icmp_type(ct, repl));
436596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
437596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	if (nfnl_ct_test_icmp_code(ct, repl))
438596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy		NLA_PUT_U8(msg, CTA_PROTO_ICMP_CODE,
439596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy			    nfnl_ct_get_icmp_code(ct, repl));
440596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
441596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	nla_nest_end(msg, proto);
442596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
443596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	nla_nest_end(msg, tuple);
444596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	return 0;
445596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
446596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardynla_put_failure:
4478a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return -NLE_MSGSIZE;
448596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy}
449596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
4508a3efffa5b3fde252675239914118664d36a2c24Thomas Grafstatic int nfnl_ct_build_message(const struct nfnl_ct *ct, int cmd, int flags,
4518a3efffa5b3fde252675239914118664d36a2c24Thomas Graf				 struct nl_msg **result)
452596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy{
453596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	struct nl_msg *msg;
4548a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	int err;
455596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
456596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_CTNETLINK, cmd, flags,
457596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy				   nfnl_ct_get_family(ct), 0);
458596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	if (msg == NULL)
4598a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
460596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
4618a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	if ((err = nfnl_ct_build_tuple(msg, ct, 0)) < 0)
462596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy		goto err_out;
463596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
4648a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	*result = msg;
4658a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return 0;
466596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
467596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardyerr_out:
468596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	nlmsg_free(msg);
4698a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return err;
470596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy}
471596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
4728a3efffa5b3fde252675239914118664d36a2c24Thomas Grafint nfnl_ct_build_add_request(const struct nfnl_ct *ct, int flags,
4738a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			      struct nl_msg **result)
474596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy{
4758a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_NEW, flags, result);
476596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy}
477596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
4781155370f520cb64657e25153255cf7dc1424317fThomas Grafint nfnl_ct_add(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
479596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy{
480596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	struct nl_msg *msg;
481596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	int err;
482596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
4838a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	if ((err = nfnl_ct_build_add_request(ct, flags, &msg)) < 0)
4848a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return err;
485596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
4861155370f520cb64657e25153255cf7dc1424317fThomas Graf	err = nl_send_auto_complete(sk, msg);
487596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	nlmsg_free(msg);
488596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	if (err < 0)
489596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy		return err;
490596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
491cfcfca070355b246028df60da79813f09ed65755Thomas Graf	return wait_for_ack(sk);
492596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy}
493596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
4948a3efffa5b3fde252675239914118664d36a2c24Thomas Grafint nfnl_ct_build_delete_request(const struct nfnl_ct *ct, int flags,
4958a3efffa5b3fde252675239914118664d36a2c24Thomas Graf				 struct nl_msg **result)
496596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy{
4978a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_DELETE, flags, result);
498596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy}
499596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
5001155370f520cb64657e25153255cf7dc1424317fThomas Grafint nfnl_ct_del(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
501596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy{
502596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	struct nl_msg *msg;
503596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	int err;
504596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
5058a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	if ((err = nfnl_ct_build_delete_request(ct, flags, &msg)) < 0)
5068a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return err;
507596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
5081155370f520cb64657e25153255cf7dc1424317fThomas Graf	err = nl_send_auto_complete(sk, msg);
509596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	nlmsg_free(msg);
510596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	if (err < 0)
511596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy		return err;
512596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
513cfcfca070355b246028df60da79813f09ed65755Thomas Graf	return wait_for_ack(sk);
514596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy}
515596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
5168a3efffa5b3fde252675239914118664d36a2c24Thomas Grafint nfnl_ct_build_query_request(const struct nfnl_ct *ct, int flags,
5178a3efffa5b3fde252675239914118664d36a2c24Thomas Graf				struct nl_msg **result)
518596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy{
5198a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_GET, flags, result);
520596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy}
521596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
5221155370f520cb64657e25153255cf7dc1424317fThomas Grafint nfnl_ct_query(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
523596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy{
524596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	struct nl_msg *msg;
525596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	int err;
526596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
5278a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	if ((err = nfnl_ct_build_query_request(ct, flags, &msg)) < 0)
5288a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return err;
529596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
5301155370f520cb64657e25153255cf7dc1424317fThomas Graf	err = nl_send_auto_complete(sk, msg);
531596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	nlmsg_free(msg);
532596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy	if (err < 0)
533596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy		return err;
534596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
535cfcfca070355b246028df60da79813f09ed65755Thomas Graf	return wait_for_ack(sk);
536596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy}
537596d3bc2e9a55d36667abc9b1339b875abd4e11aPatrick McHardy
53844d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
53944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Cache Management
54044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
54144d362409d5469aed47d19e7908d19bd194493aThomas Graf */
54244d362409d5469aed47d19e7908d19bd194493aThomas Graf
54344d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
54444d362409d5469aed47d19e7908d19bd194493aThomas Graf * Build a conntrack cache holding all conntrack currently in the kernel
5451155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk		Netlink socket.
5468a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * @arg result		Pointer to store resulting cache.
54744d362409d5469aed47d19e7908d19bd194493aThomas Graf *
54844d362409d5469aed47d19e7908d19bd194493aThomas Graf * Allocates a new cache, initializes it properly and updates it to
54944d362409d5469aed47d19e7908d19bd194493aThomas Graf * contain all conntracks currently in the kernel.
55044d362409d5469aed47d19e7908d19bd194493aThomas Graf *
5518a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * @return 0 on success or a negative error code.
55244d362409d5469aed47d19e7908d19bd194493aThomas Graf */
5531155370f520cb64657e25153255cf7dc1424317fThomas Grafint nfnl_ct_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
55444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
5551155370f520cb64657e25153255cf7dc1424317fThomas Graf	return nl_cache_alloc_and_fill(&nfnl_ct_ops, sk, result);
55644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
55744d362409d5469aed47d19e7908d19bd194493aThomas Graf
55844d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
55944d362409d5469aed47d19e7908d19bd194493aThomas Graf
56044d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
56144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Conntrack Addition
56244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
56344d362409d5469aed47d19e7908d19bd194493aThomas Graf */
56444d362409d5469aed47d19e7908d19bd194493aThomas Graf
56544d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
56644d362409d5469aed47d19e7908d19bd194493aThomas Graf
56744d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nl_af_group ct_groups[] = {
56844d362409d5469aed47d19e7908d19bd194493aThomas Graf	{ AF_UNSPEC, NFNLGRP_CONNTRACK_NEW },
56944d362409d5469aed47d19e7908d19bd194493aThomas Graf	{ AF_UNSPEC, NFNLGRP_CONNTRACK_UPDATE },
57044d362409d5469aed47d19e7908d19bd194493aThomas Graf	{ AF_UNSPEC, NFNLGRP_CONNTRACK_DESTROY },
57144d362409d5469aed47d19e7908d19bd194493aThomas Graf	{ END_OF_GROUP_LIST },
57244d362409d5469aed47d19e7908d19bd194493aThomas Graf};
57344d362409d5469aed47d19e7908d19bd194493aThomas Graf
57444d362409d5469aed47d19e7908d19bd194493aThomas Graf#define NFNLMSG_CT_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_CTNETLINK, (type))
57544d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nl_cache_ops nfnl_ct_ops = {
57644d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_name		= "netfilter/ct",
57744d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_hdrsize		= NFNL_HDRLEN,
57844d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_msgtypes		= {
57944d362409d5469aed47d19e7908d19bd194493aThomas Graf		{ NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_NEW), NL_ACT_NEW, "new" },
58044d362409d5469aed47d19e7908d19bd194493aThomas Graf		{ NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_GET), NL_ACT_GET, "get" },
58144d362409d5469aed47d19e7908d19bd194493aThomas Graf		{ NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_DELETE), NL_ACT_DEL, "del" },
58244d362409d5469aed47d19e7908d19bd194493aThomas Graf		END_OF_MSGTYPES_LIST,
58344d362409d5469aed47d19e7908d19bd194493aThomas Graf	},
58444d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_protocol		= NETLINK_NETFILTER,
58544d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_groups		= ct_groups,
58644d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_request_update	= ct_request_update,
58744d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_msg_parser		= ct_msg_parser,
58844d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_obj_ops		= &ct_obj_ops,
58944d362409d5469aed47d19e7908d19bd194493aThomas Graf};
59044d362409d5469aed47d19e7908d19bd194493aThomas Graf
59144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void __init ct_init(void)
59244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
59344d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_cache_mngt_register(&nfnl_ct_ops);
59444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
59544d362409d5469aed47d19e7908d19bd194493aThomas Graf
59644d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void __exit ct_exit(void)
59744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
59844d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_cache_mngt_unregister(&nfnl_ct_ops);
59944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
60044d362409d5469aed47d19e7908d19bd194493aThomas Graf
60144d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
602