Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
Pablo Neira Ayuso says: ==================== Netfilter updates for net-next The following patchset contains Netfilter updates for net-next, they are: 1) Release nf_tables objects on netns destructions via nft_release_afinfo(). 2) Destroy basechain and rules on netdevice removal in the new netdev family. 3) Get rid of defensive check against removal of inactive objects in nf_tables. 4) Pass down netns pointer to our existing nfnetlink callbacks, as well as commit() and abort() nfnetlink callbacks. 5) Allow to invert limit expression in nf_tables, so we can throttle overlimit traffic. 6) Add packet duplication for the netdev family. 7) Add forward expression for the netdev family. 8) Define pr_fmt() in conntrack helpers. 9) Don't leave nfqueue configuration on inconsistent state in case of errors, from Ken-ichirou MATSUZAWA, follow up patches are also from him. 10) Skip queue option handling after unbind. 11) Return error on unknown both in nfqueue and nflog command. 12) Autoload ctnetlink when NFQA_CFG_F_CONNTRACK is set. 13) Add new NFTA_SET_USERDATA attribute to store user data in sets, from Carlos Falgueras. 14) Add support for 64 bit byteordering changes nf_tables, from Florian Westphal. 15) Add conntrack byte/packet counter matching support to nf_tables, also from Florian. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
9b59377b75
34 changed files with 750 additions and 370 deletions
|
@ -8,12 +8,12 @@
|
||||||
#include <uapi/linux/netfilter/nfnetlink.h>
|
#include <uapi/linux/netfilter/nfnetlink.h>
|
||||||
|
|
||||||
struct nfnl_callback {
|
struct nfnl_callback {
|
||||||
int (*call)(struct sock *nl, struct sk_buff *skb,
|
int (*call)(struct net *net, struct sock *nl, struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
|
||||||
const struct nlattr * const cda[]);
|
|
||||||
int (*call_rcu)(struct sock *nl, struct sk_buff *skb,
|
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const cda[]);
|
const struct nlattr * const cda[]);
|
||||||
|
int (*call_rcu)(struct net *net, struct sock *nl, struct sk_buff *skb,
|
||||||
|
const struct nlmsghdr *nlh,
|
||||||
|
const struct nlattr * const cda[]);
|
||||||
int (*call_batch)(struct net *net, struct sock *nl, struct sk_buff *skb,
|
int (*call_batch)(struct net *net, struct sock *nl, struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const cda[]);
|
const struct nlattr * const cda[]);
|
||||||
|
@ -26,8 +26,8 @@ struct nfnetlink_subsystem {
|
||||||
__u8 subsys_id; /* nfnetlink subsystem ID */
|
__u8 subsys_id; /* nfnetlink subsystem ID */
|
||||||
__u8 cb_count; /* number of callbacks */
|
__u8 cb_count; /* number of callbacks */
|
||||||
const struct nfnl_callback *cb; /* callback for individual types */
|
const struct nfnl_callback *cb; /* callback for individual types */
|
||||||
int (*commit)(struct sk_buff *skb);
|
int (*commit)(struct net *net, struct sk_buff *skb);
|
||||||
int (*abort)(struct sk_buff *skb);
|
int (*abort)(struct net *net, struct sk_buff *skb);
|
||||||
};
|
};
|
||||||
|
|
||||||
int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n);
|
int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n);
|
||||||
|
|
6
include/net/netfilter/nf_dup_netdev.h
Normal file
6
include/net/netfilter/nf_dup_netdev.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef _NF_DUP_NETDEV_H_
|
||||||
|
#define _NF_DUP_NETDEV_H_
|
||||||
|
|
||||||
|
void nf_dup_netdev_egress(const struct nft_pktinfo *pkt, int oif);
|
||||||
|
|
||||||
|
#endif
|
|
@ -291,6 +291,8 @@ void nft_unregister_set(struct nft_set_ops *ops);
|
||||||
* @timeout: default timeout value in msecs
|
* @timeout: default timeout value in msecs
|
||||||
* @gc_int: garbage collection interval in msecs
|
* @gc_int: garbage collection interval in msecs
|
||||||
* @policy: set parameterization (see enum nft_set_policies)
|
* @policy: set parameterization (see enum nft_set_policies)
|
||||||
|
* @udlen: user data length
|
||||||
|
* @udata: user data
|
||||||
* @ops: set ops
|
* @ops: set ops
|
||||||
* @pnet: network namespace
|
* @pnet: network namespace
|
||||||
* @flags: set flags
|
* @flags: set flags
|
||||||
|
@ -310,6 +312,8 @@ struct nft_set {
|
||||||
u64 timeout;
|
u64 timeout;
|
||||||
u32 gc_int;
|
u32 gc_int;
|
||||||
u16 policy;
|
u16 policy;
|
||||||
|
u16 udlen;
|
||||||
|
unsigned char *udata;
|
||||||
/* runtime data below here */
|
/* runtime data below here */
|
||||||
const struct nft_set_ops *ops ____cacheline_aligned;
|
const struct nft_set_ops *ops ____cacheline_aligned;
|
||||||
possible_net_t pnet;
|
possible_net_t pnet;
|
||||||
|
@ -821,10 +825,7 @@ static inline struct nft_base_chain *nft_base_chain(const struct nft_chain *chai
|
||||||
return container_of(chain, struct nft_base_chain, chain);
|
return container_of(chain, struct nft_base_chain, chain);
|
||||||
}
|
}
|
||||||
|
|
||||||
int nft_register_basechain(struct nft_base_chain *basechain,
|
int __nft_release_basechain(struct nft_ctx *ctx);
|
||||||
unsigned int hook_nops);
|
|
||||||
void nft_unregister_basechain(struct nft_base_chain *basechain,
|
|
||||||
unsigned int hook_nops);
|
|
||||||
|
|
||||||
unsigned int nft_do_chain(struct nft_pktinfo *pkt, void *priv);
|
unsigned int nft_do_chain(struct nft_pktinfo *pkt, void *priv);
|
||||||
|
|
||||||
|
@ -880,7 +881,7 @@ struct nft_af_info {
|
||||||
};
|
};
|
||||||
|
|
||||||
int nft_register_afinfo(struct net *, struct nft_af_info *);
|
int nft_register_afinfo(struct net *, struct nft_af_info *);
|
||||||
void nft_unregister_afinfo(struct nft_af_info *);
|
void nft_unregister_afinfo(struct net *, struct nft_af_info *);
|
||||||
|
|
||||||
int nft_register_chain_type(const struct nf_chain_type *);
|
int nft_register_chain_type(const struct nf_chain_type *);
|
||||||
void nft_unregister_chain_type(const struct nf_chain_type *);
|
void nft_unregister_chain_type(const struct nf_chain_type *);
|
||||||
|
|
|
@ -291,6 +291,7 @@ enum nft_set_desc_attributes {
|
||||||
* @NFTA_SET_ID: uniquely identifies a set in a transaction (NLA_U32)
|
* @NFTA_SET_ID: uniquely identifies a set in a transaction (NLA_U32)
|
||||||
* @NFTA_SET_TIMEOUT: default timeout value (NLA_U64)
|
* @NFTA_SET_TIMEOUT: default timeout value (NLA_U64)
|
||||||
* @NFTA_SET_GC_INTERVAL: garbage collection interval (NLA_U32)
|
* @NFTA_SET_GC_INTERVAL: garbage collection interval (NLA_U32)
|
||||||
|
* @NFTA_SET_USERDATA: user data (NLA_BINARY)
|
||||||
*/
|
*/
|
||||||
enum nft_set_attributes {
|
enum nft_set_attributes {
|
||||||
NFTA_SET_UNSPEC,
|
NFTA_SET_UNSPEC,
|
||||||
|
@ -306,6 +307,7 @@ enum nft_set_attributes {
|
||||||
NFTA_SET_ID,
|
NFTA_SET_ID,
|
||||||
NFTA_SET_TIMEOUT,
|
NFTA_SET_TIMEOUT,
|
||||||
NFTA_SET_GC_INTERVAL,
|
NFTA_SET_GC_INTERVAL,
|
||||||
|
NFTA_SET_USERDATA,
|
||||||
__NFTA_SET_MAX
|
__NFTA_SET_MAX
|
||||||
};
|
};
|
||||||
#define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
|
#define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
|
||||||
|
@ -755,6 +757,8 @@ enum nft_ct_keys {
|
||||||
NFT_CT_PROTO_SRC,
|
NFT_CT_PROTO_SRC,
|
||||||
NFT_CT_PROTO_DST,
|
NFT_CT_PROTO_DST,
|
||||||
NFT_CT_LABELS,
|
NFT_CT_LABELS,
|
||||||
|
NFT_CT_PKTS,
|
||||||
|
NFT_CT_BYTES,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -780,6 +784,10 @@ enum nft_limit_type {
|
||||||
NFT_LIMIT_PKT_BYTES
|
NFT_LIMIT_PKT_BYTES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum nft_limit_flags {
|
||||||
|
NFT_LIMIT_F_INV = (1 << 0),
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enum nft_limit_attributes - nf_tables limit expression netlink attributes
|
* enum nft_limit_attributes - nf_tables limit expression netlink attributes
|
||||||
*
|
*
|
||||||
|
@ -787,6 +795,7 @@ enum nft_limit_type {
|
||||||
* @NFTA_LIMIT_UNIT: refill unit (NLA_U64)
|
* @NFTA_LIMIT_UNIT: refill unit (NLA_U64)
|
||||||
* @NFTA_LIMIT_BURST: burst (NLA_U32)
|
* @NFTA_LIMIT_BURST: burst (NLA_U32)
|
||||||
* @NFTA_LIMIT_TYPE: type of limit (NLA_U32: enum nft_limit_type)
|
* @NFTA_LIMIT_TYPE: type of limit (NLA_U32: enum nft_limit_type)
|
||||||
|
* @NFTA_LIMIT_FLAGS: flags (NLA_U32: enum nft_limit_flags)
|
||||||
*/
|
*/
|
||||||
enum nft_limit_attributes {
|
enum nft_limit_attributes {
|
||||||
NFTA_LIMIT_UNSPEC,
|
NFTA_LIMIT_UNSPEC,
|
||||||
|
@ -794,6 +803,7 @@ enum nft_limit_attributes {
|
||||||
NFTA_LIMIT_UNIT,
|
NFTA_LIMIT_UNIT,
|
||||||
NFTA_LIMIT_BURST,
|
NFTA_LIMIT_BURST,
|
||||||
NFTA_LIMIT_TYPE,
|
NFTA_LIMIT_TYPE,
|
||||||
|
NFTA_LIMIT_FLAGS,
|
||||||
__NFTA_LIMIT_MAX
|
__NFTA_LIMIT_MAX
|
||||||
};
|
};
|
||||||
#define NFTA_LIMIT_MAX (__NFTA_LIMIT_MAX - 1)
|
#define NFTA_LIMIT_MAX (__NFTA_LIMIT_MAX - 1)
|
||||||
|
@ -977,6 +987,18 @@ enum nft_dup_attributes {
|
||||||
};
|
};
|
||||||
#define NFTA_DUP_MAX (__NFTA_DUP_MAX - 1)
|
#define NFTA_DUP_MAX (__NFTA_DUP_MAX - 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum nft_fwd_attributes - nf_tables fwd expression netlink attributes
|
||||||
|
*
|
||||||
|
* @NFTA_FWD_SREG_DEV: source register of output interface (NLA_U32: nft_register)
|
||||||
|
*/
|
||||||
|
enum nft_fwd_attributes {
|
||||||
|
NFTA_FWD_UNSPEC,
|
||||||
|
NFTA_FWD_SREG_DEV,
|
||||||
|
__NFTA_FWD_MAX
|
||||||
|
};
|
||||||
|
#define NFTA_FWD_MAX (__NFTA_FWD_MAX - 1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enum nft_gen_attributes - nf_tables ruleset generation attributes
|
* enum nft_gen_attributes - nf_tables ruleset generation attributes
|
||||||
*
|
*
|
||||||
|
|
|
@ -141,7 +141,7 @@ err:
|
||||||
|
|
||||||
static void nf_tables_bridge_exit_net(struct net *net)
|
static void nf_tables_bridge_exit_net(struct net *net)
|
||||||
{
|
{
|
||||||
nft_unregister_afinfo(net->nft.bridge);
|
nft_unregister_afinfo(net, net->nft.bridge);
|
||||||
kfree(net->nft.bridge);
|
kfree(net->nft.bridge);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ err:
|
||||||
|
|
||||||
static void nf_tables_arp_exit_net(struct net *net)
|
static void nf_tables_arp_exit_net(struct net *net)
|
||||||
{
|
{
|
||||||
nft_unregister_afinfo(net->nft.arp);
|
nft_unregister_afinfo(net, net->nft.arp);
|
||||||
kfree(net->nft.arp);
|
kfree(net->nft.arp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,7 @@ err:
|
||||||
|
|
||||||
static void nf_tables_ipv4_exit_net(struct net *net)
|
static void nf_tables_ipv4_exit_net(struct net *net)
|
||||||
{
|
{
|
||||||
nft_unregister_afinfo(net->nft.ipv4);
|
nft_unregister_afinfo(net, net->nft.ipv4);
|
||||||
kfree(net->nft.ipv4);
|
kfree(net->nft.ipv4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ err:
|
||||||
|
|
||||||
static void nf_tables_ipv6_exit_net(struct net *net)
|
static void nf_tables_ipv6_exit_net(struct net *net)
|
||||||
{
|
{
|
||||||
nft_unregister_afinfo(net->nft.ipv6);
|
nft_unregister_afinfo(net, net->nft.ipv6);
|
||||||
kfree(net->nft.ipv6);
|
kfree(net->nft.ipv6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -563,6 +563,28 @@ config NFT_COMPAT
|
||||||
x_tables match/target extensions over the nf_tables
|
x_tables match/target extensions over the nf_tables
|
||||||
framework.
|
framework.
|
||||||
|
|
||||||
|
if NF_TABLES_NETDEV
|
||||||
|
|
||||||
|
config NF_DUP_NETDEV
|
||||||
|
tristate "Netfilter packet duplication support"
|
||||||
|
help
|
||||||
|
This option enables the generic packet duplication infrastructure
|
||||||
|
for Netfilter.
|
||||||
|
|
||||||
|
config NFT_DUP_NETDEV
|
||||||
|
tristate "Netfilter nf_tables netdev packet duplication support"
|
||||||
|
select NF_DUP_NETDEV
|
||||||
|
help
|
||||||
|
This option enables packet duplication for the "netdev" family.
|
||||||
|
|
||||||
|
config NFT_FWD_NETDEV
|
||||||
|
tristate "Netfilter nf_tables netdev packet forwarding support"
|
||||||
|
select NF_DUP_NETDEV
|
||||||
|
help
|
||||||
|
This option enables packet forwarding for the "netdev" family.
|
||||||
|
|
||||||
|
endif # NF_TABLES_NETDEV
|
||||||
|
|
||||||
endif # NF_TABLES
|
endif # NF_TABLES
|
||||||
|
|
||||||
config NETFILTER_XTABLES
|
config NETFILTER_XTABLES
|
||||||
|
|
|
@ -66,6 +66,9 @@ obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o
|
||||||
# SYNPROXY
|
# SYNPROXY
|
||||||
obj-$(CONFIG_NETFILTER_SYNPROXY) += nf_synproxy_core.o
|
obj-$(CONFIG_NETFILTER_SYNPROXY) += nf_synproxy_core.o
|
||||||
|
|
||||||
|
# generic packet duplication from netdev family
|
||||||
|
obj-$(CONFIG_NF_DUP_NETDEV) += nf_dup_netdev.o
|
||||||
|
|
||||||
# nf_tables
|
# nf_tables
|
||||||
nf_tables-objs += nf_tables_core.o nf_tables_api.o nf_tables_trace.o
|
nf_tables-objs += nf_tables_core.o nf_tables_api.o nf_tables_trace.o
|
||||||
nf_tables-objs += nft_immediate.o nft_cmp.o nft_lookup.o nft_dynset.o
|
nf_tables-objs += nft_immediate.o nft_cmp.o nft_lookup.o nft_dynset.o
|
||||||
|
@ -90,6 +93,10 @@ obj-$(CONFIG_NFT_LOG) += nft_log.o
|
||||||
obj-$(CONFIG_NFT_MASQ) += nft_masq.o
|
obj-$(CONFIG_NFT_MASQ) += nft_masq.o
|
||||||
obj-$(CONFIG_NFT_REDIR) += nft_redir.o
|
obj-$(CONFIG_NFT_REDIR) += nft_redir.o
|
||||||
|
|
||||||
|
# nf_tables netdev
|
||||||
|
obj-$(CONFIG_NFT_DUP_NETDEV) += nft_dup_netdev.o
|
||||||
|
obj-$(CONFIG_NFT_FWD_NETDEV) += nft_fwd_netdev.o
|
||||||
|
|
||||||
# generic X tables
|
# generic X tables
|
||||||
obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
|
obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
|
||||||
|
|
||||||
|
|
|
@ -825,20 +825,17 @@ find_free_id(struct ip_set_net *inst, const char *name, ip_set_id_t *index,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int ip_set_none(struct net *net, struct sock *ctnl, struct sk_buff *skb,
|
||||||
ip_set_none(struct sock *ctnl, struct sk_buff *skb,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const attr[])
|
||||||
const struct nlattr * const attr[])
|
|
||||||
{
|
{
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int ip_set_create(struct net *net, struct sock *ctnl,
|
||||||
ip_set_create(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const attr[])
|
||||||
const struct nlattr * const attr[])
|
|
||||||
{
|
{
|
||||||
struct net *net = sock_net(ctnl);
|
|
||||||
struct ip_set_net *inst = ip_set_pernet(net);
|
struct ip_set_net *inst = ip_set_pernet(net);
|
||||||
struct ip_set *set, *clash = NULL;
|
struct ip_set *set, *clash = NULL;
|
||||||
ip_set_id_t index = IPSET_INVALID_ID;
|
ip_set_id_t index = IPSET_INVALID_ID;
|
||||||
|
@ -976,12 +973,11 @@ ip_set_destroy_set(struct ip_set *set)
|
||||||
kfree(set);
|
kfree(set);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int ip_set_destroy(struct net *net, struct sock *ctnl,
|
||||||
ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const attr[])
|
||||||
const struct nlattr * const attr[])
|
|
||||||
{
|
{
|
||||||
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
|
struct ip_set_net *inst = ip_set_pernet(net);
|
||||||
struct ip_set *s;
|
struct ip_set *s;
|
||||||
ip_set_id_t i;
|
ip_set_id_t i;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -1052,12 +1048,11 @@ ip_set_flush_set(struct ip_set *set)
|
||||||
spin_unlock_bh(&set->lock);
|
spin_unlock_bh(&set->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int ip_set_flush(struct net *net, struct sock *ctnl, struct sk_buff *skb,
|
||||||
ip_set_flush(struct sock *ctnl, struct sk_buff *skb,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const attr[])
|
||||||
const struct nlattr * const attr[])
|
|
||||||
{
|
{
|
||||||
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
|
struct ip_set_net *inst = ip_set_pernet(net);
|
||||||
struct ip_set *s;
|
struct ip_set *s;
|
||||||
ip_set_id_t i;
|
ip_set_id_t i;
|
||||||
|
|
||||||
|
@ -1092,12 +1087,11 @@ ip_set_setname2_policy[IPSET_ATTR_CMD_MAX + 1] = {
|
||||||
.len = IPSET_MAXNAMELEN - 1 },
|
.len = IPSET_MAXNAMELEN - 1 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int ip_set_rename(struct net *net, struct sock *ctnl,
|
||||||
ip_set_rename(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const attr[])
|
||||||
const struct nlattr * const attr[])
|
|
||||||
{
|
{
|
||||||
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
|
struct ip_set_net *inst = ip_set_pernet(net);
|
||||||
struct ip_set *set, *s;
|
struct ip_set *set, *s;
|
||||||
const char *name2;
|
const char *name2;
|
||||||
ip_set_id_t i;
|
ip_set_id_t i;
|
||||||
|
@ -1142,12 +1136,11 @@ out:
|
||||||
* so the ip_set_list always contains valid pointers to the sets.
|
* so the ip_set_list always contains valid pointers to the sets.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
static int ip_set_swap(struct net *net, struct sock *ctnl, struct sk_buff *skb,
|
||||||
ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const attr[])
|
||||||
const struct nlattr * const attr[])
|
|
||||||
{
|
{
|
||||||
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
|
struct ip_set_net *inst = ip_set_pernet(net);
|
||||||
struct ip_set *from, *to;
|
struct ip_set *from, *to;
|
||||||
ip_set_id_t from_id, to_id;
|
ip_set_id_t from_id, to_id;
|
||||||
char from_name[IPSET_MAXNAMELEN];
|
char from_name[IPSET_MAXNAMELEN];
|
||||||
|
@ -1413,10 +1406,9 @@ out:
|
||||||
return ret < 0 ? ret : skb->len;
|
return ret < 0 ? ret : skb->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int ip_set_dump(struct net *net, struct sock *ctnl, struct sk_buff *skb,
|
||||||
ip_set_dump(struct sock *ctnl, struct sk_buff *skb,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const attr[])
|
||||||
const struct nlattr * const attr[])
|
|
||||||
{
|
{
|
||||||
if (unlikely(protocol_failed(attr)))
|
if (unlikely(protocol_failed(attr)))
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
@ -1500,12 +1492,11 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int ip_set_uadd(struct net *net, struct sock *ctnl, struct sk_buff *skb,
|
||||||
ip_set_uadd(struct sock *ctnl, struct sk_buff *skb,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const attr[])
|
||||||
const struct nlattr * const attr[])
|
|
||||||
{
|
{
|
||||||
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
|
struct ip_set_net *inst = ip_set_pernet(net);
|
||||||
struct ip_set *set;
|
struct ip_set *set;
|
||||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX + 1] = {};
|
struct nlattr *tb[IPSET_ATTR_ADT_MAX + 1] = {};
|
||||||
const struct nlattr *nla;
|
const struct nlattr *nla;
|
||||||
|
@ -1555,12 +1546,11 @@ ip_set_uadd(struct sock *ctnl, struct sk_buff *skb,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int ip_set_udel(struct net *net, struct sock *ctnl, struct sk_buff *skb,
|
||||||
ip_set_udel(struct sock *ctnl, struct sk_buff *skb,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const attr[])
|
||||||
const struct nlattr * const attr[])
|
|
||||||
{
|
{
|
||||||
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
|
struct ip_set_net *inst = ip_set_pernet(net);
|
||||||
struct ip_set *set;
|
struct ip_set *set;
|
||||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX + 1] = {};
|
struct nlattr *tb[IPSET_ATTR_ADT_MAX + 1] = {};
|
||||||
const struct nlattr *nla;
|
const struct nlattr *nla;
|
||||||
|
@ -1610,12 +1600,11 @@ ip_set_udel(struct sock *ctnl, struct sk_buff *skb,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int ip_set_utest(struct net *net, struct sock *ctnl, struct sk_buff *skb,
|
||||||
ip_set_utest(struct sock *ctnl, struct sk_buff *skb,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const attr[])
|
||||||
const struct nlattr * const attr[])
|
|
||||||
{
|
{
|
||||||
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
|
struct ip_set_net *inst = ip_set_pernet(net);
|
||||||
struct ip_set *set;
|
struct ip_set *set;
|
||||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX + 1] = {};
|
struct nlattr *tb[IPSET_ATTR_ADT_MAX + 1] = {};
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -1646,12 +1635,11 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb,
|
||||||
|
|
||||||
/* Get headed data of a set */
|
/* Get headed data of a set */
|
||||||
|
|
||||||
static int
|
static int ip_set_header(struct net *net, struct sock *ctnl,
|
||||||
ip_set_header(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const attr[])
|
||||||
const struct nlattr * const attr[])
|
|
||||||
{
|
{
|
||||||
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
|
struct ip_set_net *inst = ip_set_pernet(net);
|
||||||
const struct ip_set *set;
|
const struct ip_set *set;
|
||||||
struct sk_buff *skb2;
|
struct sk_buff *skb2;
|
||||||
struct nlmsghdr *nlh2;
|
struct nlmsghdr *nlh2;
|
||||||
|
@ -1703,10 +1691,9 @@ static const struct nla_policy ip_set_type_policy[IPSET_ATTR_CMD_MAX + 1] = {
|
||||||
[IPSET_ATTR_FAMILY] = { .type = NLA_U8 },
|
[IPSET_ATTR_FAMILY] = { .type = NLA_U8 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int ip_set_type(struct net *net, struct sock *ctnl, struct sk_buff *skb,
|
||||||
ip_set_type(struct sock *ctnl, struct sk_buff *skb,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const attr[])
|
||||||
const struct nlattr * const attr[])
|
|
||||||
{
|
{
|
||||||
struct sk_buff *skb2;
|
struct sk_buff *skb2;
|
||||||
struct nlmsghdr *nlh2;
|
struct nlmsghdr *nlh2;
|
||||||
|
@ -1762,10 +1749,9 @@ ip_set_protocol_policy[IPSET_ATTR_CMD_MAX + 1] = {
|
||||||
[IPSET_ATTR_PROTOCOL] = { .type = NLA_U8 },
|
[IPSET_ATTR_PROTOCOL] = { .type = NLA_U8 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int ip_set_protocol(struct net *net, struct sock *ctnl,
|
||||||
ip_set_protocol(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const attr[])
|
||||||
const struct nlattr * const attr[])
|
|
||||||
{
|
{
|
||||||
struct sk_buff *skb2;
|
struct sk_buff *skb2;
|
||||||
struct nlmsghdr *nlh2;
|
struct nlmsghdr *nlh2;
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
* published by the Free Software Foundation.
|
* published by the Free Software Foundation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/netfilter.h>
|
#include <linux/netfilter.h>
|
||||||
|
@ -505,11 +507,11 @@ skip_nl_seq:
|
||||||
different IP address. Simply don't record it for
|
different IP address. Simply don't record it for
|
||||||
NAT. */
|
NAT. */
|
||||||
if (cmd.l3num == PF_INET) {
|
if (cmd.l3num == PF_INET) {
|
||||||
pr_debug("conntrack_ftp: NOT RECORDING: %pI4 != %pI4\n",
|
pr_debug("NOT RECORDING: %pI4 != %pI4\n",
|
||||||
&cmd.u3.ip,
|
&cmd.u3.ip,
|
||||||
&ct->tuplehash[dir].tuple.src.u3.ip);
|
&ct->tuplehash[dir].tuple.src.u3.ip);
|
||||||
} else {
|
} else {
|
||||||
pr_debug("conntrack_ftp: NOT RECORDING: %pI6 != %pI6\n",
|
pr_debug("NOT RECORDING: %pI6 != %pI6\n",
|
||||||
cmd.u3.ip6,
|
cmd.u3.ip6,
|
||||||
ct->tuplehash[dir].tuple.src.u3.ip6);
|
ct->tuplehash[dir].tuple.src.u3.ip6);
|
||||||
}
|
}
|
||||||
|
@ -586,8 +588,7 @@ static void nf_conntrack_ftp_fini(void)
|
||||||
if (ftp[i][j].me == NULL)
|
if (ftp[i][j].me == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
pr_debug("nf_ct_ftp: unregistering helper for pf: %d "
|
pr_debug("unregistering helper for pf: %d port: %d\n",
|
||||||
"port: %d\n",
|
|
||||||
ftp[i][j].tuple.src.l3num, ports[i]);
|
ftp[i][j].tuple.src.l3num, ports[i]);
|
||||||
nf_conntrack_helper_unregister(&ftp[i][j]);
|
nf_conntrack_helper_unregister(&ftp[i][j]);
|
||||||
}
|
}
|
||||||
|
@ -625,14 +626,12 @@ static int __init nf_conntrack_ftp_init(void)
|
||||||
else
|
else
|
||||||
sprintf(ftp[i][j].name, "ftp-%d", ports[i]);
|
sprintf(ftp[i][j].name, "ftp-%d", ports[i]);
|
||||||
|
|
||||||
pr_debug("nf_ct_ftp: registering helper for pf: %d "
|
pr_debug("registering helper for pf: %d port: %d\n",
|
||||||
"port: %d\n",
|
|
||||||
ftp[i][j].tuple.src.l3num, ports[i]);
|
ftp[i][j].tuple.src.l3num, ports[i]);
|
||||||
ret = nf_conntrack_helper_register(&ftp[i][j]);
|
ret = nf_conntrack_helper_register(&ftp[i][j]);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "nf_ct_ftp: failed to register"
|
pr_err("failed to register helper for pf: %d port: %d\n",
|
||||||
" helper for pf: %d port: %d\n",
|
ftp[i][j].tuple.src.l3num, ports[i]);
|
||||||
ftp[i][j].tuple.src.l3num, ports[i]);
|
|
||||||
nf_conntrack_ftp_fini();
|
nf_conntrack_ftp_fini();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
* 2 of the License, or (at your option) any later version.
|
* 2 of the License, or (at your option) any later version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
|
@ -237,7 +239,7 @@ static int __init nf_conntrack_irc_init(void)
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
||||||
if (max_dcc_channels < 1) {
|
if (max_dcc_channels < 1) {
|
||||||
printk(KERN_ERR "nf_ct_irc: max_dcc_channels must not be zero\n");
|
pr_err("max_dcc_channels must not be zero\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,8 +269,7 @@ static int __init nf_conntrack_irc_init(void)
|
||||||
|
|
||||||
ret = nf_conntrack_helper_register(&irc[i]);
|
ret = nf_conntrack_helper_register(&irc[i]);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "nf_ct_irc: failed to register helper "
|
pr_err("failed to register helper for pf: %u port: %u\n",
|
||||||
"for pf: %u port: %u\n",
|
|
||||||
irc[i].tuple.src.l3num, ports[i]);
|
irc[i].tuple.src.l3num, ports[i]);
|
||||||
nf_conntrack_irc_fini();
|
nf_conntrack_irc_fini();
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -1113,12 +1113,11 @@ static int ctnetlink_flush_conntrack(struct net *net,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl,
|
||||||
ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const cda[])
|
const struct nlattr * const cda[])
|
||||||
{
|
{
|
||||||
struct net *net = sock_net(ctnl);
|
|
||||||
struct nf_conntrack_tuple_hash *h;
|
struct nf_conntrack_tuple_hash *h;
|
||||||
struct nf_conntrack_tuple tuple;
|
struct nf_conntrack_tuple tuple;
|
||||||
struct nf_conn *ct;
|
struct nf_conn *ct;
|
||||||
|
@ -1168,12 +1167,11 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int ctnetlink_get_conntrack(struct net *net, struct sock *ctnl,
|
||||||
ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const cda[])
|
const struct nlattr * const cda[])
|
||||||
{
|
{
|
||||||
struct net *net = sock_net(ctnl);
|
|
||||||
struct nf_conntrack_tuple_hash *h;
|
struct nf_conntrack_tuple_hash *h;
|
||||||
struct nf_conntrack_tuple tuple;
|
struct nf_conntrack_tuple tuple;
|
||||||
struct nf_conn *ct;
|
struct nf_conn *ct;
|
||||||
|
@ -1330,10 +1328,10 @@ ctnetlink_dump_dying(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
return ctnetlink_dump_list(skb, cb, true);
|
return ctnetlink_dump_list(skb, cb, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int ctnetlink_get_ct_dying(struct net *net, struct sock *ctnl,
|
||||||
ctnetlink_get_ct_dying(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const cda[])
|
const struct nlattr * const cda[])
|
||||||
{
|
{
|
||||||
if (nlh->nlmsg_flags & NLM_F_DUMP) {
|
if (nlh->nlmsg_flags & NLM_F_DUMP) {
|
||||||
struct netlink_dump_control c = {
|
struct netlink_dump_control c = {
|
||||||
|
@ -1352,10 +1350,10 @@ ctnetlink_dump_unconfirmed(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
return ctnetlink_dump_list(skb, cb, false);
|
return ctnetlink_dump_list(skb, cb, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int ctnetlink_get_ct_unconfirmed(struct net *net, struct sock *ctnl,
|
||||||
ctnetlink_get_ct_unconfirmed(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const cda[])
|
const struct nlattr * const cda[])
|
||||||
{
|
{
|
||||||
if (nlh->nlmsg_flags & NLM_F_DUMP) {
|
if (nlh->nlmsg_flags & NLM_F_DUMP) {
|
||||||
struct netlink_dump_control c = {
|
struct netlink_dump_control c = {
|
||||||
|
@ -1865,12 +1863,11 @@ err1:
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
|
||||||
ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const cda[])
|
const struct nlattr * const cda[])
|
||||||
{
|
{
|
||||||
struct net *net = sock_net(ctnl);
|
|
||||||
struct nf_conntrack_tuple otuple, rtuple;
|
struct nf_conntrack_tuple otuple, rtuple;
|
||||||
struct nf_conntrack_tuple_hash *h = NULL;
|
struct nf_conntrack_tuple_hash *h = NULL;
|
||||||
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
||||||
|
@ -2034,10 +2031,10 @@ ctnetlink_ct_stat_cpu_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
return skb->len;
|
return skb->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int ctnetlink_stat_ct_cpu(struct net *net, struct sock *ctnl,
|
||||||
ctnetlink_stat_ct_cpu(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const cda[])
|
const struct nlattr * const cda[])
|
||||||
{
|
{
|
||||||
if (nlh->nlmsg_flags & NLM_F_DUMP) {
|
if (nlh->nlmsg_flags & NLM_F_DUMP) {
|
||||||
struct netlink_dump_control c = {
|
struct netlink_dump_control c = {
|
||||||
|
@ -2080,10 +2077,9 @@ nlmsg_failure:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int ctnetlink_stat_ct(struct net *net, struct sock *ctnl,
|
||||||
ctnetlink_stat_ct(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const cda[])
|
||||||
const struct nlattr * const cda[])
|
|
||||||
{
|
{
|
||||||
struct sk_buff *skb2;
|
struct sk_buff *skb2;
|
||||||
int err;
|
int err;
|
||||||
|
@ -2729,12 +2725,12 @@ out:
|
||||||
return skb->len;
|
return skb->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ctnetlink_dump_exp_ct(struct sock *ctnl, struct sk_buff *skb,
|
static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl,
|
||||||
|
struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const cda[])
|
const struct nlattr * const cda[])
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct net *net = sock_net(ctnl);
|
|
||||||
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
||||||
u_int8_t u3 = nfmsg->nfgen_family;
|
u_int8_t u3 = nfmsg->nfgen_family;
|
||||||
struct nf_conntrack_tuple tuple;
|
struct nf_conntrack_tuple tuple;
|
||||||
|
@ -2768,12 +2764,10 @@ static int ctnetlink_dump_exp_ct(struct sock *ctnl, struct sk_buff *skb,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int ctnetlink_get_expect(struct net *net, struct sock *ctnl,
|
||||||
ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const cda[])
|
||||||
const struct nlattr * const cda[])
|
|
||||||
{
|
{
|
||||||
struct net *net = sock_net(ctnl);
|
|
||||||
struct nf_conntrack_tuple tuple;
|
struct nf_conntrack_tuple tuple;
|
||||||
struct nf_conntrack_expect *exp;
|
struct nf_conntrack_expect *exp;
|
||||||
struct sk_buff *skb2;
|
struct sk_buff *skb2;
|
||||||
|
@ -2784,7 +2778,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
|
||||||
|
|
||||||
if (nlh->nlmsg_flags & NLM_F_DUMP) {
|
if (nlh->nlmsg_flags & NLM_F_DUMP) {
|
||||||
if (cda[CTA_EXPECT_MASTER])
|
if (cda[CTA_EXPECT_MASTER])
|
||||||
return ctnetlink_dump_exp_ct(ctnl, skb, nlh, cda);
|
return ctnetlink_dump_exp_ct(net, ctnl, skb, nlh, cda);
|
||||||
else {
|
else {
|
||||||
struct netlink_dump_control c = {
|
struct netlink_dump_control c = {
|
||||||
.dump = ctnetlink_exp_dump_table,
|
.dump = ctnetlink_exp_dump_table,
|
||||||
|
@ -2850,12 +2844,10 @@ out:
|
||||||
return err == -EAGAIN ? -ENOBUFS : err;
|
return err == -EAGAIN ? -ENOBUFS : err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
|
||||||
ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const cda[])
|
||||||
const struct nlattr * const cda[])
|
|
||||||
{
|
{
|
||||||
struct net *net = sock_net(ctnl);
|
|
||||||
struct nf_conntrack_expect *exp;
|
struct nf_conntrack_expect *exp;
|
||||||
struct nf_conntrack_tuple tuple;
|
struct nf_conntrack_tuple tuple;
|
||||||
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
||||||
|
@ -3136,12 +3128,10 @@ err_ct:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int ctnetlink_new_expect(struct net *net, struct sock *ctnl,
|
||||||
ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const cda[])
|
||||||
const struct nlattr * const cda[])
|
|
||||||
{
|
{
|
||||||
struct net *net = sock_net(ctnl);
|
|
||||||
struct nf_conntrack_tuple tuple;
|
struct nf_conntrack_tuple tuple;
|
||||||
struct nf_conntrack_expect *exp;
|
struct nf_conntrack_expect *exp;
|
||||||
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
||||||
|
@ -3242,10 +3232,10 @@ ctnetlink_exp_stat_cpu_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
return skb->len;
|
return skb->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int ctnetlink_stat_exp_cpu(struct net *net, struct sock *ctnl,
|
||||||
ctnetlink_stat_exp_cpu(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const cda[])
|
const struct nlattr * const cda[])
|
||||||
{
|
{
|
||||||
if (nlh->nlmsg_flags & NLM_F_DUMP) {
|
if (nlh->nlmsg_flags & NLM_F_DUMP) {
|
||||||
struct netlink_dump_control c = {
|
struct netlink_dump_control c = {
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
* published by the Free Software Foundation.
|
* published by the Free Software Foundation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/netfilter.h>
|
#include <linux/netfilter.h>
|
||||||
|
@ -120,14 +122,14 @@ static int help(struct sk_buff *skb,
|
||||||
ct_sane_info->state = SANE_STATE_NORMAL;
|
ct_sane_info->state = SANE_STATE_NORMAL;
|
||||||
|
|
||||||
if (datalen < sizeof(struct sane_reply_net_start)) {
|
if (datalen < sizeof(struct sane_reply_net_start)) {
|
||||||
pr_debug("nf_ct_sane: NET_START reply too short\n");
|
pr_debug("NET_START reply too short\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
reply = sb_ptr;
|
reply = sb_ptr;
|
||||||
if (reply->status != htonl(SANE_STATUS_SUCCESS)) {
|
if (reply->status != htonl(SANE_STATUS_SUCCESS)) {
|
||||||
/* saned refused the command */
|
/* saned refused the command */
|
||||||
pr_debug("nf_ct_sane: unsuccessful SANE_STATUS = %u\n",
|
pr_debug("unsuccessful SANE_STATUS = %u\n",
|
||||||
ntohl(reply->status));
|
ntohl(reply->status));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -148,7 +150,7 @@ static int help(struct sk_buff *skb,
|
||||||
&tuple->src.u3, &tuple->dst.u3,
|
&tuple->src.u3, &tuple->dst.u3,
|
||||||
IPPROTO_TCP, NULL, &reply->port);
|
IPPROTO_TCP, NULL, &reply->port);
|
||||||
|
|
||||||
pr_debug("nf_ct_sane: expect: ");
|
pr_debug("expect: ");
|
||||||
nf_ct_dump_tuple(&exp->tuple);
|
nf_ct_dump_tuple(&exp->tuple);
|
||||||
|
|
||||||
/* Can't expect this? Best to drop packet now. */
|
/* Can't expect this? Best to drop packet now. */
|
||||||
|
@ -178,8 +180,7 @@ static void nf_conntrack_sane_fini(void)
|
||||||
|
|
||||||
for (i = 0; i < ports_c; i++) {
|
for (i = 0; i < ports_c; i++) {
|
||||||
for (j = 0; j < 2; j++) {
|
for (j = 0; j < 2; j++) {
|
||||||
pr_debug("nf_ct_sane: unregistering helper for pf: %d "
|
pr_debug("unregistering helper for pf: %d port: %d\n",
|
||||||
"port: %d\n",
|
|
||||||
sane[i][j].tuple.src.l3num, ports[i]);
|
sane[i][j].tuple.src.l3num, ports[i]);
|
||||||
nf_conntrack_helper_unregister(&sane[i][j]);
|
nf_conntrack_helper_unregister(&sane[i][j]);
|
||||||
}
|
}
|
||||||
|
@ -216,14 +217,12 @@ static int __init nf_conntrack_sane_init(void)
|
||||||
else
|
else
|
||||||
sprintf(sane[i][j].name, "sane-%d", ports[i]);
|
sprintf(sane[i][j].name, "sane-%d", ports[i]);
|
||||||
|
|
||||||
pr_debug("nf_ct_sane: registering helper for pf: %d "
|
pr_debug("registering helper for pf: %d port: %d\n",
|
||||||
"port: %d\n",
|
|
||||||
sane[i][j].tuple.src.l3num, ports[i]);
|
sane[i][j].tuple.src.l3num, ports[i]);
|
||||||
ret = nf_conntrack_helper_register(&sane[i][j]);
|
ret = nf_conntrack_helper_register(&sane[i][j]);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "nf_ct_sane: failed to "
|
pr_err("failed to register helper for pf: %d port: %d\n",
|
||||||
"register helper for pf: %d port: %d\n",
|
sane[i][j].tuple.src.l3num, ports[i]);
|
||||||
sane[i][j].tuple.src.l3num, ports[i]);
|
|
||||||
nf_conntrack_sane_fini();
|
nf_conntrack_sane_fini();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
* published by the Free Software Foundation.
|
* published by the Free Software Foundation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
|
@ -1665,8 +1667,7 @@ static int __init nf_conntrack_sip_init(void)
|
||||||
|
|
||||||
ret = nf_conntrack_helper_register(&sip[i][j]);
|
ret = nf_conntrack_helper_register(&sip[i][j]);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "nf_ct_sip: failed to register"
|
pr_err("failed to register helper for pf: %u port: %u\n",
|
||||||
" helper for pf: %u port: %u\n",
|
|
||||||
sip[i][j].tuple.src.l3num, ports[i]);
|
sip[i][j].tuple.src.l3num, ports[i]);
|
||||||
nf_conntrack_sip_fini();
|
nf_conntrack_sip_fini();
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
* published by the Free Software Foundation.
|
* published by the Free Software Foundation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/in.h>
|
#include <linux/in.h>
|
||||||
|
@ -138,9 +140,8 @@ static int __init nf_conntrack_tftp_init(void)
|
||||||
|
|
||||||
ret = nf_conntrack_helper_register(&tftp[i][j]);
|
ret = nf_conntrack_helper_register(&tftp[i][j]);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "nf_ct_tftp: failed to register"
|
pr_err("failed to register helper for pf: %u port: %u\n",
|
||||||
" helper for pf: %u port: %u\n",
|
tftp[i][j].tuple.src.l3num, ports[i]);
|
||||||
tftp[i][j].tuple.src.l3num, ports[i]);
|
|
||||||
nf_conntrack_tftp_fini();
|
nf_conntrack_tftp_fini();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
40
net/netfilter/nf_dup_netdev.c
Normal file
40
net/netfilter/nf_dup_netdev.c
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015 Pablo Neira Ayuso <pablo@netfilter.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 as published by
|
||||||
|
* the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/netlink.h>
|
||||||
|
#include <linux/netfilter.h>
|
||||||
|
#include <linux/netfilter/nf_tables.h>
|
||||||
|
#include <net/netfilter/nf_tables.h>
|
||||||
|
|
||||||
|
void nf_dup_netdev_egress(const struct nft_pktinfo *pkt, int oif)
|
||||||
|
{
|
||||||
|
struct net_device *dev;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
dev = dev_get_by_index_rcu(pkt->net, oif);
|
||||||
|
if (dev == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
skb = skb_clone(pkt->skb, GFP_ATOMIC);
|
||||||
|
if (skb == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (skb_mac_header_was_set(skb))
|
||||||
|
skb_push(skb, skb->mac_len);
|
||||||
|
|
||||||
|
skb->dev = dev;
|
||||||
|
skb_sender_cpu_clear(skb);
|
||||||
|
dev_queue_xmit(skb);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(nf_dup_netdev_egress);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
|
|
@ -41,6 +41,8 @@ int nft_register_afinfo(struct net *net, struct nft_af_info *afi)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nft_register_afinfo);
|
EXPORT_SYMBOL_GPL(nft_register_afinfo);
|
||||||
|
|
||||||
|
static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nft_unregister_afinfo - unregister nf_tables address family info
|
* nft_unregister_afinfo - unregister nf_tables address family info
|
||||||
*
|
*
|
||||||
|
@ -48,9 +50,10 @@ EXPORT_SYMBOL_GPL(nft_register_afinfo);
|
||||||
*
|
*
|
||||||
* Unregister the address family for use with nf_tables.
|
* Unregister the address family for use with nf_tables.
|
||||||
*/
|
*/
|
||||||
void nft_unregister_afinfo(struct nft_af_info *afi)
|
void nft_unregister_afinfo(struct net *net, struct nft_af_info *afi)
|
||||||
{
|
{
|
||||||
nfnl_lock(NFNL_SUBSYS_NFTABLES);
|
nfnl_lock(NFNL_SUBSYS_NFTABLES);
|
||||||
|
__nft_release_afinfo(net, afi);
|
||||||
list_del_rcu(&afi->list);
|
list_del_rcu(&afi->list);
|
||||||
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
|
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
|
||||||
}
|
}
|
||||||
|
@ -128,8 +131,8 @@ static void nft_trans_destroy(struct nft_trans *trans)
|
||||||
kfree(trans);
|
kfree(trans);
|
||||||
}
|
}
|
||||||
|
|
||||||
int nft_register_basechain(struct nft_base_chain *basechain,
|
static int nft_register_basechain(struct nft_base_chain *basechain,
|
||||||
unsigned int hook_nops)
|
unsigned int hook_nops)
|
||||||
{
|
{
|
||||||
struct net *net = read_pnet(&basechain->pnet);
|
struct net *net = read_pnet(&basechain->pnet);
|
||||||
|
|
||||||
|
@ -138,10 +141,9 @@ int nft_register_basechain(struct nft_base_chain *basechain,
|
||||||
|
|
||||||
return nf_register_net_hooks(net, basechain->ops, hook_nops);
|
return nf_register_net_hooks(net, basechain->ops, hook_nops);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nft_register_basechain);
|
|
||||||
|
|
||||||
void nft_unregister_basechain(struct nft_base_chain *basechain,
|
static void nft_unregister_basechain(struct nft_base_chain *basechain,
|
||||||
unsigned int hook_nops)
|
unsigned int hook_nops)
|
||||||
{
|
{
|
||||||
struct net *net = read_pnet(&basechain->pnet);
|
struct net *net = read_pnet(&basechain->pnet);
|
||||||
|
|
||||||
|
@ -150,7 +152,6 @@ void nft_unregister_basechain(struct nft_base_chain *basechain,
|
||||||
|
|
||||||
nf_unregister_net_hooks(net, basechain->ops, hook_nops);
|
nf_unregister_net_hooks(net, basechain->ops, hook_nops);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nft_unregister_basechain);
|
|
||||||
|
|
||||||
static int nf_tables_register_hooks(const struct nft_table *table,
|
static int nf_tables_register_hooks(const struct nft_table *table,
|
||||||
struct nft_chain *chain,
|
struct nft_chain *chain,
|
||||||
|
@ -542,15 +543,14 @@ done:
|
||||||
return skb->len;
|
return skb->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nf_tables_gettable(struct sock *nlsk, struct sk_buff *skb,
|
static int nf_tables_gettable(struct net *net, struct sock *nlsk,
|
||||||
const struct nlmsghdr *nlh,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const nla[])
|
const struct nlattr * const nla[])
|
||||||
{
|
{
|
||||||
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
||||||
const struct nft_af_info *afi;
|
const struct nft_af_info *afi;
|
||||||
const struct nft_table *table;
|
const struct nft_table *table;
|
||||||
struct sk_buff *skb2;
|
struct sk_buff *skb2;
|
||||||
struct net *net = sock_net(skb->sk);
|
|
||||||
int family = nfmsg->nfgen_family;
|
int family = nfmsg->nfgen_family;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -831,8 +831,6 @@ static int nf_tables_deltable(struct net *net, struct sock *nlsk,
|
||||||
table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
|
table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
|
||||||
if (IS_ERR(table))
|
if (IS_ERR(table))
|
||||||
return PTR_ERR(table);
|
return PTR_ERR(table);
|
||||||
if (table->flags & NFT_TABLE_INACTIVE)
|
|
||||||
return -ENOENT;
|
|
||||||
|
|
||||||
ctx.afi = afi;
|
ctx.afi = afi;
|
||||||
ctx.table = table;
|
ctx.table = table;
|
||||||
|
@ -1098,8 +1096,8 @@ done:
|
||||||
return skb->len;
|
return skb->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nf_tables_getchain(struct sock *nlsk, struct sk_buff *skb,
|
static int nf_tables_getchain(struct net *net, struct sock *nlsk,
|
||||||
const struct nlmsghdr *nlh,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const nla[])
|
const struct nlattr * const nla[])
|
||||||
{
|
{
|
||||||
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
||||||
|
@ -1107,7 +1105,6 @@ static int nf_tables_getchain(struct sock *nlsk, struct sk_buff *skb,
|
||||||
const struct nft_table *table;
|
const struct nft_table *table;
|
||||||
const struct nft_chain *chain;
|
const struct nft_chain *chain;
|
||||||
struct sk_buff *skb2;
|
struct sk_buff *skb2;
|
||||||
struct net *net = sock_net(skb->sk);
|
|
||||||
int family = nfmsg->nfgen_family;
|
int family = nfmsg->nfgen_family;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -1492,14 +1489,10 @@ static int nf_tables_delchain(struct net *net, struct sock *nlsk,
|
||||||
table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
|
table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
|
||||||
if (IS_ERR(table))
|
if (IS_ERR(table))
|
||||||
return PTR_ERR(table);
|
return PTR_ERR(table);
|
||||||
if (table->flags & NFT_TABLE_INACTIVE)
|
|
||||||
return -ENOENT;
|
|
||||||
|
|
||||||
chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
|
chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
|
||||||
if (IS_ERR(chain))
|
if (IS_ERR(chain))
|
||||||
return PTR_ERR(chain);
|
return PTR_ERR(chain);
|
||||||
if (chain->flags & NFT_CHAIN_INACTIVE)
|
|
||||||
return -ENOENT;
|
|
||||||
if (chain->use > 0)
|
if (chain->use > 0)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
|
@ -1928,8 +1921,8 @@ done:
|
||||||
return skb->len;
|
return skb->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nf_tables_getrule(struct sock *nlsk, struct sk_buff *skb,
|
static int nf_tables_getrule(struct net *net, struct sock *nlsk,
|
||||||
const struct nlmsghdr *nlh,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const nla[])
|
const struct nlattr * const nla[])
|
||||||
{
|
{
|
||||||
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
||||||
|
@ -1938,7 +1931,6 @@ static int nf_tables_getrule(struct sock *nlsk, struct sk_buff *skb,
|
||||||
const struct nft_chain *chain;
|
const struct nft_chain *chain;
|
||||||
const struct nft_rule *rule;
|
const struct nft_rule *rule;
|
||||||
struct sk_buff *skb2;
|
struct sk_buff *skb2;
|
||||||
struct net *net = sock_net(skb->sk);
|
|
||||||
int family = nfmsg->nfgen_family;
|
int family = nfmsg->nfgen_family;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -2191,8 +2183,6 @@ static int nf_tables_delrule(struct net *net, struct sock *nlsk,
|
||||||
table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
|
table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
|
||||||
if (IS_ERR(table))
|
if (IS_ERR(table))
|
||||||
return PTR_ERR(table);
|
return PTR_ERR(table);
|
||||||
if (table->flags & NFT_TABLE_INACTIVE)
|
|
||||||
return -ENOENT;
|
|
||||||
|
|
||||||
if (nla[NFTA_RULE_CHAIN]) {
|
if (nla[NFTA_RULE_CHAIN]) {
|
||||||
chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
|
chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
|
||||||
|
@ -2333,6 +2323,8 @@ static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
|
||||||
[NFTA_SET_ID] = { .type = NLA_U32 },
|
[NFTA_SET_ID] = { .type = NLA_U32 },
|
||||||
[NFTA_SET_TIMEOUT] = { .type = NLA_U64 },
|
[NFTA_SET_TIMEOUT] = { .type = NLA_U64 },
|
||||||
[NFTA_SET_GC_INTERVAL] = { .type = NLA_U32 },
|
[NFTA_SET_GC_INTERVAL] = { .type = NLA_U32 },
|
||||||
|
[NFTA_SET_USERDATA] = { .type = NLA_BINARY,
|
||||||
|
.len = NFT_USERDATA_MAXLEN },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
|
static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
|
||||||
|
@ -2361,8 +2353,6 @@ static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, struct net *net,
|
||||||
table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
|
table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
|
||||||
if (IS_ERR(table))
|
if (IS_ERR(table))
|
||||||
return PTR_ERR(table);
|
return PTR_ERR(table);
|
||||||
if (table->flags & NFT_TABLE_INACTIVE)
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nft_ctx_init(ctx, net, skb, nlh, afi, table, NULL, nla);
|
nft_ctx_init(ctx, net, skb, nlh, afi, table, NULL, nla);
|
||||||
|
@ -2494,6 +2484,9 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nla_put(skb, NFTA_SET_USERDATA, set->udlen, set->udata))
|
||||||
|
goto nla_put_failure;
|
||||||
|
|
||||||
desc = nla_nest_start(skb, NFTA_SET_DESC);
|
desc = nla_nest_start(skb, NFTA_SET_DESC);
|
||||||
if (desc == NULL)
|
if (desc == NULL)
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
@ -2613,11 +2606,10 @@ static int nf_tables_dump_sets_done(struct netlink_callback *cb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb,
|
static int nf_tables_getset(struct net *net, struct sock *nlsk,
|
||||||
const struct nlmsghdr *nlh,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const nla[])
|
const struct nlattr * const nla[])
|
||||||
{
|
{
|
||||||
struct net *net = sock_net(skb->sk);
|
|
||||||
const struct nft_set *set;
|
const struct nft_set *set;
|
||||||
struct nft_ctx ctx;
|
struct nft_ctx ctx;
|
||||||
struct sk_buff *skb2;
|
struct sk_buff *skb2;
|
||||||
|
@ -2704,6 +2696,8 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
|
||||||
u64 timeout;
|
u64 timeout;
|
||||||
u32 ktype, dtype, flags, policy, gc_int;
|
u32 ktype, dtype, flags, policy, gc_int;
|
||||||
struct nft_set_desc desc;
|
struct nft_set_desc desc;
|
||||||
|
unsigned char *udata;
|
||||||
|
u16 udlen;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (nla[NFTA_SET_TABLE] == NULL ||
|
if (nla[NFTA_SET_TABLE] == NULL ||
|
||||||
|
@ -2816,12 +2810,16 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
|
||||||
if (IS_ERR(ops))
|
if (IS_ERR(ops))
|
||||||
return PTR_ERR(ops);
|
return PTR_ERR(ops);
|
||||||
|
|
||||||
|
udlen = 0;
|
||||||
|
if (nla[NFTA_SET_USERDATA])
|
||||||
|
udlen = nla_len(nla[NFTA_SET_USERDATA]);
|
||||||
|
|
||||||
size = 0;
|
size = 0;
|
||||||
if (ops->privsize != NULL)
|
if (ops->privsize != NULL)
|
||||||
size = ops->privsize(nla);
|
size = ops->privsize(nla);
|
||||||
|
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
set = kzalloc(sizeof(*set) + size, GFP_KERNEL);
|
set = kzalloc(sizeof(*set) + size + udlen, GFP_KERNEL);
|
||||||
if (set == NULL)
|
if (set == NULL)
|
||||||
goto err1;
|
goto err1;
|
||||||
|
|
||||||
|
@ -2830,6 +2828,12 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto err2;
|
goto err2;
|
||||||
|
|
||||||
|
udata = NULL;
|
||||||
|
if (udlen) {
|
||||||
|
udata = set->data + size;
|
||||||
|
nla_memcpy(udata, nla[NFTA_SET_USERDATA], udlen);
|
||||||
|
}
|
||||||
|
|
||||||
INIT_LIST_HEAD(&set->bindings);
|
INIT_LIST_HEAD(&set->bindings);
|
||||||
write_pnet(&set->pnet, net);
|
write_pnet(&set->pnet, net);
|
||||||
set->ops = ops;
|
set->ops = ops;
|
||||||
|
@ -2840,6 +2844,8 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
|
||||||
set->flags = flags;
|
set->flags = flags;
|
||||||
set->size = desc.size;
|
set->size = desc.size;
|
||||||
set->policy = policy;
|
set->policy = policy;
|
||||||
|
set->udlen = udlen;
|
||||||
|
set->udata = udata;
|
||||||
set->timeout = timeout;
|
set->timeout = timeout;
|
||||||
set->gc_int = gc_int;
|
set->gc_int = gc_int;
|
||||||
|
|
||||||
|
@ -2897,8 +2903,6 @@ static int nf_tables_delset(struct net *net, struct sock *nlsk,
|
||||||
set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
|
set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
|
||||||
if (IS_ERR(set))
|
if (IS_ERR(set))
|
||||||
return PTR_ERR(set);
|
return PTR_ERR(set);
|
||||||
if (set->flags & NFT_SET_INACTIVE)
|
|
||||||
return -ENOENT;
|
|
||||||
if (!list_empty(&set->bindings))
|
if (!list_empty(&set->bindings))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
|
@ -3021,8 +3025,7 @@ static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX +
|
||||||
static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx, struct net *net,
|
static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx, struct net *net,
|
||||||
const struct sk_buff *skb,
|
const struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const nla[],
|
const struct nlattr * const nla[])
|
||||||
bool trans)
|
|
||||||
{
|
{
|
||||||
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
||||||
struct nft_af_info *afi;
|
struct nft_af_info *afi;
|
||||||
|
@ -3035,8 +3038,6 @@ static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx, struct net *net,
|
||||||
table = nf_tables_table_lookup(afi, nla[NFTA_SET_ELEM_LIST_TABLE]);
|
table = nf_tables_table_lookup(afi, nla[NFTA_SET_ELEM_LIST_TABLE]);
|
||||||
if (IS_ERR(table))
|
if (IS_ERR(table))
|
||||||
return PTR_ERR(table);
|
return PTR_ERR(table);
|
||||||
if (!trans && (table->flags & NFT_TABLE_INACTIVE))
|
|
||||||
return -ENOENT;
|
|
||||||
|
|
||||||
nft_ctx_init(ctx, net, skb, nlh, afi, table, NULL, nla);
|
nft_ctx_init(ctx, net, skb, nlh, afi, table, NULL, nla);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3145,9 +3146,11 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = nft_ctx_init_from_elemattr(&ctx, net, cb->skb, cb->nlh,
|
err = nft_ctx_init_from_elemattr(&ctx, net, cb->skb, cb->nlh,
|
||||||
(void *)nla, false);
|
(void *)nla);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
if (ctx.table->flags & NFT_TABLE_INACTIVE)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
|
set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
|
||||||
if (IS_ERR(set))
|
if (IS_ERR(set))
|
||||||
|
@ -3202,18 +3205,19 @@ nla_put_failure:
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nf_tables_getsetelem(struct sock *nlsk, struct sk_buff *skb,
|
static int nf_tables_getsetelem(struct net *net, struct sock *nlsk,
|
||||||
const struct nlmsghdr *nlh,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const nla[])
|
const struct nlattr * const nla[])
|
||||||
{
|
{
|
||||||
struct net *net = sock_net(skb->sk);
|
|
||||||
const struct nft_set *set;
|
const struct nft_set *set;
|
||||||
struct nft_ctx ctx;
|
struct nft_ctx ctx;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, false);
|
err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
if (ctx.table->flags & NFT_TABLE_INACTIVE)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
|
set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
|
||||||
if (IS_ERR(set))
|
if (IS_ERR(set))
|
||||||
|
@ -3535,7 +3539,7 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
|
||||||
if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL)
|
if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, true);
|
err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -3629,7 +3633,7 @@ static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
|
||||||
if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL)
|
if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, false);
|
err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -3733,11 +3737,10 @@ err:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nf_tables_getgen(struct sock *nlsk, struct sk_buff *skb,
|
static int nf_tables_getgen(struct net *net, struct sock *nlsk,
|
||||||
const struct nlmsghdr *nlh,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const nla[])
|
const struct nlattr * const nla[])
|
||||||
{
|
{
|
||||||
struct net *net = sock_net(skb->sk);
|
|
||||||
struct sk_buff *skb2;
|
struct sk_buff *skb2;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -3881,9 +3884,8 @@ static void nf_tables_commit_release(struct nft_trans *trans)
|
||||||
kfree(trans);
|
kfree(trans);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nf_tables_commit(struct sk_buff *skb)
|
static int nf_tables_commit(struct net *net, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct net *net = sock_net(skb->sk);
|
|
||||||
struct nft_trans *trans, *next;
|
struct nft_trans *trans, *next;
|
||||||
struct nft_trans_elem *te;
|
struct nft_trans_elem *te;
|
||||||
|
|
||||||
|
@ -4018,9 +4020,8 @@ static void nf_tables_abort_release(struct nft_trans *trans)
|
||||||
kfree(trans);
|
kfree(trans);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nf_tables_abort(struct sk_buff *skb)
|
static int nf_tables_abort(struct net *net, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct net *net = sock_net(skb->sk);
|
|
||||||
struct nft_trans *trans, *next;
|
struct nft_trans *trans, *next;
|
||||||
struct nft_trans_elem *te;
|
struct nft_trans_elem *te;
|
||||||
|
|
||||||
|
@ -4579,7 +4580,7 @@ int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nft_data_dump);
|
EXPORT_SYMBOL_GPL(nft_data_dump);
|
||||||
|
|
||||||
static int nf_tables_init_net(struct net *net)
|
static int __net_init nf_tables_init_net(struct net *net)
|
||||||
{
|
{
|
||||||
INIT_LIST_HEAD(&net->nft.af_info);
|
INIT_LIST_HEAD(&net->nft.af_info);
|
||||||
INIT_LIST_HEAD(&net->nft.commit_list);
|
INIT_LIST_HEAD(&net->nft.commit_list);
|
||||||
|
@ -4587,6 +4588,67 @@ static int nf_tables_init_net(struct net *net)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int __nft_release_basechain(struct nft_ctx *ctx)
|
||||||
|
{
|
||||||
|
struct nft_rule *rule, *nr;
|
||||||
|
|
||||||
|
BUG_ON(!(ctx->chain->flags & NFT_BASE_CHAIN));
|
||||||
|
|
||||||
|
nf_tables_unregister_hooks(ctx->chain->table, ctx->chain,
|
||||||
|
ctx->afi->nops);
|
||||||
|
list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) {
|
||||||
|
list_del(&rule->list);
|
||||||
|
ctx->chain->use--;
|
||||||
|
nf_tables_rule_destroy(ctx, rule);
|
||||||
|
}
|
||||||
|
list_del(&ctx->chain->list);
|
||||||
|
ctx->table->use--;
|
||||||
|
nf_tables_chain_destroy(ctx->chain);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(__nft_release_basechain);
|
||||||
|
|
||||||
|
/* Called by nft_unregister_afinfo() from __net_exit path, nfnl_lock is held. */
|
||||||
|
static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi)
|
||||||
|
{
|
||||||
|
struct nft_table *table, *nt;
|
||||||
|
struct nft_chain *chain, *nc;
|
||||||
|
struct nft_rule *rule, *nr;
|
||||||
|
struct nft_set *set, *ns;
|
||||||
|
struct nft_ctx ctx = {
|
||||||
|
.net = net,
|
||||||
|
.afi = afi,
|
||||||
|
};
|
||||||
|
|
||||||
|
list_for_each_entry_safe(table, nt, &afi->tables, list) {
|
||||||
|
list_for_each_entry(chain, &table->chains, list)
|
||||||
|
nf_tables_unregister_hooks(table, chain, afi->nops);
|
||||||
|
/* No packets are walking on these chains anymore. */
|
||||||
|
ctx.table = table;
|
||||||
|
list_for_each_entry(chain, &table->chains, list) {
|
||||||
|
ctx.chain = chain;
|
||||||
|
list_for_each_entry_safe(rule, nr, &chain->rules, list) {
|
||||||
|
list_del(&rule->list);
|
||||||
|
chain->use--;
|
||||||
|
nf_tables_rule_destroy(&ctx, rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list_for_each_entry_safe(set, ns, &table->sets, list) {
|
||||||
|
list_del(&set->list);
|
||||||
|
table->use--;
|
||||||
|
nft_set_destroy(set);
|
||||||
|
}
|
||||||
|
list_for_each_entry_safe(chain, nc, &table->chains, list) {
|
||||||
|
list_del(&chain->list);
|
||||||
|
table->use--;
|
||||||
|
nf_tables_chain_destroy(chain);
|
||||||
|
}
|
||||||
|
list_del(&table->list);
|
||||||
|
nf_tables_table_destroy(&ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static struct pernet_operations nf_tables_net_ops = {
|
static struct pernet_operations nf_tables_net_ops = {
|
||||||
.init = nf_tables_init_net,
|
.init = nf_tables_init_net,
|
||||||
};
|
};
|
||||||
|
|
|
@ -57,7 +57,7 @@ err:
|
||||||
|
|
||||||
static void __net_exit nf_tables_inet_exit_net(struct net *net)
|
static void __net_exit nf_tables_inet_exit_net(struct net *net)
|
||||||
{
|
{
|
||||||
nft_unregister_afinfo(net->nft.inet);
|
nft_unregister_afinfo(net, net->nft.inet);
|
||||||
kfree(net->nft.inet);
|
kfree(net->nft.inet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -139,7 +139,7 @@ err:
|
||||||
|
|
||||||
static void nf_tables_netdev_exit_net(struct net *net)
|
static void nf_tables_netdev_exit_net(struct net *net)
|
||||||
{
|
{
|
||||||
nft_unregister_afinfo(net->nft.netdev);
|
nft_unregister_afinfo(net, net->nft.netdev);
|
||||||
kfree(net->nft.netdev);
|
kfree(net->nft.netdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,35 +156,17 @@ static const struct nf_chain_type nft_filter_chain_netdev = {
|
||||||
.hook_mask = (1 << NF_NETDEV_INGRESS),
|
.hook_mask = (1 << NF_NETDEV_INGRESS),
|
||||||
};
|
};
|
||||||
|
|
||||||
static void nft_netdev_event(unsigned long event, struct nft_af_info *afi,
|
static void nft_netdev_event(unsigned long event, struct net_device *dev,
|
||||||
struct net_device *dev, struct nft_table *table,
|
struct nft_ctx *ctx)
|
||||||
struct nft_base_chain *basechain)
|
|
||||||
{
|
{
|
||||||
|
struct nft_base_chain *basechain = nft_base_chain(ctx->chain);
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case NETDEV_REGISTER:
|
|
||||||
if (strcmp(basechain->dev_name, dev->name) != 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
BUG_ON(!(basechain->flags & NFT_BASECHAIN_DISABLED));
|
|
||||||
|
|
||||||
dev_hold(dev);
|
|
||||||
basechain->ops[0].dev = dev;
|
|
||||||
basechain->flags &= ~NFT_BASECHAIN_DISABLED;
|
|
||||||
if (!(table->flags & NFT_TABLE_F_DORMANT))
|
|
||||||
nft_register_basechain(basechain, afi->nops);
|
|
||||||
break;
|
|
||||||
case NETDEV_UNREGISTER:
|
case NETDEV_UNREGISTER:
|
||||||
if (strcmp(basechain->dev_name, dev->name) != 0)
|
if (strcmp(basechain->dev_name, dev->name) != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
BUG_ON(basechain->flags & NFT_BASECHAIN_DISABLED);
|
__nft_release_basechain(ctx);
|
||||||
|
|
||||||
if (!(table->flags & NFT_TABLE_F_DORMANT))
|
|
||||||
nft_unregister_basechain(basechain, afi->nops);
|
|
||||||
|
|
||||||
dev_put(basechain->ops[0].dev);
|
|
||||||
basechain->ops[0].dev = NULL;
|
|
||||||
basechain->flags |= NFT_BASECHAIN_DISABLED;
|
|
||||||
break;
|
break;
|
||||||
case NETDEV_CHANGENAME:
|
case NETDEV_CHANGENAME:
|
||||||
if (dev->ifindex != basechain->ops[0].dev->ifindex)
|
if (dev->ifindex != basechain->ops[0].dev->ifindex)
|
||||||
|
@ -201,20 +183,29 @@ static int nf_tables_netdev_event(struct notifier_block *this,
|
||||||
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
||||||
struct nft_af_info *afi;
|
struct nft_af_info *afi;
|
||||||
struct nft_table *table;
|
struct nft_table *table;
|
||||||
struct nft_chain *chain;
|
struct nft_chain *chain, *nr;
|
||||||
|
struct nft_ctx ctx = {
|
||||||
|
.net = dev_net(dev),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (event != NETDEV_UNREGISTER &&
|
||||||
|
event != NETDEV_CHANGENAME)
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
|
||||||
nfnl_lock(NFNL_SUBSYS_NFTABLES);
|
nfnl_lock(NFNL_SUBSYS_NFTABLES);
|
||||||
list_for_each_entry(afi, &dev_net(dev)->nft.af_info, list) {
|
list_for_each_entry(afi, &dev_net(dev)->nft.af_info, list) {
|
||||||
|
ctx.afi = afi;
|
||||||
if (afi->family != NFPROTO_NETDEV)
|
if (afi->family != NFPROTO_NETDEV)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
list_for_each_entry(table, &afi->tables, list) {
|
list_for_each_entry(table, &afi->tables, list) {
|
||||||
list_for_each_entry(chain, &table->chains, list) {
|
ctx.table = table;
|
||||||
|
list_for_each_entry_safe(chain, nr, &table->chains, list) {
|
||||||
if (!(chain->flags & NFT_BASE_CHAIN))
|
if (!(chain->flags & NFT_BASE_CHAIN))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
nft_netdev_event(event, afi, dev, table,
|
ctx.chain = chain;
|
||||||
nft_base_chain(chain));
|
nft_netdev_event(event, dev, &ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -206,7 +206,7 @@ replay:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nc->call_rcu) {
|
if (nc->call_rcu) {
|
||||||
err = nc->call_rcu(net->nfnl, skb, nlh,
|
err = nc->call_rcu(net, net->nfnl, skb, nlh,
|
||||||
(const struct nlattr **)cda);
|
(const struct nlattr **)cda);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
} else {
|
} else {
|
||||||
|
@ -216,8 +216,8 @@ replay:
|
||||||
nfnetlink_find_client(type, ss) != nc)
|
nfnetlink_find_client(type, ss) != nc)
|
||||||
err = -EAGAIN;
|
err = -EAGAIN;
|
||||||
else if (nc->call)
|
else if (nc->call)
|
||||||
err = nc->call(net->nfnl, skb, nlh,
|
err = nc->call(net, net->nfnl, skb, nlh,
|
||||||
(const struct nlattr **)cda);
|
(const struct nlattr **)cda);
|
||||||
else
|
else
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
nfnl_unlock(subsys_id);
|
nfnl_unlock(subsys_id);
|
||||||
|
@ -425,15 +425,15 @@ next:
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
if (status & NFNL_BATCH_REPLAY) {
|
if (status & NFNL_BATCH_REPLAY) {
|
||||||
ss->abort(oskb);
|
ss->abort(net, oskb);
|
||||||
nfnl_err_reset(&err_list);
|
nfnl_err_reset(&err_list);
|
||||||
nfnl_unlock(subsys_id);
|
nfnl_unlock(subsys_id);
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
goto replay;
|
goto replay;
|
||||||
} else if (status == NFNL_BATCH_DONE) {
|
} else if (status == NFNL_BATCH_DONE) {
|
||||||
ss->commit(oskb);
|
ss->commit(net, oskb);
|
||||||
} else {
|
} else {
|
||||||
ss->abort(oskb);
|
ss->abort(net, oskb);
|
||||||
}
|
}
|
||||||
|
|
||||||
nfnl_err_deliver(&err_list, oskb);
|
nfnl_err_deliver(&err_list, oskb);
|
||||||
|
|
|
@ -46,12 +46,11 @@ struct nfacct_filter {
|
||||||
#define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES)
|
#define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES)
|
||||||
#define NFACCT_OVERQUOTA_BIT 2 /* NFACCT_F_OVERQUOTA */
|
#define NFACCT_OVERQUOTA_BIT 2 /* NFACCT_F_OVERQUOTA */
|
||||||
|
|
||||||
static int
|
static int nfnl_acct_new(struct net *net, struct sock *nfnl,
|
||||||
nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh, const struct nlattr * const tb[])
|
const struct nlattr * const tb[])
|
||||||
{
|
{
|
||||||
struct nf_acct *nfacct, *matching = NULL;
|
struct nf_acct *nfacct, *matching = NULL;
|
||||||
struct net *net = sock_net(nfnl);
|
|
||||||
char *acct_name;
|
char *acct_name;
|
||||||
unsigned int size = 0;
|
unsigned int size = 0;
|
||||||
u32 flags = 0;
|
u32 flags = 0;
|
||||||
|
@ -253,11 +252,10 @@ nfacct_filter_alloc(const struct nlattr * const attr)
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int nfnl_acct_get(struct net *net, struct sock *nfnl,
|
||||||
nfnl_acct_get(struct sock *nfnl, struct sk_buff *skb,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh, const struct nlattr * const tb[])
|
const struct nlattr * const tb[])
|
||||||
{
|
{
|
||||||
struct net *net = sock_net(nfnl);
|
|
||||||
int ret = -ENOENT;
|
int ret = -ENOENT;
|
||||||
struct nf_acct *cur;
|
struct nf_acct *cur;
|
||||||
char *acct_name;
|
char *acct_name;
|
||||||
|
@ -333,11 +331,10 @@ static int nfnl_acct_try_del(struct nf_acct *cur)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int nfnl_acct_del(struct net *net, struct sock *nfnl,
|
||||||
nfnl_acct_del(struct sock *nfnl, struct sk_buff *skb,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh, const struct nlattr * const tb[])
|
const struct nlattr * const tb[])
|
||||||
{
|
{
|
||||||
struct net *net = sock_net(nfnl);
|
|
||||||
char *acct_name;
|
char *acct_name;
|
||||||
struct nf_acct *cur;
|
struct nf_acct *cur;
|
||||||
int ret = -ENOENT;
|
int ret = -ENOENT;
|
||||||
|
|
|
@ -286,9 +286,9 @@ nfnl_cthelper_update(const struct nlattr * const tb[],
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int nfnl_cthelper_new(struct net *net, struct sock *nfnl,
|
||||||
nfnl_cthelper_new(struct sock *nfnl, struct sk_buff *skb,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh, const struct nlattr * const tb[])
|
const struct nlattr * const tb[])
|
||||||
{
|
{
|
||||||
const char *helper_name;
|
const char *helper_name;
|
||||||
struct nf_conntrack_helper *cur, *helper = NULL;
|
struct nf_conntrack_helper *cur, *helper = NULL;
|
||||||
|
@ -498,9 +498,9 @@ out:
|
||||||
return skb->len;
|
return skb->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int nfnl_cthelper_get(struct net *net, struct sock *nfnl,
|
||||||
nfnl_cthelper_get(struct sock *nfnl, struct sk_buff *skb,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh, const struct nlattr * const tb[])
|
const struct nlattr * const tb[])
|
||||||
{
|
{
|
||||||
int ret = -ENOENT, i;
|
int ret = -ENOENT, i;
|
||||||
struct nf_conntrack_helper *cur;
|
struct nf_conntrack_helper *cur;
|
||||||
|
@ -570,9 +570,9 @@ nfnl_cthelper_get(struct sock *nfnl, struct sk_buff *skb,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int nfnl_cthelper_del(struct net *net, struct sock *nfnl,
|
||||||
nfnl_cthelper_del(struct sock *nfnl, struct sk_buff *skb,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh, const struct nlattr * const tb[])
|
const struct nlattr * const tb[])
|
||||||
{
|
{
|
||||||
char *helper_name = NULL;
|
char *helper_name = NULL;
|
||||||
struct nf_conntrack_helper *cur;
|
struct nf_conntrack_helper *cur;
|
||||||
|
|
|
@ -65,16 +65,15 @@ ctnl_timeout_parse_policy(void *timeouts, struct nf_conntrack_l4proto *l4proto,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int cttimeout_new_timeout(struct net *net, struct sock *ctnl,
|
||||||
cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const cda[])
|
const struct nlattr * const cda[])
|
||||||
{
|
{
|
||||||
__u16 l3num;
|
__u16 l3num;
|
||||||
__u8 l4num;
|
__u8 l4num;
|
||||||
struct nf_conntrack_l4proto *l4proto;
|
struct nf_conntrack_l4proto *l4proto;
|
||||||
struct ctnl_timeout *timeout, *matching = NULL;
|
struct ctnl_timeout *timeout, *matching = NULL;
|
||||||
struct net *net = sock_net(skb->sk);
|
|
||||||
char *name;
|
char *name;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -239,12 +238,11 @@ ctnl_timeout_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
return skb->len;
|
return skb->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int cttimeout_get_timeout(struct net *net, struct sock *ctnl,
|
||||||
cttimeout_get_timeout(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const cda[])
|
const struct nlattr * const cda[])
|
||||||
{
|
{
|
||||||
struct net *net = sock_net(skb->sk);
|
|
||||||
int ret = -ENOENT;
|
int ret = -ENOENT;
|
||||||
char *name;
|
char *name;
|
||||||
struct ctnl_timeout *cur;
|
struct ctnl_timeout *cur;
|
||||||
|
@ -339,15 +337,14 @@ static int ctnl_timeout_try_del(struct net *net, struct ctnl_timeout *timeout)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int cttimeout_del_timeout(struct net *net, struct sock *ctnl,
|
||||||
cttimeout_del_timeout(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const cda[])
|
const struct nlattr * const cda[])
|
||||||
{
|
{
|
||||||
struct net *net = sock_net(skb->sk);
|
|
||||||
char *name;
|
|
||||||
struct ctnl_timeout *cur;
|
struct ctnl_timeout *cur;
|
||||||
int ret = -ENOENT;
|
int ret = -ENOENT;
|
||||||
|
char *name;
|
||||||
|
|
||||||
if (!cda[CTA_TIMEOUT_NAME]) {
|
if (!cda[CTA_TIMEOUT_NAME]) {
|
||||||
list_for_each_entry(cur, &net->nfct_timeout_list, head)
|
list_for_each_entry(cur, &net->nfct_timeout_list, head)
|
||||||
|
@ -370,15 +367,14 @@ cttimeout_del_timeout(struct sock *ctnl, struct sk_buff *skb,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int cttimeout_default_set(struct net *net, struct sock *ctnl,
|
||||||
cttimeout_default_set(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const cda[])
|
const struct nlattr * const cda[])
|
||||||
{
|
{
|
||||||
__u16 l3num;
|
__u16 l3num;
|
||||||
__u8 l4num;
|
__u8 l4num;
|
||||||
struct nf_conntrack_l4proto *l4proto;
|
struct nf_conntrack_l4proto *l4proto;
|
||||||
struct net *net = sock_net(skb->sk);
|
|
||||||
unsigned int *timeouts;
|
unsigned int *timeouts;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -460,14 +456,14 @@ nla_put_failure:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cttimeout_default_get(struct sock *ctnl, struct sk_buff *skb,
|
static int cttimeout_default_get(struct net *net, struct sock *ctnl,
|
||||||
|
struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const cda[])
|
const struct nlattr * const cda[])
|
||||||
{
|
{
|
||||||
__u16 l3num;
|
__u16 l3num;
|
||||||
__u8 l4num;
|
__u8 l4num;
|
||||||
struct nf_conntrack_l4proto *l4proto;
|
struct nf_conntrack_l4proto *l4proto;
|
||||||
struct net *net = sock_net(skb->sk);
|
|
||||||
struct sk_buff *skb2;
|
struct sk_buff *skb2;
|
||||||
int ret, err;
|
int ret, err;
|
||||||
|
|
||||||
|
|
|
@ -785,10 +785,9 @@ static struct notifier_block nfulnl_rtnl_notifier = {
|
||||||
.notifier_call = nfulnl_rcv_nl_event,
|
.notifier_call = nfulnl_rcv_nl_event,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int nfulnl_recv_unsupp(struct net *net, struct sock *ctnl,
|
||||||
nfulnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const nfqa[])
|
||||||
const struct nlattr * const nfqa[])
|
|
||||||
{
|
{
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
}
|
}
|
||||||
|
@ -809,16 +808,14 @@ static const struct nla_policy nfula_cfg_policy[NFULA_CFG_MAX+1] = {
|
||||||
[NFULA_CFG_FLAGS] = { .type = NLA_U16 },
|
[NFULA_CFG_FLAGS] = { .type = NLA_U16 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int nfulnl_recv_config(struct net *net, struct sock *ctnl,
|
||||||
nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const nfula[])
|
||||||
const struct nlattr * const nfula[])
|
|
||||||
{
|
{
|
||||||
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
||||||
u_int16_t group_num = ntohs(nfmsg->res_id);
|
u_int16_t group_num = ntohs(nfmsg->res_id);
|
||||||
struct nfulnl_instance *inst;
|
struct nfulnl_instance *inst;
|
||||||
struct nfulnl_msg_config_cmd *cmd = NULL;
|
struct nfulnl_msg_config_cmd *cmd = NULL;
|
||||||
struct net *net = sock_net(ctnl);
|
|
||||||
struct nfnl_log_net *log = nfnl_log_pernet(net);
|
struct nfnl_log_net *log = nfnl_log_pernet(net);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u16 flags = 0;
|
u16 flags = 0;
|
||||||
|
@ -891,7 +888,7 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
|
||||||
goto out_put;
|
goto out_put;
|
||||||
default:
|
default:
|
||||||
ret = -ENOTSUPP;
|
ret = -ENOTSUPP;
|
||||||
break;
|
goto out_put;
|
||||||
}
|
}
|
||||||
} else if (!inst) {
|
} else if (!inst) {
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
|
|
|
@ -957,10 +957,10 @@ static int nfq_id_after(unsigned int id, unsigned int max)
|
||||||
return (int)(id - max) > 0;
|
return (int)(id - max) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int nfqnl_recv_verdict_batch(struct net *net, struct sock *ctnl,
|
||||||
nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const nfqa[])
|
const struct nlattr * const nfqa[])
|
||||||
{
|
{
|
||||||
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
||||||
struct nf_queue_entry *entry, *tmp;
|
struct nf_queue_entry *entry, *tmp;
|
||||||
|
@ -969,8 +969,6 @@ nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb,
|
||||||
struct nfqnl_instance *queue;
|
struct nfqnl_instance *queue;
|
||||||
LIST_HEAD(batch_list);
|
LIST_HEAD(batch_list);
|
||||||
u16 queue_num = ntohs(nfmsg->res_id);
|
u16 queue_num = ntohs(nfmsg->res_id);
|
||||||
|
|
||||||
struct net *net = sock_net(ctnl);
|
|
||||||
struct nfnl_queue_net *q = nfnl_queue_pernet(net);
|
struct nfnl_queue_net *q = nfnl_queue_pernet(net);
|
||||||
|
|
||||||
queue = verdict_instance_lookup(q, queue_num,
|
queue = verdict_instance_lookup(q, queue_num,
|
||||||
|
@ -1029,14 +1027,13 @@ static struct nf_conn *nfqnl_ct_parse(struct nfnl_ct_hook *nfnl_ct,
|
||||||
return ct;
|
return ct;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int nfqnl_recv_verdict(struct net *net, struct sock *ctnl,
|
||||||
nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const nfqa[])
|
const struct nlattr * const nfqa[])
|
||||||
{
|
{
|
||||||
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
||||||
u_int16_t queue_num = ntohs(nfmsg->res_id);
|
u_int16_t queue_num = ntohs(nfmsg->res_id);
|
||||||
|
|
||||||
struct nfqnl_msg_verdict_hdr *vhdr;
|
struct nfqnl_msg_verdict_hdr *vhdr;
|
||||||
struct nfqnl_instance *queue;
|
struct nfqnl_instance *queue;
|
||||||
unsigned int verdict;
|
unsigned int verdict;
|
||||||
|
@ -1044,8 +1041,6 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
|
||||||
enum ip_conntrack_info uninitialized_var(ctinfo);
|
enum ip_conntrack_info uninitialized_var(ctinfo);
|
||||||
struct nfnl_ct_hook *nfnl_ct;
|
struct nfnl_ct_hook *nfnl_ct;
|
||||||
struct nf_conn *ct = NULL;
|
struct nf_conn *ct = NULL;
|
||||||
|
|
||||||
struct net *net = sock_net(ctnl);
|
|
||||||
struct nfnl_queue_net *q = nfnl_queue_pernet(net);
|
struct nfnl_queue_net *q = nfnl_queue_pernet(net);
|
||||||
|
|
||||||
queue = instance_lookup(q, queue_num);
|
queue = instance_lookup(q, queue_num);
|
||||||
|
@ -1092,10 +1087,9 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int nfqnl_recv_unsupp(struct net *net, struct sock *ctnl,
|
||||||
nfqnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const nfqa[])
|
||||||
const struct nlattr * const nfqa[])
|
|
||||||
{
|
{
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
}
|
}
|
||||||
|
@ -1110,17 +1104,16 @@ static const struct nf_queue_handler nfqh = {
|
||||||
.nf_hook_drop = &nfqnl_nf_hook_drop,
|
.nf_hook_drop = &nfqnl_nf_hook_drop,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int nfqnl_recv_config(struct net *net, struct sock *ctnl,
|
||||||
nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlattr * const nfqa[])
|
||||||
const struct nlattr * const nfqa[])
|
|
||||||
{
|
{
|
||||||
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
|
||||||
u_int16_t queue_num = ntohs(nfmsg->res_id);
|
u_int16_t queue_num = ntohs(nfmsg->res_id);
|
||||||
struct nfqnl_instance *queue;
|
struct nfqnl_instance *queue;
|
||||||
struct nfqnl_msg_config_cmd *cmd = NULL;
|
struct nfqnl_msg_config_cmd *cmd = NULL;
|
||||||
struct net *net = sock_net(ctnl);
|
|
||||||
struct nfnl_queue_net *q = nfnl_queue_pernet(net);
|
struct nfnl_queue_net *q = nfnl_queue_pernet(net);
|
||||||
|
__u32 flags = 0, mask = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (nfqa[NFQA_CFG_CMD]) {
|
if (nfqa[NFQA_CFG_CMD]) {
|
||||||
|
@ -1133,6 +1126,40 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if we support these flags in first place, dependencies should
|
||||||
|
* be there too not to break atomicity.
|
||||||
|
*/
|
||||||
|
if (nfqa[NFQA_CFG_FLAGS]) {
|
||||||
|
if (!nfqa[NFQA_CFG_MASK]) {
|
||||||
|
/* A mask is needed to specify which flags are being
|
||||||
|
* changed.
|
||||||
|
*/
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags = ntohl(nla_get_be32(nfqa[NFQA_CFG_FLAGS]));
|
||||||
|
mask = ntohl(nla_get_be32(nfqa[NFQA_CFG_MASK]));
|
||||||
|
|
||||||
|
if (flags >= NFQA_CFG_F_MAX)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
#if !IS_ENABLED(CONFIG_NETWORK_SECMARK)
|
||||||
|
if (flags & mask & NFQA_CFG_F_SECCTX)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
#endif
|
||||||
|
if ((flags & mask & NFQA_CFG_F_CONNTRACK) &&
|
||||||
|
!rcu_access_pointer(nfnl_ct_hook)) {
|
||||||
|
#ifdef CONFIG_MODULES
|
||||||
|
nfnl_unlock(NFNL_SUBSYS_QUEUE);
|
||||||
|
request_module("ip_conntrack_netlink");
|
||||||
|
nfnl_lock(NFNL_SUBSYS_QUEUE);
|
||||||
|
if (rcu_access_pointer(nfnl_ct_hook))
|
||||||
|
return -EAGAIN;
|
||||||
|
#endif
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
queue = instance_lookup(q, queue_num);
|
queue = instance_lookup(q, queue_num);
|
||||||
if (queue && queue->peer_portid != NETLINK_CB(skb).portid) {
|
if (queue && queue->peer_portid != NETLINK_CB(skb).portid) {
|
||||||
|
@ -1160,70 +1187,38 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
|
||||||
goto err_out_unlock;
|
goto err_out_unlock;
|
||||||
}
|
}
|
||||||
instance_destroy(q, queue);
|
instance_destroy(q, queue);
|
||||||
break;
|
goto err_out_unlock;
|
||||||
case NFQNL_CFG_CMD_PF_BIND:
|
case NFQNL_CFG_CMD_PF_BIND:
|
||||||
case NFQNL_CFG_CMD_PF_UNBIND:
|
case NFQNL_CFG_CMD_PF_UNBIND:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -ENOTSUPP;
|
ret = -ENOTSUPP;
|
||||||
break;
|
goto err_out_unlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nfqa[NFQA_CFG_PARAMS]) {
|
if (!queue) {
|
||||||
struct nfqnl_msg_config_params *params;
|
ret = -ENODEV;
|
||||||
|
goto err_out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nfqa[NFQA_CFG_PARAMS]) {
|
||||||
|
struct nfqnl_msg_config_params *params =
|
||||||
|
nla_data(nfqa[NFQA_CFG_PARAMS]);
|
||||||
|
|
||||||
if (!queue) {
|
|
||||||
ret = -ENODEV;
|
|
||||||
goto err_out_unlock;
|
|
||||||
}
|
|
||||||
params = nla_data(nfqa[NFQA_CFG_PARAMS]);
|
|
||||||
nfqnl_set_mode(queue, params->copy_mode,
|
nfqnl_set_mode(queue, params->copy_mode,
|
||||||
ntohl(params->copy_range));
|
ntohl(params->copy_range));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nfqa[NFQA_CFG_QUEUE_MAXLEN]) {
|
if (nfqa[NFQA_CFG_QUEUE_MAXLEN]) {
|
||||||
__be32 *queue_maxlen;
|
__be32 *queue_maxlen = nla_data(nfqa[NFQA_CFG_QUEUE_MAXLEN]);
|
||||||
|
|
||||||
if (!queue) {
|
|
||||||
ret = -ENODEV;
|
|
||||||
goto err_out_unlock;
|
|
||||||
}
|
|
||||||
queue_maxlen = nla_data(nfqa[NFQA_CFG_QUEUE_MAXLEN]);
|
|
||||||
spin_lock_bh(&queue->lock);
|
spin_lock_bh(&queue->lock);
|
||||||
queue->queue_maxlen = ntohl(*queue_maxlen);
|
queue->queue_maxlen = ntohl(*queue_maxlen);
|
||||||
spin_unlock_bh(&queue->lock);
|
spin_unlock_bh(&queue->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nfqa[NFQA_CFG_FLAGS]) {
|
if (nfqa[NFQA_CFG_FLAGS]) {
|
||||||
__u32 flags, mask;
|
|
||||||
|
|
||||||
if (!queue) {
|
|
||||||
ret = -ENODEV;
|
|
||||||
goto err_out_unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!nfqa[NFQA_CFG_MASK]) {
|
|
||||||
/* A mask is needed to specify which flags are being
|
|
||||||
* changed.
|
|
||||||
*/
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto err_out_unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
flags = ntohl(nla_get_be32(nfqa[NFQA_CFG_FLAGS]));
|
|
||||||
mask = ntohl(nla_get_be32(nfqa[NFQA_CFG_MASK]));
|
|
||||||
|
|
||||||
if (flags >= NFQA_CFG_F_MAX) {
|
|
||||||
ret = -EOPNOTSUPP;
|
|
||||||
goto err_out_unlock;
|
|
||||||
}
|
|
||||||
#if !IS_ENABLED(CONFIG_NETWORK_SECMARK)
|
|
||||||
if (flags & mask & NFQA_CFG_F_SECCTX) {
|
|
||||||
ret = -EOPNOTSUPP;
|
|
||||||
goto err_out_unlock;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
spin_lock_bh(&queue->lock);
|
spin_lock_bh(&queue->lock);
|
||||||
queue->flags &= ~mask;
|
queue->flags &= ~mask;
|
||||||
queue->flags |= flags & mask;
|
queue->flags |= flags & mask;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <asm/unaligned.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
@ -39,6 +40,27 @@ static void nft_byteorder_eval(const struct nft_expr *expr,
|
||||||
d = (void *)dst;
|
d = (void *)dst;
|
||||||
|
|
||||||
switch (priv->size) {
|
switch (priv->size) {
|
||||||
|
case 8: {
|
||||||
|
u64 src64;
|
||||||
|
|
||||||
|
switch (priv->op) {
|
||||||
|
case NFT_BYTEORDER_NTOH:
|
||||||
|
for (i = 0; i < priv->len / 8; i++) {
|
||||||
|
src64 = get_unaligned_be64(&src[i]);
|
||||||
|
src64 = be64_to_cpu((__force __be64)src64);
|
||||||
|
put_unaligned_be64(src64, &dst[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NFT_BYTEORDER_HTON:
|
||||||
|
for (i = 0; i < priv->len / 8; i++) {
|
||||||
|
src64 = get_unaligned_be64(&src[i]);
|
||||||
|
src64 = (__force u64)cpu_to_be64(src64);
|
||||||
|
put_unaligned_be64(src64, &dst[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 4:
|
case 4:
|
||||||
switch (priv->op) {
|
switch (priv->op) {
|
||||||
case NFT_BYTEORDER_NTOH:
|
case NFT_BYTEORDER_NTOH:
|
||||||
|
@ -101,6 +123,7 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
|
||||||
switch (priv->size) {
|
switch (priv->size) {
|
||||||
case 2:
|
case 2:
|
||||||
case 4:
|
case 4:
|
||||||
|
case 8:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
|
@ -519,9 +519,9 @@ nla_put_failure:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int nfnl_compat_get(struct net *net, struct sock *nfnl,
|
||||||
nfnl_compat_get(struct sock *nfnl, struct sk_buff *skb,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlmsghdr *nlh, const struct nlattr * const tb[])
|
const struct nlattr * const tb[])
|
||||||
{
|
{
|
||||||
int ret = 0, target;
|
int ret = 0, target;
|
||||||
struct nfgenmsg *nfmsg;
|
struct nfgenmsg *nfmsg;
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <linux/netfilter/nf_tables.h>
|
#include <linux/netfilter/nf_tables.h>
|
||||||
#include <net/netfilter/nf_tables.h>
|
#include <net/netfilter/nf_tables.h>
|
||||||
#include <net/netfilter/nf_conntrack.h>
|
#include <net/netfilter/nf_conntrack.h>
|
||||||
|
#include <net/netfilter/nf_conntrack_acct.h>
|
||||||
#include <net/netfilter/nf_conntrack_tuple.h>
|
#include <net/netfilter/nf_conntrack_tuple.h>
|
||||||
#include <net/netfilter/nf_conntrack_helper.h>
|
#include <net/netfilter/nf_conntrack_helper.h>
|
||||||
#include <net/netfilter/nf_conntrack_ecache.h>
|
#include <net/netfilter/nf_conntrack_ecache.h>
|
||||||
|
@ -30,6 +31,18 @@ struct nft_ct {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static u64 nft_ct_get_eval_counter(const struct nf_conn_counter *c,
|
||||||
|
enum nft_ct_keys k,
|
||||||
|
enum ip_conntrack_dir d)
|
||||||
|
{
|
||||||
|
if (d < IP_CT_DIR_MAX)
|
||||||
|
return k == NFT_CT_BYTES ? atomic64_read(&c[d].bytes) :
|
||||||
|
atomic64_read(&c[d].packets);
|
||||||
|
|
||||||
|
return nft_ct_get_eval_counter(c, k, IP_CT_DIR_ORIGINAL) +
|
||||||
|
nft_ct_get_eval_counter(c, k, IP_CT_DIR_REPLY);
|
||||||
|
}
|
||||||
|
|
||||||
static void nft_ct_get_eval(const struct nft_expr *expr,
|
static void nft_ct_get_eval(const struct nft_expr *expr,
|
||||||
struct nft_regs *regs,
|
struct nft_regs *regs,
|
||||||
const struct nft_pktinfo *pkt)
|
const struct nft_pktinfo *pkt)
|
||||||
|
@ -114,6 +127,17 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
|
||||||
NF_CT_LABELS_MAX_SIZE - size);
|
NF_CT_LABELS_MAX_SIZE - size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case NFT_CT_BYTES: /* fallthrough */
|
||||||
|
case NFT_CT_PKTS: {
|
||||||
|
const struct nf_conn_acct *acct = nf_conn_acct_find(ct);
|
||||||
|
u64 count = 0;
|
||||||
|
|
||||||
|
if (acct)
|
||||||
|
count = nft_ct_get_eval_counter(acct->counter,
|
||||||
|
priv->key, priv->dir);
|
||||||
|
memcpy(dest, &count, sizeof(count));
|
||||||
|
return;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -291,6 +315,13 @@ static int nft_ct_get_init(const struct nft_ctx *ctx,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u.all);
|
len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u.all);
|
||||||
break;
|
break;
|
||||||
|
case NFT_CT_BYTES:
|
||||||
|
case NFT_CT_PKTS:
|
||||||
|
/* no direction? return sum of original + reply */
|
||||||
|
if (tb[NFTA_CT_DIRECTION] == NULL)
|
||||||
|
priv->dir = IP_CT_DIR_MAX;
|
||||||
|
len = sizeof(u64);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
@ -374,6 +405,13 @@ static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr)
|
||||||
case NFT_CT_PROTO_DST:
|
case NFT_CT_PROTO_DST:
|
||||||
if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
|
if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
break;
|
||||||
|
case NFT_CT_BYTES:
|
||||||
|
case NFT_CT_PKTS:
|
||||||
|
if (priv->dir < IP_CT_DIR_MAX &&
|
||||||
|
nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
|
||||||
|
goto nla_put_failure;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
97
net/netfilter/nft_dup_netdev.c
Normal file
97
net/netfilter/nft_dup_netdev.c
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015 Pablo Neira Ayuso <pablo@netfilter.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 as published by
|
||||||
|
* the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/netlink.h>
|
||||||
|
#include <linux/netfilter.h>
|
||||||
|
#include <linux/netfilter/nf_tables.h>
|
||||||
|
#include <net/netfilter/nf_tables.h>
|
||||||
|
#include <net/netfilter/nf_dup_netdev.h>
|
||||||
|
|
||||||
|
struct nft_dup_netdev {
|
||||||
|
enum nft_registers sreg_dev:8;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void nft_dup_netdev_eval(const struct nft_expr *expr,
|
||||||
|
struct nft_regs *regs,
|
||||||
|
const struct nft_pktinfo *pkt)
|
||||||
|
{
|
||||||
|
struct nft_dup_netdev *priv = nft_expr_priv(expr);
|
||||||
|
int oif = regs->data[priv->sreg_dev];
|
||||||
|
|
||||||
|
nf_dup_netdev_egress(pkt, oif);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct nla_policy nft_dup_netdev_policy[NFTA_DUP_MAX + 1] = {
|
||||||
|
[NFTA_DUP_SREG_DEV] = { .type = NLA_U32 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static int nft_dup_netdev_init(const struct nft_ctx *ctx,
|
||||||
|
const struct nft_expr *expr,
|
||||||
|
const struct nlattr * const tb[])
|
||||||
|
{
|
||||||
|
struct nft_dup_netdev *priv = nft_expr_priv(expr);
|
||||||
|
|
||||||
|
if (tb[NFTA_DUP_SREG_DEV] == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
priv->sreg_dev = nft_parse_register(tb[NFTA_DUP_SREG_DEV]);
|
||||||
|
return nft_validate_register_load(priv->sreg_dev, sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct nft_expr_ops nft_dup_netdev_ingress_ops;
|
||||||
|
|
||||||
|
static int nft_dup_netdev_dump(struct sk_buff *skb, const struct nft_expr *expr)
|
||||||
|
{
|
||||||
|
struct nft_dup_netdev *priv = nft_expr_priv(expr);
|
||||||
|
|
||||||
|
if (nft_dump_register(skb, NFTA_DUP_SREG_DEV, priv->sreg_dev))
|
||||||
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
nla_put_failure:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct nft_expr_type nft_dup_netdev_type;
|
||||||
|
static const struct nft_expr_ops nft_dup_netdev_ops = {
|
||||||
|
.type = &nft_dup_netdev_type,
|
||||||
|
.size = NFT_EXPR_SIZE(sizeof(struct nft_dup_netdev)),
|
||||||
|
.eval = nft_dup_netdev_eval,
|
||||||
|
.init = nft_dup_netdev_init,
|
||||||
|
.dump = nft_dup_netdev_dump,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct nft_expr_type nft_dup_netdev_type __read_mostly = {
|
||||||
|
.family = NFPROTO_NETDEV,
|
||||||
|
.name = "dup",
|
||||||
|
.ops = &nft_dup_netdev_ops,
|
||||||
|
.policy = nft_dup_netdev_policy,
|
||||||
|
.maxattr = NFTA_DUP_MAX,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init nft_dup_netdev_module_init(void)
|
||||||
|
{
|
||||||
|
return nft_register_expr(&nft_dup_netdev_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit nft_dup_netdev_module_exit(void)
|
||||||
|
{
|
||||||
|
nft_unregister_expr(&nft_dup_netdev_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(nft_dup_netdev_module_init);
|
||||||
|
module_exit(nft_dup_netdev_module_exit);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
|
||||||
|
MODULE_ALIAS_NFT_AF_EXPR(5, "dup");
|
98
net/netfilter/nft_fwd_netdev.c
Normal file
98
net/netfilter/nft_fwd_netdev.c
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015 Pablo Neira Ayuso <pablo@netfilter.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 as published by
|
||||||
|
* the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/netlink.h>
|
||||||
|
#include <linux/netfilter.h>
|
||||||
|
#include <linux/netfilter/nf_tables.h>
|
||||||
|
#include <net/netfilter/nf_tables.h>
|
||||||
|
#include <net/netfilter/nf_dup_netdev.h>
|
||||||
|
|
||||||
|
struct nft_fwd_netdev {
|
||||||
|
enum nft_registers sreg_dev:8;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void nft_fwd_netdev_eval(const struct nft_expr *expr,
|
||||||
|
struct nft_regs *regs,
|
||||||
|
const struct nft_pktinfo *pkt)
|
||||||
|
{
|
||||||
|
struct nft_fwd_netdev *priv = nft_expr_priv(expr);
|
||||||
|
int oif = regs->data[priv->sreg_dev];
|
||||||
|
|
||||||
|
nf_dup_netdev_egress(pkt, oif);
|
||||||
|
regs->verdict.code = NF_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct nla_policy nft_fwd_netdev_policy[NFTA_FWD_MAX + 1] = {
|
||||||
|
[NFTA_FWD_SREG_DEV] = { .type = NLA_U32 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static int nft_fwd_netdev_init(const struct nft_ctx *ctx,
|
||||||
|
const struct nft_expr *expr,
|
||||||
|
const struct nlattr * const tb[])
|
||||||
|
{
|
||||||
|
struct nft_fwd_netdev *priv = nft_expr_priv(expr);
|
||||||
|
|
||||||
|
if (tb[NFTA_FWD_SREG_DEV] == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
priv->sreg_dev = nft_parse_register(tb[NFTA_FWD_SREG_DEV]);
|
||||||
|
return nft_validate_register_load(priv->sreg_dev, sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct nft_expr_ops nft_fwd_netdev_ingress_ops;
|
||||||
|
|
||||||
|
static int nft_fwd_netdev_dump(struct sk_buff *skb, const struct nft_expr *expr)
|
||||||
|
{
|
||||||
|
struct nft_fwd_netdev *priv = nft_expr_priv(expr);
|
||||||
|
|
||||||
|
if (nft_dump_register(skb, NFTA_FWD_SREG_DEV, priv->sreg_dev))
|
||||||
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
nla_put_failure:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct nft_expr_type nft_fwd_netdev_type;
|
||||||
|
static const struct nft_expr_ops nft_fwd_netdev_ops = {
|
||||||
|
.type = &nft_fwd_netdev_type,
|
||||||
|
.size = NFT_EXPR_SIZE(sizeof(struct nft_fwd_netdev)),
|
||||||
|
.eval = nft_fwd_netdev_eval,
|
||||||
|
.init = nft_fwd_netdev_init,
|
||||||
|
.dump = nft_fwd_netdev_dump,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct nft_expr_type nft_fwd_netdev_type __read_mostly = {
|
||||||
|
.family = NFPROTO_NETDEV,
|
||||||
|
.name = "fwd",
|
||||||
|
.ops = &nft_fwd_netdev_ops,
|
||||||
|
.policy = nft_fwd_netdev_policy,
|
||||||
|
.maxattr = NFTA_FWD_MAX,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init nft_fwd_netdev_module_init(void)
|
||||||
|
{
|
||||||
|
return nft_register_expr(&nft_fwd_netdev_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit nft_fwd_netdev_module_exit(void)
|
||||||
|
{
|
||||||
|
nft_unregister_expr(&nft_fwd_netdev_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(nft_fwd_netdev_module_init);
|
||||||
|
module_exit(nft_fwd_netdev_module_exit);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
|
||||||
|
MODULE_ALIAS_NFT_AF_EXPR(5, "fwd");
|
|
@ -26,6 +26,7 @@ struct nft_limit {
|
||||||
u64 rate;
|
u64 rate;
|
||||||
u64 nsecs;
|
u64 nsecs;
|
||||||
u32 burst;
|
u32 burst;
|
||||||
|
bool invert;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline bool nft_limit_eval(struct nft_limit *limit, u64 cost)
|
static inline bool nft_limit_eval(struct nft_limit *limit, u64 cost)
|
||||||
|
@ -44,11 +45,11 @@ static inline bool nft_limit_eval(struct nft_limit *limit, u64 cost)
|
||||||
if (delta >= 0) {
|
if (delta >= 0) {
|
||||||
limit->tokens = delta;
|
limit->tokens = delta;
|
||||||
spin_unlock_bh(&limit_lock);
|
spin_unlock_bh(&limit_lock);
|
||||||
return false;
|
return limit->invert;
|
||||||
}
|
}
|
||||||
limit->tokens = tokens;
|
limit->tokens = tokens;
|
||||||
spin_unlock_bh(&limit_lock);
|
spin_unlock_bh(&limit_lock);
|
||||||
return true;
|
return !limit->invert;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nft_limit_init(struct nft_limit *limit,
|
static int nft_limit_init(struct nft_limit *limit,
|
||||||
|
@ -78,6 +79,12 @@ static int nft_limit_init(struct nft_limit *limit,
|
||||||
|
|
||||||
limit->rate = rate;
|
limit->rate = rate;
|
||||||
}
|
}
|
||||||
|
if (tb[NFTA_LIMIT_FLAGS]) {
|
||||||
|
u32 flags = ntohl(nla_get_be32(tb[NFTA_LIMIT_FLAGS]));
|
||||||
|
|
||||||
|
if (flags & NFT_LIMIT_F_INV)
|
||||||
|
limit->invert = true;
|
||||||
|
}
|
||||||
limit->last = ktime_get_ns();
|
limit->last = ktime_get_ns();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -86,13 +93,15 @@ static int nft_limit_init(struct nft_limit *limit,
|
||||||
static int nft_limit_dump(struct sk_buff *skb, const struct nft_limit *limit,
|
static int nft_limit_dump(struct sk_buff *skb, const struct nft_limit *limit,
|
||||||
enum nft_limit_type type)
|
enum nft_limit_type type)
|
||||||
{
|
{
|
||||||
|
u32 flags = limit->invert ? NFT_LIMIT_F_INV : 0;
|
||||||
u64 secs = div_u64(limit->nsecs, NSEC_PER_SEC);
|
u64 secs = div_u64(limit->nsecs, NSEC_PER_SEC);
|
||||||
u64 rate = limit->rate - limit->burst;
|
u64 rate = limit->rate - limit->burst;
|
||||||
|
|
||||||
if (nla_put_be64(skb, NFTA_LIMIT_RATE, cpu_to_be64(rate)) ||
|
if (nla_put_be64(skb, NFTA_LIMIT_RATE, cpu_to_be64(rate)) ||
|
||||||
nla_put_be64(skb, NFTA_LIMIT_UNIT, cpu_to_be64(secs)) ||
|
nla_put_be64(skb, NFTA_LIMIT_UNIT, cpu_to_be64(secs)) ||
|
||||||
nla_put_be32(skb, NFTA_LIMIT_BURST, htonl(limit->burst)) ||
|
nla_put_be32(skb, NFTA_LIMIT_BURST, htonl(limit->burst)) ||
|
||||||
nla_put_be32(skb, NFTA_LIMIT_TYPE, htonl(type)))
|
nla_put_be32(skb, NFTA_LIMIT_TYPE, htonl(type)) ||
|
||||||
|
nla_put_be32(skb, NFTA_LIMIT_FLAGS, htonl(flags)))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -120,6 +129,7 @@ static const struct nla_policy nft_limit_policy[NFTA_LIMIT_MAX + 1] = {
|
||||||
[NFTA_LIMIT_UNIT] = { .type = NLA_U64 },
|
[NFTA_LIMIT_UNIT] = { .type = NLA_U64 },
|
||||||
[NFTA_LIMIT_BURST] = { .type = NLA_U32 },
|
[NFTA_LIMIT_BURST] = { .type = NLA_U32 },
|
||||||
[NFTA_LIMIT_TYPE] = { .type = NLA_U32 },
|
[NFTA_LIMIT_TYPE] = { .type = NLA_U32 },
|
||||||
|
[NFTA_LIMIT_FLAGS] = { .type = NLA_U32 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int nft_limit_pkts_init(const struct nft_ctx *ctx,
|
static int nft_limit_pkts_init(const struct nft_ctx *ctx,
|
||||||
|
|
|
@ -61,8 +61,8 @@ static const struct nla_policy xt_osf_policy[OSF_ATTR_MAX + 1] = {
|
||||||
[OSF_ATTR_FINGER] = { .len = sizeof(struct xt_osf_user_finger) },
|
[OSF_ATTR_FINGER] = { .len = sizeof(struct xt_osf_user_finger) },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int xt_osf_add_callback(struct sock *ctnl, struct sk_buff *skb,
|
static int xt_osf_add_callback(struct net *net, struct sock *ctnl,
|
||||||
const struct nlmsghdr *nlh,
|
struct sk_buff *skb, const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const osf_attrs[])
|
const struct nlattr * const osf_attrs[])
|
||||||
{
|
{
|
||||||
struct xt_osf_user_finger *f;
|
struct xt_osf_user_finger *f;
|
||||||
|
@ -104,7 +104,8 @@ static int xt_osf_add_callback(struct sock *ctnl, struct sk_buff *skb,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xt_osf_remove_callback(struct sock *ctnl, struct sk_buff *skb,
|
static int xt_osf_remove_callback(struct net *net, struct sock *ctnl,
|
||||||
|
struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
const struct nlattr * const osf_attrs[])
|
const struct nlattr * const osf_attrs[])
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue