netfilter: nf_tables: build-in filter chain type
One module per supported filter chain family type takes too much memory for very little code - too much modularization - place all chain filter definitions in one single file. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
cc07eeb0e5
commit
02c7b25e5f
17 changed files with 414 additions and 509 deletions
|
@ -1345,4 +1345,7 @@ struct nft_trans_flowtable {
|
|||
#define nft_trans_flowtable(trans) \
|
||||
(((struct nft_trans_flowtable *)trans->data)->flowtable)
|
||||
|
||||
int __init nft_chain_filter_init(void);
|
||||
void __exit nft_chain_filter_fini(void);
|
||||
|
||||
#endif /* _NET_NF_TABLES_H */
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
menuconfig NF_TABLES_BRIDGE
|
||||
depends on BRIDGE && NETFILTER && NF_TABLES
|
||||
select NETFILTER_FAMILY_BRIDGE
|
||||
tristate "Ethernet Bridge nf_tables support"
|
||||
bool "Ethernet Bridge nf_tables support"
|
||||
|
||||
if NF_TABLES_BRIDGE
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
# Makefile for the netfilter modules for Link Layer filtering on a bridge.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_NF_TABLES_BRIDGE) += nf_tables_bridge.o
|
||||
obj-$(CONFIG_NFT_BRIDGE_META) += nft_meta_bridge.o
|
||||
obj-$(CONFIG_NFT_BRIDGE_REJECT) += nft_reject_bridge.o
|
||||
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
|
||||
* Copyright (c) 2013 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.
|
||||
*
|
||||
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netfilter_bridge.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <net/netfilter/nf_tables_ipv4.h>
|
||||
#include <net/netfilter/nf_tables_ipv6.h>
|
||||
|
||||
static unsigned int
|
||||
nft_do_chain_bridge(void *priv,
|
||||
struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
{
|
||||
struct nft_pktinfo pkt;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
|
||||
switch (eth_hdr(skb)->h_proto) {
|
||||
case htons(ETH_P_IP):
|
||||
nft_set_pktinfo_ipv4_validate(&pkt, skb);
|
||||
break;
|
||||
case htons(ETH_P_IPV6):
|
||||
nft_set_pktinfo_ipv6_validate(&pkt, skb);
|
||||
break;
|
||||
default:
|
||||
nft_set_pktinfo_unspec(&pkt, skb);
|
||||
break;
|
||||
}
|
||||
|
||||
return nft_do_chain(&pkt, priv);
|
||||
}
|
||||
|
||||
static const struct nft_chain_type filter_bridge = {
|
||||
.name = "filter",
|
||||
.type = NFT_CHAIN_T_DEFAULT,
|
||||
.family = NFPROTO_BRIDGE,
|
||||
.owner = THIS_MODULE,
|
||||
.hook_mask = (1 << NF_BR_PRE_ROUTING) |
|
||||
(1 << NF_BR_LOCAL_IN) |
|
||||
(1 << NF_BR_FORWARD) |
|
||||
(1 << NF_BR_LOCAL_OUT) |
|
||||
(1 << NF_BR_POST_ROUTING),
|
||||
.hooks = {
|
||||
[NF_BR_PRE_ROUTING] = nft_do_chain_bridge,
|
||||
[NF_BR_LOCAL_IN] = nft_do_chain_bridge,
|
||||
[NF_BR_FORWARD] = nft_do_chain_bridge,
|
||||
[NF_BR_LOCAL_OUT] = nft_do_chain_bridge,
|
||||
[NF_BR_POST_ROUTING] = nft_do_chain_bridge,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init nf_tables_bridge_init(void)
|
||||
{
|
||||
nft_register_chain_type(&filter_bridge);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit nf_tables_bridge_exit(void)
|
||||
{
|
||||
nft_unregister_chain_type(&filter_bridge);
|
||||
}
|
||||
|
||||
module_init(nf_tables_bridge_init);
|
||||
module_exit(nf_tables_bridge_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
||||
MODULE_ALIAS_NFT_CHAIN(AF_BRIDGE, "filter");
|
|
@ -34,7 +34,7 @@ config NF_SOCKET_IPV4
|
|||
if NF_TABLES
|
||||
|
||||
config NF_TABLES_IPV4
|
||||
tristate "IPv4 nf_tables support"
|
||||
bool "IPv4 nf_tables support"
|
||||
help
|
||||
This option enables the IPv4 support for nf_tables.
|
||||
|
||||
|
@ -71,7 +71,7 @@ config NFT_FIB_IPV4
|
|||
endif # NF_TABLES_IPV4
|
||||
|
||||
config NF_TABLES_ARP
|
||||
tristate "ARP nf_tables support"
|
||||
bool "ARP nf_tables support"
|
||||
select NETFILTER_FAMILY_ARP
|
||||
help
|
||||
This option enables the ARP support for nf_tables.
|
||||
|
|
|
@ -39,7 +39,6 @@ obj-$(CONFIG_NF_NAT_MASQUERADE_IPV4) += nf_nat_masquerade_ipv4.o
|
|||
# NAT protocols (nf_nat)
|
||||
obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o
|
||||
|
||||
obj-$(CONFIG_NF_TABLES_IPV4) += nf_tables_ipv4.o
|
||||
obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV4) += nft_chain_route_ipv4.o
|
||||
obj-$(CONFIG_NFT_CHAIN_NAT_IPV4) += nft_chain_nat_ipv4.o
|
||||
obj-$(CONFIG_NFT_REJECT_IPV4) += nft_reject_ipv4.o
|
||||
|
@ -47,7 +46,6 @@ obj-$(CONFIG_NFT_FIB_IPV4) += nft_fib_ipv4.o
|
|||
obj-$(CONFIG_NFT_MASQ_IPV4) += nft_masq_ipv4.o
|
||||
obj-$(CONFIG_NFT_REDIR_IPV4) += nft_redir_ipv4.o
|
||||
obj-$(CONFIG_NFT_DUP_IPV4) += nft_dup_ipv4.o
|
||||
obj-$(CONFIG_NF_TABLES_ARP) += nf_tables_arp.o
|
||||
|
||||
# flow table support
|
||||
obj-$(CONFIG_NF_FLOW_TABLE_IPV4) += nf_flow_table_ipv4.o
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2008-2010 Patrick McHardy <kaber@trash.net>
|
||||
* Copyright (c) 2013 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.
|
||||
*
|
||||
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/netfilter_arp.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
|
||||
static unsigned int
|
||||
nft_do_chain_arp(void *priv,
|
||||
struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
{
|
||||
struct nft_pktinfo pkt;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
nft_set_pktinfo_unspec(&pkt, skb);
|
||||
|
||||
return nft_do_chain(&pkt, priv);
|
||||
}
|
||||
|
||||
static const struct nft_chain_type filter_arp = {
|
||||
.name = "filter",
|
||||
.type = NFT_CHAIN_T_DEFAULT,
|
||||
.family = NFPROTO_ARP,
|
||||
.owner = THIS_MODULE,
|
||||
.hook_mask = (1 << NF_ARP_IN) |
|
||||
(1 << NF_ARP_OUT),
|
||||
.hooks = {
|
||||
[NF_ARP_IN] = nft_do_chain_arp,
|
||||
[NF_ARP_OUT] = nft_do_chain_arp,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init nf_tables_arp_init(void)
|
||||
{
|
||||
nft_register_chain_type(&filter_arp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit nf_tables_arp_exit(void)
|
||||
{
|
||||
nft_unregister_chain_type(&filter_arp);
|
||||
}
|
||||
|
||||
module_init(nf_tables_arp_init);
|
||||
module_exit(nf_tables_arp_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
||||
MODULE_ALIAS_NFT_CHAIN(3, "filter"); /* NFPROTO_ARP */
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
|
||||
* Copyright (c) 2012-2013 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.
|
||||
*
|
||||
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/netfilter/nf_tables_ipv4.h>
|
||||
|
||||
static unsigned int nft_do_chain_ipv4(void *priv,
|
||||
struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
{
|
||||
struct nft_pktinfo pkt;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
nft_set_pktinfo_ipv4(&pkt, skb);
|
||||
|
||||
return nft_do_chain(&pkt, priv);
|
||||
}
|
||||
|
||||
static const struct nft_chain_type filter_ipv4 = {
|
||||
.name = "filter",
|
||||
.type = NFT_CHAIN_T_DEFAULT,
|
||||
.family = NFPROTO_IPV4,
|
||||
.owner = THIS_MODULE,
|
||||
.hook_mask = (1 << NF_INET_LOCAL_IN) |
|
||||
(1 << NF_INET_LOCAL_OUT) |
|
||||
(1 << NF_INET_FORWARD) |
|
||||
(1 << NF_INET_PRE_ROUTING) |
|
||||
(1 << NF_INET_POST_ROUTING),
|
||||
.hooks = {
|
||||
[NF_INET_LOCAL_IN] = nft_do_chain_ipv4,
|
||||
[NF_INET_LOCAL_OUT] = nft_do_chain_ipv4,
|
||||
[NF_INET_FORWARD] = nft_do_chain_ipv4,
|
||||
[NF_INET_PRE_ROUTING] = nft_do_chain_ipv4,
|
||||
[NF_INET_POST_ROUTING] = nft_do_chain_ipv4,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init nf_tables_ipv4_init(void)
|
||||
{
|
||||
nft_register_chain_type(&filter_ipv4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit nf_tables_ipv4_exit(void)
|
||||
{
|
||||
nft_unregister_chain_type(&filter_ipv4);
|
||||
}
|
||||
|
||||
module_init(nf_tables_ipv4_init);
|
||||
module_exit(nf_tables_ipv4_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
||||
MODULE_ALIAS_NFT_CHAIN(AF_INET, "filter");
|
|
@ -34,7 +34,7 @@ config NF_SOCKET_IPV6
|
|||
if NF_TABLES
|
||||
|
||||
config NF_TABLES_IPV6
|
||||
tristate "IPv6 nf_tables support"
|
||||
bool "IPv6 nf_tables support"
|
||||
help
|
||||
This option enables the IPv6 support for nf_tables.
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@ obj-$(CONFIG_NF_REJECT_IPV6) += nf_reject_ipv6.o
|
|||
obj-$(CONFIG_NF_DUP_IPV6) += nf_dup_ipv6.o
|
||||
|
||||
# nf_tables
|
||||
obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o
|
||||
obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o
|
||||
obj-$(CONFIG_NFT_CHAIN_NAT_IPV6) += nft_chain_nat_ipv6.o
|
||||
obj-$(CONFIG_NFT_REJECT_IPV6) += nft_reject_ipv6.o
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
|
||||
* Copyright (c) 2012-2013 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.
|
||||
*
|
||||
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/netfilter_ipv6.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
#include <net/netfilter/nf_tables_ipv6.h>
|
||||
|
||||
static unsigned int nft_do_chain_ipv6(void *priv,
|
||||
struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
{
|
||||
struct nft_pktinfo pkt;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
nft_set_pktinfo_ipv6(&pkt, skb);
|
||||
|
||||
return nft_do_chain(&pkt, priv);
|
||||
}
|
||||
|
||||
static const struct nft_chain_type filter_ipv6 = {
|
||||
.name = "filter",
|
||||
.type = NFT_CHAIN_T_DEFAULT,
|
||||
.family = NFPROTO_IPV6,
|
||||
.owner = THIS_MODULE,
|
||||
.hook_mask = (1 << NF_INET_LOCAL_IN) |
|
||||
(1 << NF_INET_LOCAL_OUT) |
|
||||
(1 << NF_INET_FORWARD) |
|
||||
(1 << NF_INET_PRE_ROUTING) |
|
||||
(1 << NF_INET_POST_ROUTING),
|
||||
.hooks = {
|
||||
[NF_INET_LOCAL_IN] = nft_do_chain_ipv6,
|
||||
[NF_INET_LOCAL_OUT] = nft_do_chain_ipv6,
|
||||
[NF_INET_FORWARD] = nft_do_chain_ipv6,
|
||||
[NF_INET_PRE_ROUTING] = nft_do_chain_ipv6,
|
||||
[NF_INET_POST_ROUTING] = nft_do_chain_ipv6,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init nf_tables_ipv6_init(void)
|
||||
{
|
||||
nft_register_chain_type(&filter_ipv6);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit nf_tables_ipv6_exit(void)
|
||||
{
|
||||
nft_unregister_chain_type(&filter_ipv6);
|
||||
}
|
||||
|
||||
module_init(nf_tables_ipv6_init);
|
||||
module_exit(nf_tables_ipv6_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
||||
MODULE_ALIAS_NFT_CHAIN(AF_INET6, "filter");
|
|
@ -465,12 +465,12 @@ config NF_TABLES_INET
|
|||
depends on IPV6
|
||||
select NF_TABLES_IPV4
|
||||
select NF_TABLES_IPV6
|
||||
tristate "Netfilter nf_tables mixed IPv4/IPv6 tables support"
|
||||
bool "Netfilter nf_tables mixed IPv4/IPv6 tables support"
|
||||
help
|
||||
This option enables support for a mixed IPv4/IPv6 "inet" table.
|
||||
|
||||
config NF_TABLES_NETDEV
|
||||
tristate "Netfilter nf_tables netdev tables support"
|
||||
bool "Netfilter nf_tables netdev tables support"
|
||||
help
|
||||
This option enables support for the "netdev" table.
|
||||
|
||||
|
|
|
@ -73,13 +73,12 @@ obj-$(CONFIG_NETFILTER_CONNCOUNT) += nf_conncount.o
|
|||
obj-$(CONFIG_NF_DUP_NETDEV) += nf_dup_netdev.o
|
||||
|
||||
# nf_tables
|
||||
nf_tables-objs := nf_tables_core.o nf_tables_api.o nf_tables_trace.o \
|
||||
nft_immediate.o nft_cmp.o nft_range.o nft_bitwise.o \
|
||||
nft_byteorder.o nft_payload.o nft_lookup.o nft_dynset.o
|
||||
nf_tables-objs := nf_tables_core.o nf_tables_api.o nft_chain_filter.o \
|
||||
nf_tables_trace.o nft_immediate.o nft_cmp.o nft_range.o \
|
||||
nft_bitwise.o nft_byteorder.o nft_payload.o nft_lookup.o \
|
||||
nft_dynset.o
|
||||
|
||||
obj-$(CONFIG_NF_TABLES) += nf_tables.o
|
||||
obj-$(CONFIG_NF_TABLES_INET) += nf_tables_inet.o
|
||||
obj-$(CONFIG_NF_TABLES_NETDEV) += nf_tables_netdev.o
|
||||
obj-$(CONFIG_NFT_COMPAT) += nft_compat.o
|
||||
obj-$(CONFIG_NFT_EXTHDR) += nft_exthdr.o
|
||||
obj-$(CONFIG_NFT_META) += nft_meta.o
|
||||
|
|
|
@ -6584,6 +6584,8 @@ static int __init nf_tables_module_init(void)
|
|||
{
|
||||
int err;
|
||||
|
||||
nft_chain_filter_init();
|
||||
|
||||
info = kmalloc(sizeof(struct nft_expr_info) * NFT_RULE_MAXEXPRS,
|
||||
GFP_KERNEL);
|
||||
if (info == NULL) {
|
||||
|
@ -6618,6 +6620,7 @@ static void __exit nf_tables_module_exit(void)
|
|||
rcu_barrier();
|
||||
nf_tables_core_module_exit();
|
||||
kfree(info);
|
||||
nft_chain_filter_fini();
|
||||
}
|
||||
|
||||
module_init(nf_tables_module_init);
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2014 Patrick McHardy <kaber@trash.net>
|
||||
*
|
||||
* 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/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter_ipv6.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
#include <net/netfilter/nf_tables_ipv4.h>
|
||||
#include <net/netfilter/nf_tables_ipv6.h>
|
||||
#include <net/ip.h>
|
||||
|
||||
static unsigned int nft_do_chain_inet(void *priv, struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
{
|
||||
struct nft_pktinfo pkt;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
|
||||
switch (state->pf) {
|
||||
case NFPROTO_IPV4:
|
||||
nft_set_pktinfo_ipv4(&pkt, skb);
|
||||
break;
|
||||
case NFPROTO_IPV6:
|
||||
nft_set_pktinfo_ipv6(&pkt, skb);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return nft_do_chain(&pkt, priv);
|
||||
}
|
||||
|
||||
static const struct nft_chain_type filter_inet = {
|
||||
.name = "filter",
|
||||
.type = NFT_CHAIN_T_DEFAULT,
|
||||
.family = NFPROTO_INET,
|
||||
.owner = THIS_MODULE,
|
||||
.hook_mask = (1 << NF_INET_LOCAL_IN) |
|
||||
(1 << NF_INET_LOCAL_OUT) |
|
||||
(1 << NF_INET_FORWARD) |
|
||||
(1 << NF_INET_PRE_ROUTING) |
|
||||
(1 << NF_INET_POST_ROUTING),
|
||||
.hooks = {
|
||||
[NF_INET_LOCAL_IN] = nft_do_chain_inet,
|
||||
[NF_INET_LOCAL_OUT] = nft_do_chain_inet,
|
||||
[NF_INET_FORWARD] = nft_do_chain_inet,
|
||||
[NF_INET_PRE_ROUTING] = nft_do_chain_inet,
|
||||
[NF_INET_POST_ROUTING] = nft_do_chain_inet,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init nf_tables_inet_init(void)
|
||||
{
|
||||
nft_register_chain_type(&filter_inet);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit nf_tables_inet_exit(void)
|
||||
{
|
||||
nft_unregister_chain_type(&filter_inet);
|
||||
}
|
||||
|
||||
module_init(nf_tables_inet_init);
|
||||
module_exit(nf_tables_inet_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
||||
MODULE_ALIAS_NFT_CHAIN(1, "filter");
|
|
@ -1,140 +0,0 @@
|
|||
/*
|
||||
* 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/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <net/netfilter/nf_tables_ipv4.h>
|
||||
#include <net/netfilter/nf_tables_ipv6.h>
|
||||
|
||||
static unsigned int
|
||||
nft_do_chain_netdev(void *priv, struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
{
|
||||
struct nft_pktinfo pkt;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
|
||||
switch (skb->protocol) {
|
||||
case htons(ETH_P_IP):
|
||||
nft_set_pktinfo_ipv4_validate(&pkt, skb);
|
||||
break;
|
||||
case htons(ETH_P_IPV6):
|
||||
nft_set_pktinfo_ipv6_validate(&pkt, skb);
|
||||
break;
|
||||
default:
|
||||
nft_set_pktinfo_unspec(&pkt, skb);
|
||||
break;
|
||||
}
|
||||
|
||||
return nft_do_chain(&pkt, priv);
|
||||
}
|
||||
|
||||
static const struct nft_chain_type nft_filter_chain_netdev = {
|
||||
.name = "filter",
|
||||
.type = NFT_CHAIN_T_DEFAULT,
|
||||
.family = NFPROTO_NETDEV,
|
||||
.owner = THIS_MODULE,
|
||||
.hook_mask = (1 << NF_NETDEV_INGRESS),
|
||||
.hooks = {
|
||||
[NF_NETDEV_INGRESS] = nft_do_chain_netdev,
|
||||
},
|
||||
};
|
||||
|
||||
static void nft_netdev_event(unsigned long event, struct net_device *dev,
|
||||
struct nft_ctx *ctx)
|
||||
{
|
||||
struct nft_base_chain *basechain = nft_base_chain(ctx->chain);
|
||||
|
||||
switch (event) {
|
||||
case NETDEV_UNREGISTER:
|
||||
if (strcmp(basechain->dev_name, dev->name) != 0)
|
||||
return;
|
||||
|
||||
__nft_release_basechain(ctx);
|
||||
break;
|
||||
case NETDEV_CHANGENAME:
|
||||
if (dev->ifindex != basechain->ops.dev->ifindex)
|
||||
return;
|
||||
|
||||
strncpy(basechain->dev_name, dev->name, IFNAMSIZ);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int nf_tables_netdev_event(struct notifier_block *this,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
||||
struct nft_table *table;
|
||||
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);
|
||||
list_for_each_entry(table, &ctx.net->nft.tables, list) {
|
||||
if (table->family != NFPROTO_NETDEV)
|
||||
continue;
|
||||
|
||||
ctx.family = table->family;
|
||||
ctx.table = table;
|
||||
list_for_each_entry_safe(chain, nr, &table->chains, list) {
|
||||
if (!nft_is_base_chain(chain))
|
||||
continue;
|
||||
|
||||
ctx.chain = chain;
|
||||
nft_netdev_event(event, dev, &ctx);
|
||||
}
|
||||
}
|
||||
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct notifier_block nf_tables_netdev_notifier = {
|
||||
.notifier_call = nf_tables_netdev_event,
|
||||
};
|
||||
|
||||
static int __init nf_tables_netdev_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
nft_register_chain_type(&nft_filter_chain_netdev);
|
||||
|
||||
ret = register_netdevice_notifier(&nf_tables_netdev_notifier);
|
||||
if (ret)
|
||||
goto err_register_netdevice_notifier;
|
||||
|
||||
return 0;
|
||||
|
||||
err_register_netdevice_notifier:
|
||||
nft_unregister_chain_type(&nft_filter_chain_netdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit nf_tables_netdev_exit(void)
|
||||
{
|
||||
unregister_netdevice_notifier(&nf_tables_netdev_notifier);
|
||||
nft_unregister_chain_type(&nft_filter_chain_netdev);
|
||||
}
|
||||
|
||||
module_init(nf_tables_netdev_init);
|
||||
module_exit(nf_tables_netdev_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
|
||||
MODULE_ALIAS_NFT_CHAIN(5, "filter"); /* NFPROTO_NETDEV */
|
398
net/netfilter/nft_chain_filter.c
Normal file
398
net/netfilter/nft_chain_filter.c
Normal file
|
@ -0,0 +1,398 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter_ipv6.h>
|
||||
#include <linux/netfilter_bridge.h>
|
||||
#include <linux/netfilter_arp.h>
|
||||
#include <net/netfilter/nf_tables_ipv4.h>
|
||||
#include <net/netfilter/nf_tables_ipv6.h>
|
||||
|
||||
#ifdef CONFIG_NF_TABLES_IPV4
|
||||
static unsigned int nft_do_chain_ipv4(void *priv,
|
||||
struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
{
|
||||
struct nft_pktinfo pkt;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
nft_set_pktinfo_ipv4(&pkt, skb);
|
||||
|
||||
return nft_do_chain(&pkt, priv);
|
||||
}
|
||||
|
||||
static const struct nft_chain_type nft_chain_filter_ipv4 = {
|
||||
.name = "filter",
|
||||
.type = NFT_CHAIN_T_DEFAULT,
|
||||
.family = NFPROTO_IPV4,
|
||||
.hook_mask = (1 << NF_INET_LOCAL_IN) |
|
||||
(1 << NF_INET_LOCAL_OUT) |
|
||||
(1 << NF_INET_FORWARD) |
|
||||
(1 << NF_INET_PRE_ROUTING) |
|
||||
(1 << NF_INET_POST_ROUTING),
|
||||
.hooks = {
|
||||
[NF_INET_LOCAL_IN] = nft_do_chain_ipv4,
|
||||
[NF_INET_LOCAL_OUT] = nft_do_chain_ipv4,
|
||||
[NF_INET_FORWARD] = nft_do_chain_ipv4,
|
||||
[NF_INET_PRE_ROUTING] = nft_do_chain_ipv4,
|
||||
[NF_INET_POST_ROUTING] = nft_do_chain_ipv4,
|
||||
},
|
||||
};
|
||||
|
||||
static void nft_chain_filter_ipv4_init(void)
|
||||
{
|
||||
nft_register_chain_type(&nft_chain_filter_ipv4);
|
||||
}
|
||||
static void nft_chain_filter_ipv4_fini(void)
|
||||
{
|
||||
nft_unregister_chain_type(&nft_chain_filter_ipv4);
|
||||
}
|
||||
|
||||
#else
|
||||
static inline void nft_chain_filter_ipv4_init(void) {}
|
||||
static inline void nft_chain_filter_ipv4_fini(void) {}
|
||||
#endif /* CONFIG_NF_TABLES_IPV4 */
|
||||
|
||||
#ifdef CONFIG_NF_TABLES_ARP
|
||||
static unsigned int nft_do_chain_arp(void *priv, struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
{
|
||||
struct nft_pktinfo pkt;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
nft_set_pktinfo_unspec(&pkt, skb);
|
||||
|
||||
return nft_do_chain(&pkt, priv);
|
||||
}
|
||||
|
||||
static const struct nft_chain_type nft_chain_filter_arp = {
|
||||
.name = "filter",
|
||||
.type = NFT_CHAIN_T_DEFAULT,
|
||||
.family = NFPROTO_ARP,
|
||||
.owner = THIS_MODULE,
|
||||
.hook_mask = (1 << NF_ARP_IN) |
|
||||
(1 << NF_ARP_OUT),
|
||||
.hooks = {
|
||||
[NF_ARP_IN] = nft_do_chain_arp,
|
||||
[NF_ARP_OUT] = nft_do_chain_arp,
|
||||
},
|
||||
};
|
||||
|
||||
static void nft_chain_filter_arp_init(void)
|
||||
{
|
||||
nft_register_chain_type(&nft_chain_filter_arp);
|
||||
}
|
||||
|
||||
static void nft_chain_filter_arp_fini(void)
|
||||
{
|
||||
nft_unregister_chain_type(&nft_chain_filter_arp);
|
||||
}
|
||||
#else
|
||||
static inline void nft_chain_filter_arp_init(void) {}
|
||||
static inline void nft_chain_filter_arp_fini(void) {}
|
||||
#endif /* CONFIG_NF_TABLES_ARP */
|
||||
|
||||
#ifdef CONFIG_NF_TABLES_IPV6
|
||||
static unsigned int nft_do_chain_ipv6(void *priv,
|
||||
struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
{
|
||||
struct nft_pktinfo pkt;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
nft_set_pktinfo_ipv6(&pkt, skb);
|
||||
|
||||
return nft_do_chain(&pkt, priv);
|
||||
}
|
||||
|
||||
static const struct nft_chain_type nft_chain_filter_ipv6 = {
|
||||
.name = "filter",
|
||||
.type = NFT_CHAIN_T_DEFAULT,
|
||||
.family = NFPROTO_IPV6,
|
||||
.hook_mask = (1 << NF_INET_LOCAL_IN) |
|
||||
(1 << NF_INET_LOCAL_OUT) |
|
||||
(1 << NF_INET_FORWARD) |
|
||||
(1 << NF_INET_PRE_ROUTING) |
|
||||
(1 << NF_INET_POST_ROUTING),
|
||||
.hooks = {
|
||||
[NF_INET_LOCAL_IN] = nft_do_chain_ipv6,
|
||||
[NF_INET_LOCAL_OUT] = nft_do_chain_ipv6,
|
||||
[NF_INET_FORWARD] = nft_do_chain_ipv6,
|
||||
[NF_INET_PRE_ROUTING] = nft_do_chain_ipv6,
|
||||
[NF_INET_POST_ROUTING] = nft_do_chain_ipv6,
|
||||
},
|
||||
};
|
||||
|
||||
static void nft_chain_filter_ipv6_init(void)
|
||||
{
|
||||
nft_register_chain_type(&nft_chain_filter_ipv6);
|
||||
}
|
||||
|
||||
static void nft_chain_filter_ipv6_fini(void)
|
||||
{
|
||||
nft_unregister_chain_type(&nft_chain_filter_ipv6);
|
||||
}
|
||||
#else
|
||||
static inline void nft_chain_filter_ipv6_init(void) {}
|
||||
static inline void nft_chain_filter_ipv6_fini(void) {}
|
||||
#endif /* CONFIG_NF_TABLES_IPV6 */
|
||||
|
||||
#ifdef CONFIG_NF_TABLES_INET
|
||||
static unsigned int nft_do_chain_inet(void *priv, struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
{
|
||||
struct nft_pktinfo pkt;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
|
||||
switch (state->pf) {
|
||||
case NFPROTO_IPV4:
|
||||
nft_set_pktinfo_ipv4(&pkt, skb);
|
||||
break;
|
||||
case NFPROTO_IPV6:
|
||||
nft_set_pktinfo_ipv6(&pkt, skb);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return nft_do_chain(&pkt, priv);
|
||||
}
|
||||
|
||||
static const struct nft_chain_type nft_chain_filter_inet = {
|
||||
.name = "filter",
|
||||
.type = NFT_CHAIN_T_DEFAULT,
|
||||
.family = NFPROTO_INET,
|
||||
.hook_mask = (1 << NF_INET_LOCAL_IN) |
|
||||
(1 << NF_INET_LOCAL_OUT) |
|
||||
(1 << NF_INET_FORWARD) |
|
||||
(1 << NF_INET_PRE_ROUTING) |
|
||||
(1 << NF_INET_POST_ROUTING),
|
||||
.hooks = {
|
||||
[NF_INET_LOCAL_IN] = nft_do_chain_inet,
|
||||
[NF_INET_LOCAL_OUT] = nft_do_chain_inet,
|
||||
[NF_INET_FORWARD] = nft_do_chain_inet,
|
||||
[NF_INET_PRE_ROUTING] = nft_do_chain_inet,
|
||||
[NF_INET_POST_ROUTING] = nft_do_chain_inet,
|
||||
},
|
||||
};
|
||||
|
||||
static void nft_chain_filter_inet_init(void)
|
||||
{
|
||||
nft_register_chain_type(&nft_chain_filter_inet);
|
||||
}
|
||||
|
||||
static void nft_chain_filter_inet_fini(void)
|
||||
{
|
||||
nft_unregister_chain_type(&nft_chain_filter_inet);
|
||||
}
|
||||
#else
|
||||
static inline void nft_chain_filter_inet_init(void) {}
|
||||
static inline void nft_chain_filter_inet_fini(void) {}
|
||||
#endif /* CONFIG_NF_TABLES_IPV6 */
|
||||
|
||||
#ifdef CONFIG_NF_TABLES_BRIDGE
|
||||
static unsigned int
|
||||
nft_do_chain_bridge(void *priv,
|
||||
struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
{
|
||||
struct nft_pktinfo pkt;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
|
||||
switch (eth_hdr(skb)->h_proto) {
|
||||
case htons(ETH_P_IP):
|
||||
nft_set_pktinfo_ipv4_validate(&pkt, skb);
|
||||
break;
|
||||
case htons(ETH_P_IPV6):
|
||||
nft_set_pktinfo_ipv6_validate(&pkt, skb);
|
||||
break;
|
||||
default:
|
||||
nft_set_pktinfo_unspec(&pkt, skb);
|
||||
break;
|
||||
}
|
||||
|
||||
return nft_do_chain(&pkt, priv);
|
||||
}
|
||||
|
||||
static const struct nft_chain_type nft_chain_filter_bridge = {
|
||||
.name = "filter",
|
||||
.type = NFT_CHAIN_T_DEFAULT,
|
||||
.family = NFPROTO_BRIDGE,
|
||||
.hook_mask = (1 << NF_BR_PRE_ROUTING) |
|
||||
(1 << NF_BR_LOCAL_IN) |
|
||||
(1 << NF_BR_FORWARD) |
|
||||
(1 << NF_BR_LOCAL_OUT) |
|
||||
(1 << NF_BR_POST_ROUTING),
|
||||
.hooks = {
|
||||
[NF_BR_PRE_ROUTING] = nft_do_chain_bridge,
|
||||
[NF_BR_LOCAL_IN] = nft_do_chain_bridge,
|
||||
[NF_BR_FORWARD] = nft_do_chain_bridge,
|
||||
[NF_BR_LOCAL_OUT] = nft_do_chain_bridge,
|
||||
[NF_BR_POST_ROUTING] = nft_do_chain_bridge,
|
||||
},
|
||||
};
|
||||
|
||||
static void nft_chain_filter_bridge_init(void)
|
||||
{
|
||||
nft_register_chain_type(&nft_chain_filter_bridge);
|
||||
}
|
||||
|
||||
static void nft_chain_filter_bridge_fini(void)
|
||||
{
|
||||
nft_unregister_chain_type(&nft_chain_filter_bridge);
|
||||
}
|
||||
#else
|
||||
static inline void nft_chain_filter_bridge_init(void) {}
|
||||
static inline void nft_chain_filter_bridge_fini(void) {}
|
||||
#endif /* CONFIG_NF_TABLES_BRIDGE */
|
||||
|
||||
#ifdef CONFIG_NF_TABLES_NETDEV
|
||||
static unsigned int nft_do_chain_netdev(void *priv, struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
{
|
||||
struct nft_pktinfo pkt;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
|
||||
switch (skb->protocol) {
|
||||
case htons(ETH_P_IP):
|
||||
nft_set_pktinfo_ipv4_validate(&pkt, skb);
|
||||
break;
|
||||
case htons(ETH_P_IPV6):
|
||||
nft_set_pktinfo_ipv6_validate(&pkt, skb);
|
||||
break;
|
||||
default:
|
||||
nft_set_pktinfo_unspec(&pkt, skb);
|
||||
break;
|
||||
}
|
||||
|
||||
return nft_do_chain(&pkt, priv);
|
||||
}
|
||||
|
||||
static const struct nft_chain_type nft_chain_filter_netdev = {
|
||||
.name = "filter",
|
||||
.type = NFT_CHAIN_T_DEFAULT,
|
||||
.family = NFPROTO_NETDEV,
|
||||
.hook_mask = (1 << NF_NETDEV_INGRESS),
|
||||
.hooks = {
|
||||
[NF_NETDEV_INGRESS] = nft_do_chain_netdev,
|
||||
},
|
||||
};
|
||||
|
||||
static void nft_netdev_event(unsigned long event, struct net_device *dev,
|
||||
struct nft_ctx *ctx)
|
||||
{
|
||||
struct nft_base_chain *basechain = nft_base_chain(ctx->chain);
|
||||
|
||||
switch (event) {
|
||||
case NETDEV_UNREGISTER:
|
||||
if (strcmp(basechain->dev_name, dev->name) != 0)
|
||||
return;
|
||||
|
||||
__nft_release_basechain(ctx);
|
||||
break;
|
||||
case NETDEV_CHANGENAME:
|
||||
if (dev->ifindex != basechain->ops.dev->ifindex)
|
||||
return;
|
||||
|
||||
strncpy(basechain->dev_name, dev->name, IFNAMSIZ);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int nf_tables_netdev_event(struct notifier_block *this,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
||||
struct nft_table *table;
|
||||
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);
|
||||
list_for_each_entry(table, &ctx.net->nft.tables, list) {
|
||||
if (table->family != NFPROTO_NETDEV)
|
||||
continue;
|
||||
|
||||
ctx.family = table->family;
|
||||
ctx.table = table;
|
||||
list_for_each_entry_safe(chain, nr, &table->chains, list) {
|
||||
if (!nft_is_base_chain(chain))
|
||||
continue;
|
||||
|
||||
ctx.chain = chain;
|
||||
nft_netdev_event(event, dev, &ctx);
|
||||
}
|
||||
}
|
||||
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct notifier_block nf_tables_netdev_notifier = {
|
||||
.notifier_call = nf_tables_netdev_event,
|
||||
};
|
||||
|
||||
static int nft_chain_filter_netdev_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
nft_register_chain_type(&nft_chain_filter_netdev);
|
||||
|
||||
err = register_netdevice_notifier(&nf_tables_netdev_notifier);
|
||||
if (err)
|
||||
goto err_register_netdevice_notifier;
|
||||
|
||||
return 0;
|
||||
|
||||
err_register_netdevice_notifier:
|
||||
nft_unregister_chain_type(&nft_chain_filter_netdev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void nft_chain_filter_netdev_fini(void)
|
||||
{
|
||||
nft_unregister_chain_type(&nft_chain_filter_netdev);
|
||||
unregister_netdevice_notifier(&nf_tables_netdev_notifier);
|
||||
}
|
||||
#else
|
||||
static inline int nft_chain_filter_netdev_init(void) { return 0; }
|
||||
static inline void nft_chain_filter_netdev_fini(void) {}
|
||||
#endif /* CONFIG_NF_TABLES_NETDEV */
|
||||
|
||||
int __init nft_chain_filter_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = nft_chain_filter_netdev_init();
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
nft_chain_filter_ipv4_init();
|
||||
nft_chain_filter_ipv6_init();
|
||||
nft_chain_filter_arp_init();
|
||||
nft_chain_filter_inet_init();
|
||||
nft_chain_filter_bridge_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit nft_chain_filter_fini(void)
|
||||
{
|
||||
nft_chain_filter_bridge_fini();
|
||||
nft_chain_filter_inet_fini();
|
||||
nft_chain_filter_arp_fini();
|
||||
nft_chain_filter_ipv6_fini();
|
||||
nft_chain_filter_ipv4_fini();
|
||||
nft_chain_filter_netdev_fini();
|
||||
}
|
Loading…
Reference in a new issue