Exp checkpoint

This commit is contained in:
Rich Fought 2012-10-05 06:55:04 -07:00
parent ce72837c90
commit 40457db1f4
5 changed files with 1468 additions and 2 deletions

View file

@ -779,6 +779,28 @@ struct nfnl_ct {
struct nfnl_ct_dir ct_repl;
};
struct nfnl_exp {
NLHDR_COMMON
uint8_t exp_family; // IPv4, IPv6, etc - required
uint8_t exp_proto; // tcp, udp, etc - required
union nfnl_ct_protoinfo exp_protoinfo; // ??? Assured, etc?
uint32_t exp_timeout; // required afaik
uint32_t exp_id; // optional
uint16_t exp_zone; // optional
uint32_t exp_class; // optional
uint32_t exp_flags; // optional
char * exp_helper_name; //optional
char * exp_fn; //optional
uint8_t exp_nat_dir; // optional
struct nfnl_ct_dir exp_expect; // required
struct nfnl_ct_dir exp_master; // required
struct nfnl_ct_dir exp_mask; // required
struct nfnl_ct_dir exp_nat; // optional
};
struct nfnl_log {
NLHDR_COMMON

View file

@ -0,0 +1,145 @@
/*
* netlink/netfilter/exp.h Conntrack Expectation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
* Copyright (c) 2007 Secure Computing Corporation
*/
#ifndef NETLINK_EXP_H_
#define NETLINK_EXP_H_
#include <netlink/netlink.h>
#include <netlink/addr.h>
#include <netlink/cache.h>
#include <netlink/msg.h>
#ifdef __cplusplus
extern "C" {
#endif
struct nfnl_exp;
enum nfnl_exp_tuples {
NFNL_EXP_EXPECT,
NFNL_EXP_MASTER,
NFNL_EXP_MASK,
NFNL_EXP_NAT
};
extern struct nl_object_ops exp_obj_ops;
extern struct nfnl_exp * nfnl_exp_alloc(void);
extern int nfnl_exp_alloc_cache(struct nl_sock *, struct nl_cache **);
extern int nfnlmsg_exp_group(struct nlmsghdr *);
extern int nfnlmsg_exp_parse(struct nlmsghdr *, struct nfnl_exp **);
extern void nfnl_exp_get(struct nfnl_exp *);
extern void nfnl_exp_put(struct nfnl_exp *);
extern int nfnl_exp_dump_request(struct nl_sock *);
extern int nfnl_exp_build_add_request(const struct nfnl_exp *, int,
struct nl_msg **);
extern int nfnl_exp_add(struct nl_sock *, const struct nfnl_exp *, int);
extern int nfnl_exp_build_delete_request(const struct nfnl_exp *, int,
struct nl_msg **);
extern int nfnl_exp_del(struct nl_sock *, const struct nfnl_exp *, int);
extern int nfnl_exp_build_query_request(const struct nfnl_exp *, int,
struct nl_msg **);
extern int nfnl_exp_query(struct nl_sock *, const struct nfnl_exp *, int);
extern void nfnl_exp_set_family(struct nfnl_exp *, uint8_t);
extern uint8_t nfnl_exp_get_family(const struct nfnl_exp *);
extern void nfnl_exp_set_proto(struct nfnl_exp *, uint8_t);
extern int nfnl_exp_test_proto(const struct nfnl_exp *);
extern uint8_t nfnl_exp_get_proto(const struct nfnl_exp *);
extern void nfnl_exp_set_timeout(struct nfnl_exp *, uint32_t);
extern int nfnl_exp_test_timeout(const struct nfnl_exp *);
extern uint32_t nfnl_exp_get_timeout(const struct nfnl_exp *);
extern void nfnl_exp_set_id(struct nfnl_exp *, uint32_t);
extern int nfnl_exp_test_id(const struct nfnl_exp *);
extern uint32_t nfnl_exp_get_id(const struct nfnl_exp *);
extern int nfnl_exp_set_helper_name(struct nfnl_exp *, void *);
extern int nfnl_exp_test_helper_name(const struct nfnl_exp *);
extern const char * nfnl_exp_get_helper_name(const struct nfnl_exp *);
extern void nfnl_exp_set_zone(struct nfnl_exp *, uint16_t);
extern int nfnl_exp_test_zone(const struct nfnl_exp *);
extern uint16_t nfnl_exp_get_zone(const struct nfnl_exp *);
extern void nfnl_exp_set_class(struct nfnl_exp *, uint32_t);
extern int nfnl_exp_test_class(const struct nfnl_exp *);
extern uint32_t nfnl_exp_get_class(const struct nfnl_exp *);
extern void nfnl_exp_set_flags(struct nfnl_exp *, uint32_t);
extern int nfnl_exp_test_flags(const struct nfnl_exp *);
extern uint32_t nfnl_exp_get_flags(const struct nfnl_exp *);
extern int nfnl_exp_set_fn(struct nfnl_exp *, void *);
extern int nfnl_exp_test_fn(const struct nfnl_exp *);
extern const char * nfnl_exp_get_fn(const struct nfnl_exp *);
extern void nfnl_exp_set_nat_dir(struct nfnl_exp *, int, uint8_t);
extern int nfnl_exp_test_nat_dir(const struct nfnl_exp *, int);
extern uint8_t nfnl_exp_get_nat_dir(const struct nfnl_exp *, int);
// The int argument specifies which nfnl_ct_dir (expect, master, mask or nat)
// Expectation objects only use orig, not reply
extern int nfnl_exp_test_tuple(const struct nfnl_exp *, int);
extern int nfnl_exp_set_src(struct nfnl_exp *, int, struct nl_addr *);
extern struct nl_addr * nfnl_ct_get_src(const struct nfnl_exp *, int);
extern int nfnl_exp_set_dst(struct nfnl_exp *, int, struct nl_addr *);
extern struct nl_addr * nfnl_exp_get_dst(const struct nfnl_exp *, int);
extern int nfnl_exp_set_l4proto(struct nfnl_exp *, int, uint8_t);
extern int nfnl_exp_test_l4proto(const struct nfnl_exp *);
extern struct uint8_t * nfnl_exp_get_l4proto(const struct nfnl_exp *, int);
extern void nfnl_exp_set_src_port(struct nfnl_exp *, int, uint16_t);
extern uint16_t nfnl_exp_get_src_port(const struct nfnl_exp *, int);
extern void nfnl_exp_set_dst_port(struct nfnl_exp *, int, uint16_t);
extern uint16_t nfnl_exp_get_dst_port(const struct nfnl_exp *, int);
extern void nfnl_exp_set_icmp_id(struct nfnl_exp *, int, uint16_t);
extern uint16_t nfnl_exp_get_icmp_id(const struct nfnl_exp *, int);
extern void nfnl_exp_set_icmp_type(struct nfnl_exp *, int, uint8_t);
extern uint8_t nfnl_exp_get_icmp_type(const struct nfnl_exp *, int);
extern void nfnl_exp_set_icmp_code(struct nfnl_exp *, int, uint8_t);
extern uint8_t nfnl_exp_get_icmp_code(const struct nfnl_exp *, int);
// TODO: Expectation table does support CPU stats get command, not sure if the same
/*
extern void nfnl_ct_set_packets(struct nfnl_ct *, int, uint64_t);
extern int nfnl_ct_test_packets(const struct nfnl_ct *, int);
extern uint64_t nfnl_ct_get_packets(const struct nfnl_ct *,int);
extern void nfnl_ct_set_bytes(struct nfnl_ct *, int, uint64_t);
extern int nfnl_ct_test_bytes(const struct nfnl_ct *, int);
extern uint64_t nfnl_ct_get_bytes(const struct nfnl_ct *, int);
*/
#ifdef __cplusplus
}
#endif
#endif

View file

@ -121,10 +121,10 @@ static void dump_icmp(struct nl_dump_params *p, struct nfnl_ct *ct, int reply)
if (nfnl_ct_test_icmp_type(ct, reply))
nl_dump(p, "icmp type %d ", nfnl_ct_get_icmp_type(ct, reply));
if (nfnl_ct_test_icmp_type(ct, reply))
if (nfnl_ct_test_icmp_code(ct, reply))
nl_dump(p, "code %d ", nfnl_ct_get_icmp_code(ct, reply));
if (nfnl_ct_test_icmp_type(ct, reply))
if (nfnl_ct_test_icmp_id(ct, reply))
nl_dump(p, "id %d ", nfnl_ct_get_icmp_id(ct, reply));
}

601
lib/netfilter/exp.c Normal file
View file

@ -0,0 +1,601 @@
/*
* lib/netfilter/ct.c Conntrack
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* 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>
*/
/**
* @ingroup nfnl
* @defgroup ct Conntrack
* @brief
* @{
*/
#include <byteswap.h>
#include <sys/types.h>
#include <linux/netfilter/nfnetlink_conntrack.h>
#include <netlink-local.h>
#include <netlink/attr.h>
#include <netlink/netfilter/nfnl.h>
#include <netlink/netfilter/ct.h>
static struct nl_cache_ops nfnl_ct_ops;
#if __BYTE_ORDER == __BIG_ENDIAN
static uint64_t ntohll(uint64_t x)
{
return x;
}
#elif __BYTE_ORDER == __LITTLE_ENDIAN
static uint64_t ntohll(uint64_t x)
{
return bswap_64(x);
}
#endif
static struct nla_policy ct_policy[CTA_MAX+1] = {
[CTA_TUPLE_ORIG] = { .type = NLA_NESTED },
[CTA_TUPLE_REPLY] = { .type = NLA_NESTED },
[CTA_STATUS] = { .type = NLA_U32 },
[CTA_PROTOINFO] = { .type = NLA_NESTED },
//[CTA_HELP]
//[CTA_NAT_SRC]
[CTA_TIMEOUT] = { .type = NLA_U32 },
[CTA_MARK] = { .type = NLA_U32 },
[CTA_COUNTERS_ORIG] = { .type = NLA_NESTED },
[CTA_COUNTERS_REPLY] = { .type = NLA_NESTED },
[CTA_USE] = { .type = NLA_U32 },
[CTA_ID] = { .type = NLA_U32 },
//[CTA_NAT_DST]
};
static struct nla_policy ct_tuple_policy[CTA_TUPLE_MAX+1] = {
[CTA_TUPLE_IP] = { .type = NLA_NESTED },
[CTA_TUPLE_PROTO] = { .type = NLA_NESTED },
};
static struct nla_policy ct_ip_policy[CTA_IP_MAX+1] = {
[CTA_IP_V4_SRC] = { .type = NLA_U32 },
[CTA_IP_V4_DST] = { .type = NLA_U32 },
[CTA_IP_V6_SRC] = { .minlen = 16 },
[CTA_IP_V6_DST] = { .minlen = 16 },
};
static struct nla_policy ct_proto_policy[CTA_PROTO_MAX+1] = {
[CTA_PROTO_NUM] = { .type = NLA_U8 },
[CTA_PROTO_SRC_PORT] = { .type = NLA_U16 },
[CTA_PROTO_DST_PORT] = { .type = NLA_U16 },
[CTA_PROTO_ICMP_ID] = { .type = NLA_U16 },
[CTA_PROTO_ICMP_TYPE] = { .type = NLA_U8 },
[CTA_PROTO_ICMP_CODE] = { .type = NLA_U8 },
[CTA_PROTO_ICMPV6_ID] = { .type = NLA_U16 },
[CTA_PROTO_ICMPV6_TYPE] = { .type = NLA_U8 },
[CTA_PROTO_ICMPV6_CODE] = { .type = NLA_U8 },
};
static struct nla_policy ct_protoinfo_policy[CTA_PROTOINFO_MAX+1] = {
[CTA_PROTOINFO_TCP] = { .type = NLA_NESTED },
};
static struct nla_policy ct_protoinfo_tcp_policy[CTA_PROTOINFO_TCP_MAX+1] = {
[CTA_PROTOINFO_TCP_STATE] = { .type = NLA_U8 },
[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL] = { .type = NLA_U8 },
[CTA_PROTOINFO_TCP_WSCALE_REPLY] = { .type = NLA_U8 },
[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL] = { .minlen = 2 },
[CTA_PROTOINFO_TCP_FLAGS_REPLY] = { .minlen = 2 },
};
static struct nla_policy ct_counters_policy[CTA_COUNTERS_MAX+1] = {
[CTA_COUNTERS_PACKETS] = { .type = NLA_U64 },
[CTA_COUNTERS_BYTES] = { .type = NLA_U64 },
[CTA_COUNTERS32_PACKETS]= { .type = NLA_U32 },
[CTA_COUNTERS32_BYTES] = { .type = NLA_U32 },
};
static int ct_parse_ip(struct nfnl_ct *ct, int repl, struct nlattr *attr)
{
struct nlattr *tb[CTA_IP_MAX+1];
struct nl_addr *addr;
int err;
err = nla_parse_nested(tb, CTA_IP_MAX, attr, ct_ip_policy);
if (err < 0)
goto errout;
if (tb[CTA_IP_V4_SRC]) {
addr = nl_addr_alloc_attr(tb[CTA_IP_V4_SRC], AF_INET);
if (addr == NULL)
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 = nl_addr_alloc_attr(tb[CTA_IP_V4_DST], AF_INET);
if (addr == NULL)
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 = nl_addr_alloc_attr(tb[CTA_IP_V6_SRC], AF_INET6);
if (addr == NULL)
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 = nl_addr_alloc_attr(tb[CTA_IP_V6_DST], AF_INET6);
if (addr == NULL)
goto errout_enomem;
err = nfnl_ct_set_dst(ct, repl, addr);
nl_addr_put(addr);
if (err < 0)
goto errout;
}
return 0;
errout_enomem:
err = -NLE_NOMEM;
errout:
return err;
}
static int ct_parse_proto(struct nfnl_ct *ct, int repl, struct nlattr *attr)
{
struct nlattr *tb[CTA_PROTO_MAX+1];
int err;
err = nla_parse_nested(tb, CTA_PROTO_MAX, attr, ct_proto_policy);
if (err < 0)
return err;
if (!repl && tb[CTA_PROTO_NUM])
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,
ntohs(nla_get_u16(tb[CTA_PROTO_SRC_PORT])));
if (tb[CTA_PROTO_DST_PORT])
nfnl_ct_set_dst_port(ct, repl,
ntohs(nla_get_u16(tb[CTA_PROTO_DST_PORT])));
if (tb[CTA_PROTO_ICMP_ID])
nfnl_ct_set_icmp_id(ct, repl,
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]));
if (tb[CTA_PROTO_ICMP_CODE])
nfnl_ct_set_icmp_code(ct, repl,
nla_get_u8(tb[CTA_PROTO_ICMP_CODE]));
return 0;
}
static int ct_parse_tuple(struct nfnl_ct *ct, int repl, struct nlattr *attr)
{
struct nlattr *tb[CTA_TUPLE_MAX+1];
int err;
err = nla_parse_nested(tb, CTA_TUPLE_MAX, attr, ct_tuple_policy);
if (err < 0)
return err;
if (tb[CTA_TUPLE_IP]) {
err = ct_parse_ip(ct, repl, tb[CTA_TUPLE_IP]);
if (err < 0)
return err;
}
if (tb[CTA_TUPLE_PROTO]) {
err = ct_parse_proto(ct, repl, tb[CTA_TUPLE_PROTO]);
if (err < 0)
return err;
}
return 0;
}
static int ct_parse_protoinfo_tcp(struct nfnl_ct *ct, struct nlattr *attr)
{
struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1];
int err;
err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr,
ct_protoinfo_tcp_policy);
if (err < 0)
return err;
if (tb[CTA_PROTOINFO_TCP_STATE])
nfnl_ct_set_tcp_state(ct,
nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]));
return 0;
}
static int ct_parse_protoinfo(struct nfnl_ct *ct, struct nlattr *attr)
{
struct nlattr *tb[CTA_PROTOINFO_MAX+1];
int err;
err = nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr,
ct_protoinfo_policy);
if (err < 0)
return err;
if (tb[CTA_PROTOINFO_TCP]) {
err = ct_parse_protoinfo_tcp(ct, tb[CTA_PROTOINFO_TCP]);
if (err < 0)
return err;
}
return 0;
}
static int ct_parse_counters(struct nfnl_ct *ct, int repl, struct nlattr *attr)
{
struct nlattr *tb[CTA_COUNTERS_MAX+1];
int err;
err = nla_parse_nested(tb, CTA_COUNTERS_MAX, attr, ct_counters_policy);
if (err < 0)
return err;
if (tb[CTA_COUNTERS_PACKETS])
nfnl_ct_set_packets(ct, repl,
ntohll(nla_get_u64(tb[CTA_COUNTERS_PACKETS])));
if (tb[CTA_COUNTERS32_PACKETS])
nfnl_ct_set_packets(ct, repl,
ntohl(nla_get_u32(tb[CTA_COUNTERS32_PACKETS])));
if (tb[CTA_COUNTERS_BYTES])
nfnl_ct_set_bytes(ct, repl,
ntohll(nla_get_u64(tb[CTA_COUNTERS_BYTES])));
if (tb[CTA_COUNTERS32_BYTES])
nfnl_ct_set_bytes(ct, repl,
ntohl(nla_get_u32(tb[CTA_COUNTERS32_BYTES])));
return 0;
}
int nfnlmsg_ct_group(struct nlmsghdr *nlh)
{
switch (nfnlmsg_subtype(nlh)) {
case IPCTNL_MSG_CT_NEW:
if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL))
return NFNLGRP_CONNTRACK_NEW;
else
return NFNLGRP_CONNTRACK_UPDATE;
case IPCTNL_MSG_CT_DELETE:
return NFNLGRP_CONNTRACK_DESTROY;
default:
return NFNLGRP_NONE;
}
}
int nfnlmsg_ct_parse(struct nlmsghdr *nlh, struct nfnl_ct **result)
{
struct nfnl_ct *ct;
struct nlattr *tb[CTA_MAX+1];
int err;
ct = nfnl_ct_alloc();
if (!ct)
return -NLE_NOMEM;
ct->ce_msgtype = nlh->nlmsg_type;
err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_MAX,
ct_policy);
if (err < 0)
goto errout;
nfnl_ct_set_family(ct, nfnlmsg_family(nlh));
if (tb[CTA_TUPLE_ORIG]) {
err = ct_parse_tuple(ct, 0, tb[CTA_TUPLE_ORIG]);
if (err < 0)
goto errout;
}
if (tb[CTA_TUPLE_REPLY]) {
err = ct_parse_tuple(ct, 1, tb[CTA_TUPLE_REPLY]);
if (err < 0)
goto errout;
}
if (tb[CTA_PROTOINFO]) {
err = ct_parse_protoinfo(ct, tb[CTA_PROTOINFO]);
if (err < 0)
goto errout;
}
if (tb[CTA_STATUS])
nfnl_ct_set_status(ct, ntohl(nla_get_u32(tb[CTA_STATUS])));
if (tb[CTA_TIMEOUT])
nfnl_ct_set_timeout(ct, ntohl(nla_get_u32(tb[CTA_TIMEOUT])));
if (tb[CTA_MARK])
nfnl_ct_set_mark(ct, ntohl(nla_get_u32(tb[CTA_MARK])));
if (tb[CTA_USE])
nfnl_ct_set_use(ct, ntohl(nla_get_u32(tb[CTA_USE])));
if (tb[CTA_ID])
nfnl_ct_set_id(ct, ntohl(nla_get_u32(tb[CTA_ID])));
if (tb[CTA_COUNTERS_ORIG]) {
err = ct_parse_counters(ct, 0, tb[CTA_COUNTERS_ORIG]);
if (err < 0)
goto errout;
}
if (tb[CTA_COUNTERS_REPLY]) {
err = ct_parse_counters(ct, 1, tb[CTA_COUNTERS_REPLY]);
if (err < 0)
goto errout;
}
*result = ct;
return 0;
errout:
nfnl_ct_put(ct);
return err;
}
static int ct_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
struct nlmsghdr *nlh, struct nl_parser_param *pp)
{
struct nfnl_ct *ct;
int err;
if ((err = nfnlmsg_ct_parse(nlh, &ct)) < 0)
goto errout;
err = pp->pp_cb((struct nl_object *) ct, pp);
errout:
nfnl_ct_put(ct);
return err;
}
int nfnl_ct_dump_request(struct nl_sock *sk)
{
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 *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)
{
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);
}
/**
* @name Cache Management
* @{
*/
/**
* Build a conntrack cache holding all conntrack currently in the kernel
* @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.
*
* @return 0 on success or a negative error code.
*/
int nfnl_ct_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
{
return nl_cache_alloc_and_fill(&nfnl_ct_ops, sk, result);
}
/** @} */
/**
* @name Conntrack Addition
* @{
*/
/** @} */
static struct nl_af_group ct_groups[] = {
{ AF_UNSPEC, NFNLGRP_CONNTRACK_NEW },
{ AF_UNSPEC, NFNLGRP_CONNTRACK_UPDATE },
{ AF_UNSPEC, NFNLGRP_CONNTRACK_DESTROY },
{ END_OF_GROUP_LIST },
};
#define NFNLMSG_CT_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_CTNETLINK, (type))
static struct nl_cache_ops nfnl_ct_ops = {
.co_name = "netfilter/ct",
.co_hdrsize = NFNL_HDRLEN,
.co_msgtypes = {
{ NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_NEW), NL_ACT_NEW, "new" },
{ NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_GET), NL_ACT_GET, "get" },
{ NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_DELETE), NL_ACT_DEL, "del" },
END_OF_MSGTYPES_LIST,
},
.co_protocol = NETLINK_NETFILTER,
.co_groups = ct_groups,
.co_request_update = ct_request_update,
.co_msg_parser = ct_msg_parser,
.co_obj_ops = &ct_obj_ops,
};
static void __init ct_init(void)
{
nl_cache_mngt_register(&nfnl_ct_ops);
}
static void __exit ct_exit(void)
{
nl_cache_mngt_unregister(&nfnl_ct_ops);
}
/** @} */

698
lib/netfilter/exp_obj.c Normal file
View file

@ -0,0 +1,698 @@
/*
* lib/netfilter/exp_obj.c Conntrack Expectation Object
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
* Copyright (c) 2007 Secure Computing Corporation
*/
#include <sys/types.h>
#include <netinet/in.h>
#include <linux/netfilter/nfnetlink_conntrack.h>
#include <linux/netfilter/nf_conntrack_common.h>
#include <linux/netfilter/nf_conntrack_tcp.h>
#include <netlink-local.h>
#include <netlink/netfilter/nfnl.h>
#include <netlink/netfilter/exp.h>
// The 32-bit attribute mask in the common object header isn't
// big enough to handle all attributes of an expectation. So
// we'll for sure specify optional attributes + parent attributes
// that are required for valid object comparison. Comparison of
// these parent attributes will include nested attributes.
/** @cond SKIP */
#define EXP_ATTR_FAMILY (1UL << 0)
#define EXP_ATTR_PROTO (1UL << 1)
#define EXP_ATTR_TIMEOUT (1UL << 2) // 32-bit
#define EXP_ATTR_ID (1UL << 3) // 32-bit
#define EXP_ATTR_HELPER_NAME (1UL << 4) // string (16 bytes max)
#define EXP_ATTR_ZONE (1UL << 5) // 16-bit
#define EXP_ATTR_CLASS (1UL << 6) // 32-bit
#define EXP_ATTR_FLAGS (1UL << 7) // 32-bit
#define EXP_ATTR_FN (1UL << 8) // String
// Tuples
#define EXP_ATTR_EXPECT (1UL << 9) // contains ip, proto
#define EXP_ATTR_EXPECT_IP (1UL << 10) // contains src, dst
#define EXP_ATTR_EXPECT_L4PROTO (1UL << 11) // contains l4proto # + PORT attrs or ICMP attrs
#define EXP_ATTR_EXPECT_L4PROTO_NUM (1UL << 12)
#define EXP_ATTR_MASTER (1UL << 13) // contains ip, proto
#define EXP_ATTR_MASTER_IP (1UL << 14) // contains src, dst
#define EXP_ATTR_MASTER_L4PROTO (1UL << 15) // contains l4proto # + PORT attrs or ICMP attrs
#define EXP_ATTR_MASTER_L4PROTO_NUM (1UL << 16)
#define EXP_ATTR_MASK (1UL << 17) // contains ip, proto
#define EXP_ATTR_MASK_IP (1UL << 18) // contains src, dst
#define EXP_ATTR_MASK_L4PROTO (1UL << 19) // contains l4proto # + PORT attrs or ICMP attrs
#define EXP_ATTR_MASK_L4PROTO_NUM (1UL << 20)
#define EXP_ATTR_NAT (1UL << 21) // contains ip, proto
#define EXP_ATTR_NAT_IP (1UL << 22) // contains src, dst
#define EXP_ATTR_NAT_L4PROTO (1UL << 23) // contains l4proto # + PORT attrs or ICMP attrs
#define EXP_ATTR_NAT_L4PROTO_NUM (1UL << 24)
#define EXP_ATTR_NAT_DIR (1UL << 25)
/** @endcond */
static void exp_free_data(struct nl_object *c)
{
struct nfnl_exp *exp = (struct nfnl_exp *) c;
if (exp == NULL)
return;
nl_addr_put(exp->exp_expect.src);
nl_addr_put(exp->exp_expect.dst);
nl_addr_put(exp->exp_master.src);
nl_addr_put(exp->exp_master.dst);
nl_addr_put(exp->exp_mask.src);
nl_addr_put(exp->exp_mask.dst);
nl_addr_put(exp->exp_nat.src);
nl_addr_put(exp->exp_nat.dst);
free(exp->exp_fn);
free(exp->exp_helper_name);
}
static int exp_clone(struct nl_object *_dst, struct nl_object *_src)
{
struct nfnl_exp *dst = (struct nfnl_exp *) _dst;
struct nfnl_exp *src = (struct nfnl_exp *) _src;
struct nl_addr *addr;
int result = 0;
// Expectation
if (src->exp_expect.src) {
addr = nl_addr_clone(src->exp_expect.src);
if (!addr)
return -NLE_NOMEM;
dst->exp_expect.src = addr;
}
if (src->exp_expect.dst) {
addr = nl_addr_clone(src->exp_expect.dst);
if (!addr)
return -NLE_NOMEM;
dst->exp_expect.dst = addr;
}
// Master CT
if (src->exp_master.src) {
addr = nl_addr_clone(src->exp_master.src);
if (!addr)
return -NLE_NOMEM;
dst->exp_master.src = addr;
}
if (src->exp_master.dst) {
addr = nl_addr_clone(src->exp_master.dst);
if (!addr)
return -NLE_NOMEM;
dst->exp_master.dst = addr;
}
// Mask
if (src->exp_mask.src) {
addr = nl_addr_clone(src->exp_mask.src);
if (!addr)
return -NLE_NOMEM;
dst->exp_mask.src = addr;
}
if (src->exp_mask.dst) {
addr = nl_addr_clone(src->exp_mask.dst);
if (!addr)
return -NLE_NOMEM;
dst->exp_mask.dst = addr;
}
// NAT
if (src->exp_nat.src) {
addr = nl_addr_clone(src->exp_nat.src);
if (!addr)
return -NLE_NOMEM;
dst->exp_nat.src = addr;
}
if (src->exp_nat.dst) {
addr = nl_addr_clone(src->exp_nat.dst);
if (!addr)
return -NLE_NOMEM;
dst->exp_nat.dst = addr;
}
return 0;
}
static void dump_addr(struct nl_dump_params *p, struct nl_addr *addr, int port)
{
char buf[64];
if (addr)
nl_dump(p, "%s", nl_addr2str(addr, buf, sizeof(buf)));
if (port)
nl_dump(p, ":%u ", port);
else if (addr)
nl_dump(p, " ");
}
static void dump_icmp(struct nl_dump_params *p, struct nfnl_ct *ct, int tuple)
{
nl_dump(p, "icmp type %d ", nfnl_exp_get_icmp_type(ct, tuple));
nl_dump(p, "code %d ", nfnl_exp_get_icmp_code(ct, tuple));
nl_dump(p, "id %d ", nfnl_exp_get_icmp_id(ct, tuple));
}
static void ct_dump_tuples(struct nfnl_exp *exp, struct nl_dump_params *p)
{
struct nl_addr *tuple_src, *tuple_dst;
int tuple_sport = 0, tuple_dport = 0;
int i = NFNL_EXP_EXPECT;
int icmp = 0;
for (i; i <= NFNL_EXP_NAT; i++) {
if (nfnl_exp_test_tuple(exp, i)) {
tuple_src = nfnl_ct_get_src(exp, i);
tuple_dst = nfnl_ct_get_dst(exp, i);
// Don't have tests for individual ports/types/codes/ids,
// just test L4 Proto. Ugly, but can't do much else without
// more mask bits
if (nfnl_exp_test_l4proto(exp, i)) {
int l4proto = nfnl_exp_get_l4proto(exp, i);
if ( !(l4proto == IPPROTO_ICMP ||
l4proto == IPPROTO_ICMPV6) ) {
tuple_sport = nfnl_exp_get_src_port(exp, i);
tuple_dport = nfnl_exp_get_dst_port(exp, i);
} else {
icmp = 1;
}
}
dump_addr(p, tuple_src, tuple_sport);
dump_addr(p, tuple_dst, tuple_dport);
if (icmp)
dump_icmp(p, exp, 0);
}
}
/* Compatible with /proc/net/nf_conntrack */
static void ct_dump_line(struct nl_object *a, struct nl_dump_params *p)
{
struct nfnl_ct *ct = (struct nfnl_ct *) a;
char buf[64];
nl_new_line(p);
if (nfnl_ct_test_proto(ct))
nl_dump(p, "%s ",
nl_ip_proto2str(nfnl_ct_get_proto(ct), buf, sizeof(buf)));
ct_dump_tuples(ct, p);
nl_dump(p, "\n");
}
static void ct_dump_details(struct nl_object *a, struct nl_dump_params *p)
{
struct nfnl_ct *ct = (struct nfnl_ct *) a;
char buf[64];
int fp = 0;
ct_dump_line(a, p);
nl_dump(p, " id 0x%x ", ct->ct_id);
nl_dump_line(p, "family %s ",
nl_af2str(ct->ct_family, buf, sizeof(buf)));
if (nfnl_ct_test_use(ct))
nl_dump(p, "refcnt %u ", nfnl_ct_get_use(ct));
if (nfnl_ct_test_timeout(ct)) {
uint64_t timeout_ms = nfnl_ct_get_timeout(ct) * 1000UL;
nl_dump(p, "timeout %s ",
nl_msec2str(timeout_ms, buf, sizeof(buf)));
}
if (ct->ct_status)
nl_dump(p, "<");
#define PRINT_FLAG(str) \
{ nl_dump(p, "%s%s", fp++ ? "," : "", (str)); }
if (exp->exp_flags & NF_CT_EXPECT_PERMANENT)
PRINT_FLAG("PERMANENT");
if (exp->exp_flags & NF_CT_EXPECT_INACTIVE)
PRINT_FLAG("INACTIVE");
if (exp->exp_flags & NF_CT_EXPECT_USERSPACE)
PRINT_FLAG("USERSPACE");
#undef PRINT_FLAG
if (exp->exp_flags)
nl_dump(p, ">");
nl_dump(p, "\n");
}
/*
static void ct_dump_stats(struct nl_object *a, struct nl_dump_params *p)
{
struct nfnl_ct *ct = (struct nfnl_ct *) a;
double res;
char *unit;
uint64_t packets;
const char * const names[] = {"rx", "tx"};
int i;
ct_dump_details(a, p);
if (!nfnl_ct_test_bytes(ct, 0) ||
!nfnl_ct_test_packets(ct, 0) ||
!nfnl_ct_test_bytes(ct, 1) ||
!nfnl_ct_test_packets(ct, 1))
{
nl_dump_line(p, " Statistics are not available.\n");
nl_dump_line(p, " Please set sysctl net.netfilter.nf_conntrack_acct=1\n");
nl_dump_line(p, " (Require kernel 2.6.27)\n");
return;
}
nl_dump_line(p, " # packets volume\n");
for (i=0; i<=1; i++) {
res = nl_cancel_down_bytes(nfnl_ct_get_bytes(ct, i), &unit);
packets = nfnl_ct_get_packets(ct, i);
nl_dump_line(p, " %s %10" PRIu64 " %7.2f %s\n", names[i], packets, res, unit);
}
}
*/
static int exp_cmp_tuples_loose(struct nfnl_ct_dir *a, struct nfnl_ct_dir *b)
{
// Must return 0 for match, 1 for mismatch
int d = nl_addr_cmp_prefix(a->src, b->src);
if (d == 0) {
d = nl_addr_cmp_prefix(a->dst, b->dst);
if (d == 0) {
}
}
}
static int exp_compare(struct nl_object *_a, struct nl_object *_b,
uint32_t attrs, int flags)
{
struct nfnl_exp *a = (struct nfnl_exp *) _a;
struct nfnl_exp *b = (struct nfnl_exp *) _b;
int diff = 0;
#define EXP_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, EXP_ATTR_##ATTR, a, b, EXPR)
#define EXP_DIFF_VAL(ATTR, FIELD) EXP_DIFF(ATTR, a->FIELD != b->FIELD)
#define EXP_DIFF_ADDR(ATTR, FIELD) \
((flags & LOOSE_COMPARISON) \
? EXP_DIFF(ATTR, nl_addr_cmp_prefix(a->FIELD, b->FIELD)) \
: EXP_DIFF(ATTR, nl_addr_cmp(a->FIELD, b->FIELD)))
#define EXP_DIFF_TUPLE(ATTR, FIELD) \
((flags & LOOSE_COMPARISON) \
? EXP_DIFF(ATTR, exp_cmp_tuples_loose(a->FIELD, b->FIELD)) \
: EXP_DIFF(ATTR, exp_cmp_tuples(a->FIELD, b->FIELD)))
diff |= EXP_DIFF_VAL(FAMILY, exp_family);
diff |= EXP_DIFF_VAL(PROTO, exp_proto);
diff |= EXP_DIFF_VAL(TIMEOUT, exp_timeout);
diff |= EXP_DIFF_VAL(ID, exp_id);
diff |= EXP_DIFF(FLAGS, (a->exp_flags ^ b->exp_flags));
#undef CT_DIFF
#undef CT_DIFF_VAL
#undef CT_DIFF_ADDR
#undef CT_DIFF_TUPLE
return diff;
}
static const struct trans_tbl ct_attrs[] = {
__ADD(CT_ATTR_FAMILY, family)
__ADD(CT_ATTR_PROTO, proto)
__ADD(CT_ATTR_TCP_STATE, tcpstate)
__ADD(CT_ATTR_STATUS, status)
__ADD(CT_ATTR_TIMEOUT, timeout)
__ADD(CT_ATTR_MARK, mark)
__ADD(CT_ATTR_USE, use)
__ADD(CT_ATTR_ID, id)
__ADD(CT_ATTR_ORIG_SRC, origsrc)
__ADD(CT_ATTR_ORIG_DST, origdst)
__ADD(CT_ATTR_ORIG_SRC_PORT, origsrcport)
__ADD(CT_ATTR_ORIG_DST_PORT, origdstport)
__ADD(CT_ATTR_ORIG_ICMP_ID, origicmpid)
__ADD(CT_ATTR_ORIG_ICMP_TYPE, origicmptype)
__ADD(CT_ATTR_ORIG_ICMP_CODE, origicmpcode)
__ADD(CT_ATTR_ORIG_PACKETS, origpackets)
__ADD(CT_ATTR_ORIG_BYTES, origbytes)
__ADD(CT_ATTR_REPL_SRC, replysrc)
__ADD(CT_ATTR_REPL_DST, replydst)
__ADD(CT_ATTR_REPL_SRC_PORT, replysrcport)
__ADD(CT_ATTR_REPL_DST_PORT, replydstport)
__ADD(CT_ATTR_REPL_ICMP_ID, replyicmpid)
__ADD(CT_ATTR_REPL_ICMP_TYPE, replyicmptype)
__ADD(CT_ATTR_REPL_ICMP_CODE, replyicmpcode)
__ADD(CT_ATTR_REPL_PACKETS, replypackets)
__ADD(CT_ATTR_REPL_BYTES, replybytes)
};
static char *ct_attrs2str(int attrs, char *buf, size_t len)
{
return __flags2str(attrs, buf, len, ct_attrs, ARRAY_SIZE(ct_attrs));
}
/**
* @name Allocation/Freeing
* @{
*/
struct nfnl_ct *nfnl_ct_alloc(void)
{
return (struct nfnl_ct *) nl_object_alloc(&ct_obj_ops);
}
void nfnl_ct_get(struct nfnl_ct *ct)
{
nl_object_get((struct nl_object *) ct);
}
void nfnl_ct_put(struct nfnl_ct *ct)
{
nl_object_put((struct nl_object *) ct);
}
/** @} */
/**
* @name Attributes
* @{
*/
void nfnl_exp_set_family(struct nfnl_exp *exp, uint8_t family)
{
exp->exp_family = family;
exp->ce_mask |= EXP_ATTR_FAMILY;
}
uint8_t nfnl_exp_get_family(const struct nfnl_exp *exp)
{
if (exp->ce_mask & EXP_ATTR_FAMILY)
return exp->exp_family;
else
return AF_UNSPEC;
}
void nfnl_exp_set_proto(struct nfnl_exp *exp, uint8_t proto)
{
exp->exp_proto = proto;
exp->ce_mask |= EXP_ATTR_PROTO;
}
int nfnl_exp_test_proto(const struct nfnl_exp *exp)
{
return !!(exp->ce_mask & EXP_ATTR_PROTO);
}
uint8_t nfnl_exp_get_proto(const struct nfnl_exp *ct)
{
return exp->ct_proto;
}
void nfnl_exp_set_flags(struct nfnl_exp *exp, uint32_t flags)
{
exp->exp_flags |= flags;
exp->ce_mask |= EXP_ATTR_FLAGS;
}
void nfnl_exp_unset_flags(struct nfnl_exp *exp, uint32_t flags)
{
exp->exp_flags &= ~flags;
exp->ce_mask |= EXP_ATTR_FLAGS;
}
uint32_t nfnl_exp_get_status(const struct nfnl_exp *exp)
{
return exp->exp_flags;
}
static const struct trans_tbl flag_table[] = {
__ADD(IPS_EXPECTED, expected)
__ADD(IPS_SEEN_REPLY, seen_reply)
__ADD(IPS_ASSURED, assured)
};
char * nfnl_exp_flags2str(int flags, char *buf, size_t len)
{
return __flags2str(flags, buf, len, status_flags,
ARRAY_SIZE(flag_table));
}
int nfnl_exp_str2status(const char *name)
{
return __str2flags(name, flag_table, ARRAY_SIZE(flag_table));
}
void nfnl_exp_set_timeout(struct nfnl_exp *exp, uint32_t timeout)
{
exp->exp_timeout = timeout;
exp->ce_mask |= EXP_ATTR_TIMEOUT;
}
int nfnl_exp_test_timeout(const struct nfnl_exp *exp)
{
return !!(exp->ce_mask & EXP_ATTR_TIMEOUT);
}
uint32_t nfnl_exp_get_timeout(const struct nfnl_exp *exp)
{
return exp->exp_timeout;
}
void nfnl_exp_set_id(struct nfnl_exp *exp, uint32_t id)
{
exp->exp_id = id;
exp->ce_mask |= EXP_ATTR_ID;
}
int nfnl_exp_test_id(const struct nfnl_exp *exp)
{
return !!(exp->ce_mask & EXP_ATTR_ID);
}
uint32_t nfnl_exp_get_id(const struct nfnl_exp *exp)
{
return exp->exp_id;
}
static int exp_set_addr(struct nfnl_exp *exp, struct nl_addr *addr,
int attr, struct nl_addr ** exp_addr)
{
if (exp->ce_mask & EXP_ATTR_FAMILY) {
if (addr->a_family != exp->exp_family)
return -NLE_AF_MISMATCH;
} else
nfnl_exp_set_family(exp, addr->a_family);
if (*exp_addr)
nl_addr_put(*exp_addr);
nl_addr_get(addr);
*exp_addr = addr;
exp->ce_mask |= attr;
return 0;
}
int nfnl_exp_set_src(struct nfnl_exp *exp, int tuple, struct nl_addr *addr)
{
struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
int attr = repl ? CT_ATTR_REPL_SRC : CT_ATTR_ORIG_SRC;
switch (tuple) {
case :
dir = &exp->exp_expect;
attr = EXP_ATTR_
break;
case :
dir = &exp->exp_master;
break;
case :
dir = &exp->exp_mask;
break;
case :
dir = &exp->exp_nat;
default :
}
return ct_set_addr(ct, addr, attr, &dir->src);
}
int nfnl_ct_set_dst(struct nfnl_ct *ct, int repl, struct nl_addr *addr)
{
struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
int attr = repl ? CT_ATTR_REPL_DST : CT_ATTR_ORIG_DST;
return ct_set_addr(ct, addr, attr, &dir->dst);
}
struct nl_addr *nfnl_ct_get_src(const struct nfnl_ct *ct, int repl)
{
const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
int attr = repl ? CT_ATTR_REPL_SRC : CT_ATTR_ORIG_SRC;
if (!(ct->ce_mask & attr))
return NULL;
return dir->src;
}
struct nl_addr *nfnl_ct_get_dst(const struct nfnl_ct *ct, int repl)
{
const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
int attr = repl ? CT_ATTR_REPL_DST : CT_ATTR_ORIG_DST;
if (!(ct->ce_mask & attr))
return NULL;
return dir->dst;
}
void nfnl_ct_set_src_port(struct nfnl_ct *ct, int repl, uint16_t port)
{
struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
int attr = repl ? CT_ATTR_REPL_SRC_PORT : CT_ATTR_ORIG_SRC_PORT;
dir->proto.port.src = port;
ct->ce_mask |= attr;
}
int nfnl_ct_test_src_port(const struct nfnl_ct *ct, int repl)
{
int attr = repl ? CT_ATTR_REPL_SRC_PORT : CT_ATTR_ORIG_SRC_PORT;
return !!(ct->ce_mask & attr);
}
uint16_t nfnl_ct_get_src_port(const struct nfnl_ct *ct, int repl)
{
const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
return dir->proto.port.src;
}
void nfnl_ct_set_dst_port(struct nfnl_ct *ct, int repl, uint16_t port)
{
struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
int attr = repl ? CT_ATTR_REPL_DST_PORT : CT_ATTR_ORIG_DST_PORT;
dir->proto.port.dst = port;
ct->ce_mask |= attr;
}
int nfnl_ct_test_dst_port(const struct nfnl_ct *ct, int repl)
{
int attr = repl ? CT_ATTR_REPL_DST_PORT : CT_ATTR_ORIG_DST_PORT;
return !!(ct->ce_mask & attr);
}
uint16_t nfnl_ct_get_dst_port(const struct nfnl_ct *ct, int repl)
{
const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
return dir->proto.port.dst;
}
void nfnl_ct_set_icmp_id(struct nfnl_ct *ct, int repl, uint16_t id)
{
struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
int attr = repl ? CT_ATTR_REPL_ICMP_ID : CT_ATTR_ORIG_ICMP_ID;
dir->proto.icmp.id = id;
ct->ce_mask |= attr;
}
int nfnl_ct_test_icmp_id(const struct nfnl_ct *ct, int repl)
{
int attr = repl ? CT_ATTR_REPL_ICMP_ID : CT_ATTR_ORIG_ICMP_ID;
return !!(ct->ce_mask & attr);
}
uint16_t nfnl_ct_get_icmp_id(const struct nfnl_ct *ct, int repl)
{
const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
return dir->proto.icmp.id;
}
void nfnl_ct_set_icmp_type(struct nfnl_ct *ct, int repl, uint8_t type)
{
struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
int attr = repl ? CT_ATTR_REPL_ICMP_TYPE : CT_ATTR_ORIG_ICMP_TYPE;
dir->proto.icmp.type = type;
ct->ce_mask |= attr;
}
int nfnl_ct_test_icmp_type(const struct nfnl_ct *ct, int repl)
{
int attr = repl ? CT_ATTR_REPL_ICMP_TYPE : CT_ATTR_ORIG_ICMP_TYPE;
return !!(ct->ce_mask & attr);
}
uint8_t nfnl_ct_get_icmp_type(const struct nfnl_ct *ct, int repl)
{
const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
return dir->proto.icmp.type;
}
void nfnl_ct_set_icmp_code(struct nfnl_ct *ct, int repl, uint8_t code)
{
struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
int attr = repl ? CT_ATTR_REPL_ICMP_CODE : CT_ATTR_ORIG_ICMP_CODE;
dir->proto.icmp.code = code;
ct->ce_mask |= attr;
}
int nfnl_ct_test_icmp_code(const struct nfnl_ct *ct, int repl)
{
int attr = repl ? CT_ATTR_REPL_ICMP_CODE : CT_ATTR_ORIG_ICMP_CODE;
return !!(ct->ce_mask & attr);
}
uint8_t nfnl_ct_get_icmp_code(const struct nfnl_ct *ct, int tuple)
{
const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
return dir->proto.icmp.code;
}
/** @} */
struct nl_object_ops exp_obj_ops = {
.oo_name = "netfilter/exp",
.oo_size = sizeof(struct nfnl_exp),
.oo_free_data = exp_free_data,
.oo_clone = exp_clone,
.oo_dump = {
[NL_DUMP_LINE] = exp_dump_line,
[NL_DUMP_DETAILS] = exp_dump_details,
[NL_DUMP_STATS] = exp_dump_stats,
},
.oo_compare = exp_compare,
.oo_attrs2str = exp_attrs2str,
};
/** @} */