16#include "nl-default.h"
20#include <linux/netfilter/nfnetlink_conntrack.h>
22#include <netlink/attr.h>
23#include <netlink/netfilter/nfnl.h>
24#include <netlink/netfilter/ct.h>
26#include "nl-netfilter.h"
27#include "nl-priv-dynamic-core/nl-core.h"
28#include "nl-priv-dynamic-core/cache-api.h"
30static struct nl_cache_ops nfnl_ct_ops;
101 struct nlattr *tb[CTA_IP_MAX+1];
102 struct nl_addr *addr;
109 if (tb[CTA_IP_V4_SRC]) {
113 err = nfnl_ct_set_src(ct, repl, addr);
118 if (tb[CTA_IP_V4_DST]) {
122 err = nfnl_ct_set_dst(ct, repl, addr);
127 if (tb[CTA_IP_V6_SRC]) {
131 err = nfnl_ct_set_src(ct, repl, addr);
136 if (tb[CTA_IP_V6_DST]) {
140 err = nfnl_ct_set_dst(ct, repl, addr);
154static int ct_parse_proto(
struct nfnl_ct *ct,
int repl,
struct nlattr *attr)
156 struct nlattr *tb[CTA_PROTO_MAX+1];
163 if (!repl && tb[CTA_PROTO_NUM])
164 nfnl_ct_set_proto(ct,
nla_get_u8(tb[CTA_PROTO_NUM]));
165 if (tb[CTA_PROTO_SRC_PORT])
166 nfnl_ct_set_src_port(ct, repl,
168 if (tb[CTA_PROTO_DST_PORT])
169 nfnl_ct_set_dst_port(ct, repl,
172 if (ct->ct_family == AF_INET) {
173 if (tb[CTA_PROTO_ICMP_ID])
174 nfnl_ct_set_icmp_id(ct, repl,
176 if (tb[CTA_PROTO_ICMP_TYPE])
177 nfnl_ct_set_icmp_type(ct, repl,
179 if (tb[CTA_PROTO_ICMP_CODE])
180 nfnl_ct_set_icmp_code(ct, repl,
182 }
else if (ct->ct_family == AF_INET6) {
183 if (tb[CTA_PROTO_ICMPV6_ID])
184 nfnl_ct_set_icmp_id(ct, repl,
186 if (tb[CTA_PROTO_ICMPV6_TYPE])
187 nfnl_ct_set_icmp_type(ct, repl,
189 if (tb[CTA_PROTO_ICMPV6_CODE])
190 nfnl_ct_set_icmp_code(ct, repl,
197static int ct_parse_tuple(
struct nfnl_ct *ct,
int repl,
struct nlattr *attr)
199 struct nlattr *tb[CTA_TUPLE_MAX+1];
206 if (tb[CTA_TUPLE_IP]) {
207 err = ct_parse_ip(ct, repl, tb[CTA_TUPLE_IP]);
212 if (tb[CTA_TUPLE_PROTO]) {
213 err = ct_parse_proto(ct, repl, tb[CTA_TUPLE_PROTO]);
221static int ct_parse_protoinfo_tcp(
struct nfnl_ct *ct,
struct nlattr *attr)
223 struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1];
227 ct_protoinfo_tcp_policy);
231 if (tb[CTA_PROTOINFO_TCP_STATE])
232 nfnl_ct_set_tcp_state(ct,
238static int ct_parse_protoinfo(
struct nfnl_ct *ct,
struct nlattr *attr)
240 struct nlattr *tb[CTA_PROTOINFO_MAX+1];
244 ct_protoinfo_policy);
248 if (tb[CTA_PROTOINFO_TCP]) {
249 err = ct_parse_protoinfo_tcp(ct, tb[CTA_PROTOINFO_TCP]);
257static int ct_parse_counters(
struct nfnl_ct *ct,
int repl,
struct nlattr *attr)
259 struct nlattr *tb[CTA_COUNTERS_MAX+1];
266 if (tb[CTA_COUNTERS_PACKETS])
267 nfnl_ct_set_packets(ct, repl,
269 if (tb[CTA_COUNTERS32_PACKETS])
270 nfnl_ct_set_packets(ct, repl,
272 if (tb[CTA_COUNTERS_BYTES])
273 nfnl_ct_set_bytes(ct, repl,
275 if (tb[CTA_COUNTERS32_BYTES])
276 nfnl_ct_set_bytes(ct, repl,
282int nfnlmsg_ct_group(
struct nlmsghdr *nlh)
285 case IPCTNL_MSG_CT_NEW:
286 if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL))
287 return NFNLGRP_CONNTRACK_NEW;
289 return NFNLGRP_CONNTRACK_UPDATE;
290 case IPCTNL_MSG_CT_DELETE:
291 return NFNLGRP_CONNTRACK_DESTROY;
297static int ct_parse_timestamp(
struct nfnl_ct *ct,
struct nlattr *attr)
299 struct nlattr *tb[CTA_TIMESTAMP_MAX + 1];
303 ct_timestamp_policy);
307 if (tb[CTA_TIMESTAMP_START] && tb[CTA_TIMESTAMP_STOP])
308 nfnl_ct_set_timestamp(ct,
315static int _nfnlmsg_ct_parse(
struct nlattr **tb,
struct nfnl_ct *ct)
319 if (tb[CTA_TUPLE_ORIG]) {
320 err = ct_parse_tuple(ct, 0, tb[CTA_TUPLE_ORIG]);
324 if (tb[CTA_TUPLE_REPLY]) {
325 err = ct_parse_tuple(ct, 1, tb[CTA_TUPLE_REPLY]);
330 if (tb[CTA_PROTOINFO]) {
331 err = ct_parse_protoinfo(ct, tb[CTA_PROTOINFO]);
337 nfnl_ct_set_status(ct, ntohl(
nla_get_u32(tb[CTA_STATUS])));
339 nfnl_ct_set_timeout(ct, ntohl(
nla_get_u32(tb[CTA_TIMEOUT])));
341 nfnl_ct_set_mark(ct, ntohl(
nla_get_u32(tb[CTA_MARK])));
343 nfnl_ct_set_use(ct, ntohl(
nla_get_u32(tb[CTA_USE])));
345 nfnl_ct_set_id(ct, ntohl(
nla_get_u32(tb[CTA_ID])));
347 nfnl_ct_set_zone(ct, ntohs(
nla_get_u16(tb[CTA_ZONE])));
349 if (tb[CTA_COUNTERS_ORIG]) {
350 err = ct_parse_counters(ct, 0, tb[CTA_COUNTERS_ORIG]);
355 if (tb[CTA_COUNTERS_REPLY]) {
356 err = ct_parse_counters(ct, 1, tb[CTA_COUNTERS_REPLY]);
361 if (tb[CTA_TIMESTAMP]) {
362 err = ct_parse_timestamp(ct, tb[CTA_TIMESTAMP]);
370int nfnlmsg_ct_parse(
struct nlmsghdr *nlh,
struct nfnl_ct **result)
373 struct nlattr *tb[CTA_MAX+1];
376 ct = nfnl_ct_alloc();
380 ct->ce_msgtype = nlh->nlmsg_type;
382 err =
nlmsg_parse(nlh,
sizeof(
struct nfgenmsg), tb, CTA_MAX,
389 err = _nfnlmsg_ct_parse(tb, ct);
400int nfnlmsg_ct_parse_nested(
struct nlattr *attr,
struct nfnl_ct **result)
403 struct nlattr *tb[CTA_MAX+1];
406 ct = nfnl_ct_alloc();
420 err = _nfnlmsg_ct_parse(tb, ct);
431static int ct_msg_parser(
struct nl_cache_ops *ops,
struct sockaddr_nl *who,
432 struct nlmsghdr *nlh,
struct nl_parser_param *pp)
437 if ((err = nfnlmsg_ct_parse(nlh, &ct)) < 0)
440 err = pp->pp_cb((
struct nl_object *) ct, pp);
455 NLM_F_DUMP, AF_UNSPEC, 0);
458static int ct_request_update(
struct nl_cache *cache,
struct nl_sock *sk)
463static int nfnl_ct_build_tuple(
struct nl_msg *msg,
const struct nfnl_ct *ct,
466 struct nlattr *tuple, *ip, *proto;
467 struct nl_addr *addr;
470 family = nfnl_ct_get_family(ct);
472 tuple =
nla_nest_start(msg, repl ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG);
474 goto nla_put_failure;
478 goto nla_put_failure;
480 addr = nfnl_ct_get_src(ct, repl);
483 family == AF_INET ? CTA_IP_V4_SRC : CTA_IP_V6_SRC,
486 addr = nfnl_ct_get_dst(ct, repl);
489 family == AF_INET ? CTA_IP_V4_DST : CTA_IP_V6_DST,
496 goto nla_put_failure;
498 if (nfnl_ct_test_proto(ct))
499 NLA_PUT_U8(msg, CTA_PROTO_NUM, nfnl_ct_get_proto(ct));
501 if (nfnl_ct_test_src_port(ct, repl))
503 htons(nfnl_ct_get_src_port(ct, repl)));
505 if (nfnl_ct_test_dst_port(ct, repl))
507 htons(nfnl_ct_get_dst_port(ct, repl)));
509 if (family == AF_INET) {
510 if (nfnl_ct_test_icmp_id(ct, repl))
512 htons(nfnl_ct_get_icmp_id(ct, repl)));
514 if (nfnl_ct_test_icmp_type(ct, repl))
516 nfnl_ct_get_icmp_type(ct, repl));
518 if (nfnl_ct_test_icmp_code(ct, repl))
520 nfnl_ct_get_icmp_code(ct, repl));
521 }
else if (family == AF_INET6) {
522 if (nfnl_ct_test_icmp_id(ct, repl))
524 htons(nfnl_ct_get_icmp_id(ct, repl)));
526 if (nfnl_ct_test_icmp_type(ct, repl))
528 nfnl_ct_get_icmp_type(ct, repl));
530 if (nfnl_ct_test_icmp_code(ct, repl))
532 nfnl_ct_get_icmp_code(ct, repl));
544static int nfnl_ct_build_message(
const struct nfnl_ct *ct,
int cmd,
int flags,
545 struct nl_msg **result)
552 nfnl_ct_get_family(ct), 0);
557 if (nfnl_ct_get_src(ct, 1) || nfnl_ct_get_dst(ct, 1)) {
559 if ((err = nfnl_ct_build_tuple(msg, ct, 1)) < 0)
563 if (!reply || nfnl_ct_get_src(ct, 0) || nfnl_ct_get_dst(ct, 0)) {
564 if ((err = nfnl_ct_build_tuple(msg, ct, 0)) < 0)
568 if (nfnl_ct_test_status(ct))
569 NLA_PUT_U32(msg, CTA_STATUS, htonl(nfnl_ct_get_status(ct)));
571 if (nfnl_ct_test_timeout(ct))
572 NLA_PUT_U32(msg, CTA_TIMEOUT, htonl(nfnl_ct_get_timeout(ct)));
574 if (nfnl_ct_test_mark(ct))
575 NLA_PUT_U32(msg, CTA_MARK, htonl(nfnl_ct_get_mark(ct)));
577 if (nfnl_ct_test_id(ct))
578 NLA_PUT_U32(msg, CTA_ID, htonl(nfnl_ct_get_id(ct)));
580 if (nfnl_ct_test_zone(ct))
581 NLA_PUT_U16(msg, CTA_ZONE, htons(nfnl_ct_get_zone(ct)));
592int nfnl_ct_build_add_request(
const struct nfnl_ct *ct,
int flags,
593 struct nl_msg **result)
595 return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_NEW, flags, result);
598int nfnl_ct_add(
struct nl_sock *sk,
const struct nfnl_ct *ct,
int flags)
603 if ((err = nfnl_ct_build_add_request(ct, flags, &msg)) < 0)
611 return wait_for_ack(sk);
614int nfnl_ct_build_delete_request(
const struct nfnl_ct *ct,
int flags,
615 struct nl_msg **result)
617 return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_DELETE, flags, result);
620int nfnl_ct_del(
struct nl_sock *sk,
const struct nfnl_ct *ct,
int flags)
625 if ((err = nfnl_ct_build_delete_request(ct, flags, &msg)) < 0)
633 return wait_for_ack(sk);
636int nfnl_ct_build_query_request(
const struct nfnl_ct *ct,
int flags,
637 struct nl_msg **result)
639 return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_GET, flags, result);
642int nfnl_ct_query(
struct nl_sock *sk,
const struct nfnl_ct *ct,
int flags)
647 if ((err = nfnl_ct_build_query_request(ct, flags, &msg)) < 0)
655 return wait_for_ack(sk);
687static struct nl_af_group ct_groups[] = {
688 { AF_UNSPEC, NFNLGRP_CONNTRACK_NEW },
689 { AF_UNSPEC, NFNLGRP_CONNTRACK_UPDATE },
690 { AF_UNSPEC, NFNLGRP_CONNTRACK_DESTROY },
691 { END_OF_GROUP_LIST },
694#define NFNLMSG_CT_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_CTNETLINK, (type))
695static struct nl_cache_ops nfnl_ct_ops = {
696 .co_name =
"netfilter/ct",
697 .co_hdrsize = NFNL_HDRLEN,
699 { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_NEW), NL_ACT_NEW,
"new" },
700 { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_GET), NL_ACT_GET,
"get" },
701 { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_DELETE), NL_ACT_DEL,
"del" },
702 END_OF_MSGTYPES_LIST,
704 .co_protocol = NETLINK_NETFILTER,
705 .co_groups = ct_groups,
706 .co_request_update = ct_request_update,
707 .co_msg_parser = ct_msg_parser,
708 .co_obj_ops = &ct_obj_ops,
711static void _nl_init ct_init(
void)
716static void _nl_exit ct_exit(
void)
struct nl_addr * nl_addr_alloc_attr(const struct nlattr *nla, int family)
Allocate abstract address based on Netlink attribute.
void nl_addr_put(struct nl_addr *addr)
Decrease the reference counter of an abstract address.
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
uint16_t nla_get_u16(const struct nlattr *nla)
Return payload of 16 bit integer attribute.
#define NLA_PUT_U16(msg, attrtype, value)
Add 16 bit integer attribute to netlink message.
#define NLA_PUT_U8(msg, attrtype, value)
Add 8 bit integer attribute to netlink message.
uint64_t nla_get_u64(const struct nlattr *nla)
Return payload of u64 attribute.
#define NLA_PUT_ADDR(msg, attrtype, addr)
Add address attribute to netlink message.
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
uint8_t nla_get_u8(const struct nlattr *nla)
Return value of 8 bit integer attribute.
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy)
Create attribute index based on nested attribute.
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
@ NLA_NESTED
Nested attributes.
int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
Unregister a set of cache operations.
int nl_cache_mngt_register(struct nl_cache_ops *ops)
Register a set of cache operations.
int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_sock *sock, struct nl_cache **result)
Allocate new cache and fill it.
int nfnl_ct_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
Build a conntrack cache holding all conntrack currently in the kernel.
int nfnl_ct_dump_request(struct nl_sock *sk)
Send nfnl ct dump request.
void nlmsg_free(struct nl_msg *msg)
Release a reference from an netlink message.
int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, const struct nla_policy *policy)
parse attributes of a netlink message
uint8_t nfnlmsg_family(struct nlmsghdr *nlh)
Get netfilter family from message.
int nfnl_send_simple(struct nl_sock *sk, uint8_t subsys_id, uint8_t type, int flags, uint8_t family, uint16_t res_id)
Send trivial netfilter netlink message.
uint8_t nfnlmsg_subtype(struct nlmsghdr *nlh)
Get netfilter message type from message.
struct nl_msg * nfnlmsg_alloc_simple(uint8_t subsys_id, uint8_t type, int flags, uint8_t family, uint16_t res_id)
Allocate a new netfilter netlink message.
int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
Attribute validation policy.
uint16_t type
Type of attribute or NLA_UNSPEC.