Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Pablo Neira Ayuso says: ==================== Netfilter/IPVS fixes for net The following patchset contains Netfilter/IPVS fixes for your net tree: 1) Infinite loop in IPVS when net namespace is released, from Tan Hu. 2) Do not show negative timeouts in ip_vs_conn by using the new jiffies_delta_to_msecs(), patches from Matteo Croce. 3) Set F_IFACE flag for linklocal addresses in ip6t_rpfilter, from Florian Westphal. 4) Fix overflow in set size allocation, from Taehee Yoo. 5) Use netlink_dump_start() from ctnetlink to fix memleak from the error path, again from Florian. 6) Register nfnetlink_subsys in last place, otherwise netns init path may lose race and see net->nft uninitialized data. This also reverts previous attempt to fix this by increase netns refcount, patches from Florian. 7) Remove conntrack entries on layer 4 protocol tracker module removal, from Florian. 8) Use GFP_KERNEL_ACCOUNT for xtables blob allocation, from Michal Hocko. 9) Get tproxy documentation in sync with existing codebase, from Mate Eckl. 10) Honor preset layer 3 protocol via ctx->family in the new nft_ct timeout infrastructure, from Harsha Sharma. 11) Let uapi nfnetlink_osf.h compile standalone with no errors, from Dmitry V. Levin. 12) Missing braces compilation warning in nft_tproxy, patch from Mate Eclk. 13) Disregard bogus check to bail out on non-anonymous sets from the dynamic set update extension. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
3fe49d699a
|
@ -5,19 +5,28 @@ This feature adds Linux 2.2-like transparent proxy support to current kernels.
|
||||||
To use it, enable the socket match and the TPROXY target in your kernel config.
|
To use it, enable the socket match and the TPROXY target in your kernel config.
|
||||||
You will need policy routing too, so be sure to enable that as well.
|
You will need policy routing too, so be sure to enable that as well.
|
||||||
|
|
||||||
|
From Linux 4.18 transparent proxy support is also available in nf_tables.
|
||||||
|
|
||||||
1. Making non-local sockets work
|
1. Making non-local sockets work
|
||||||
================================
|
================================
|
||||||
|
|
||||||
The idea is that you identify packets with destination address matching a local
|
The idea is that you identify packets with destination address matching a local
|
||||||
socket on your box, set the packet mark to a certain value, and then match on that
|
socket on your box, set the packet mark to a certain value:
|
||||||
value using policy routing to have those packets delivered locally:
|
|
||||||
|
|
||||||
# iptables -t mangle -N DIVERT
|
# iptables -t mangle -N DIVERT
|
||||||
# iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT
|
# iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT
|
||||||
# iptables -t mangle -A DIVERT -j MARK --set-mark 1
|
# iptables -t mangle -A DIVERT -j MARK --set-mark 1
|
||||||
# iptables -t mangle -A DIVERT -j ACCEPT
|
# iptables -t mangle -A DIVERT -j ACCEPT
|
||||||
|
|
||||||
|
Alternatively you can do this in nft with the following commands:
|
||||||
|
|
||||||
|
# nft add table filter
|
||||||
|
# nft add chain filter divert "{ type filter hook prerouting priority -150; }"
|
||||||
|
# nft add rule filter divert meta l4proto tcp socket transparent 1 meta mark set 1 accept
|
||||||
|
|
||||||
|
And then match on that value using policy routing to have those packets
|
||||||
|
delivered locally:
|
||||||
|
|
||||||
# ip rule add fwmark 1 lookup 100
|
# ip rule add fwmark 1 lookup 100
|
||||||
# ip route add local 0.0.0.0/0 dev lo table 100
|
# ip route add local 0.0.0.0/0 dev lo table 100
|
||||||
|
|
||||||
|
@ -57,17 +66,28 @@ add rules like this to the iptables ruleset above:
|
||||||
# iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY \
|
# iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY \
|
||||||
--tproxy-mark 0x1/0x1 --on-port 50080
|
--tproxy-mark 0x1/0x1 --on-port 50080
|
||||||
|
|
||||||
|
Or the following rule to nft:
|
||||||
|
|
||||||
|
# nft add rule filter divert tcp dport 80 tproxy to :50080 meta mark set 1 accept
|
||||||
|
|
||||||
Note that for this to work you'll have to modify the proxy to enable (SOL_IP,
|
Note that for this to work you'll have to modify the proxy to enable (SOL_IP,
|
||||||
IP_TRANSPARENT) for the listening socket.
|
IP_TRANSPARENT) for the listening socket.
|
||||||
|
|
||||||
|
As an example implementation, tcprdr is available here:
|
||||||
|
https://git.breakpoint.cc/cgit/fw/tcprdr.git/
|
||||||
|
This tool is written by Florian Westphal and it was used for testing during the
|
||||||
|
nf_tables implementation.
|
||||||
|
|
||||||
3. Iptables extensions
|
3. Iptables and nf_tables extensions
|
||||||
======================
|
====================================
|
||||||
|
|
||||||
To use tproxy you'll need to have the 'socket' and 'TPROXY' modules
|
To use tproxy you'll need to have the following modules compiled for iptables:
|
||||||
compiled for iptables. A patched version of iptables is available
|
- NETFILTER_XT_MATCH_SOCKET
|
||||||
here: http://git.balabit.hu/?p=bazsi/iptables-tproxy.git
|
- NETFILTER_XT_TARGET_TPROXY
|
||||||
|
|
||||||
|
Or the floowing modules for nf_tables:
|
||||||
|
- NFT_SOCKET
|
||||||
|
- NFT_TPROXY
|
||||||
|
|
||||||
4. Application support
|
4. Application support
|
||||||
======================
|
======================
|
||||||
|
|
|
@ -447,6 +447,11 @@ static inline clock_t jiffies_delta_to_clock_t(long delta)
|
||||||
return jiffies_to_clock_t(max(0L, delta));
|
return jiffies_to_clock_t(max(0L, delta));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline unsigned int jiffies_delta_to_msecs(long delta)
|
||||||
|
{
|
||||||
|
return jiffies_to_msecs(max(0L, delta));
|
||||||
|
}
|
||||||
|
|
||||||
extern unsigned long clock_t_to_jiffies(unsigned long x);
|
extern unsigned long clock_t_to_jiffies(unsigned long x);
|
||||||
extern u64 jiffies_64_to_clock_t(u64 x);
|
extern u64 jiffies_64_to_clock_t(u64 x);
|
||||||
extern u64 nsec_to_clock_t(u64 x);
|
extern u64 nsec_to_clock_t(u64 x);
|
||||||
|
|
|
@ -274,7 +274,7 @@ enum nft_set_class {
|
||||||
* @space: memory class
|
* @space: memory class
|
||||||
*/
|
*/
|
||||||
struct nft_set_estimate {
|
struct nft_set_estimate {
|
||||||
unsigned int size;
|
u64 size;
|
||||||
enum nft_set_class lookup;
|
enum nft_set_class lookup;
|
||||||
enum nft_set_class space;
|
enum nft_set_class space;
|
||||||
};
|
};
|
||||||
|
@ -336,7 +336,7 @@ struct nft_set_ops {
|
||||||
const struct nft_set_elem *elem,
|
const struct nft_set_elem *elem,
|
||||||
unsigned int flags);
|
unsigned int flags);
|
||||||
|
|
||||||
unsigned int (*privsize)(const struct nlattr * const nla[],
|
u64 (*privsize)(const struct nlattr * const nla[],
|
||||||
const struct nft_set_desc *desc);
|
const struct nft_set_desc *desc);
|
||||||
bool (*estimate)(const struct nft_set_desc *desc,
|
bool (*estimate)(const struct nft_set_desc *desc,
|
||||||
u32 features,
|
u32 features,
|
||||||
|
@ -1374,6 +1374,6 @@ struct nft_trans_flowtable {
|
||||||
(((struct nft_trans_flowtable *)trans->data)->flowtable)
|
(((struct nft_trans_flowtable *)trans->data)->flowtable)
|
||||||
|
|
||||||
int __init nft_chain_filter_init(void);
|
int __init nft_chain_filter_init(void);
|
||||||
void __exit nft_chain_filter_fini(void);
|
void nft_chain_filter_fini(void);
|
||||||
|
|
||||||
#endif /* _NET_NF_TABLES_H */
|
#endif /* _NET_NF_TABLES_H */
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#define _NF_OSF_H
|
#define _NF_OSF_H
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
#include <linux/ip.h>
|
||||||
|
#include <linux/tcp.h>
|
||||||
|
|
||||||
#define MAXGENRELEN 32
|
#define MAXGENRELEN 32
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,6 @@
|
||||||
#define _XT_OSF_H
|
#define _XT_OSF_H
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/ip.h>
|
|
||||||
#include <linux/tcp.h>
|
|
||||||
#include <linux/netfilter/nfnetlink_osf.h>
|
#include <linux/netfilter/nfnetlink_osf.h>
|
||||||
|
|
||||||
#define XT_OSF_GENRE NF_OSF_GENRE
|
#define XT_OSF_GENRE NF_OSF_GENRE
|
||||||
|
|
|
@ -26,6 +26,12 @@ static bool rpfilter_addr_unicast(const struct in6_addr *addr)
|
||||||
return addr_type & IPV6_ADDR_UNICAST;
|
return addr_type & IPV6_ADDR_UNICAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool rpfilter_addr_linklocal(const struct in6_addr *addr)
|
||||||
|
{
|
||||||
|
int addr_type = ipv6_addr_type(addr);
|
||||||
|
return addr_type & IPV6_ADDR_LINKLOCAL;
|
||||||
|
}
|
||||||
|
|
||||||
static bool rpfilter_lookup_reverse6(struct net *net, const struct sk_buff *skb,
|
static bool rpfilter_lookup_reverse6(struct net *net, const struct sk_buff *skb,
|
||||||
const struct net_device *dev, u8 flags)
|
const struct net_device *dev, u8 flags)
|
||||||
{
|
{
|
||||||
|
@ -48,7 +54,11 @@ static bool rpfilter_lookup_reverse6(struct net *net, const struct sk_buff *skb,
|
||||||
}
|
}
|
||||||
|
|
||||||
fl6.flowi6_mark = flags & XT_RPFILTER_VALID_MARK ? skb->mark : 0;
|
fl6.flowi6_mark = flags & XT_RPFILTER_VALID_MARK ? skb->mark : 0;
|
||||||
if ((flags & XT_RPFILTER_LOOSE) == 0)
|
|
||||||
|
if (rpfilter_addr_linklocal(&iph->saddr)) {
|
||||||
|
lookup_flags |= RT6_LOOKUP_F_IFACE;
|
||||||
|
fl6.flowi6_oif = dev->ifindex;
|
||||||
|
} else if ((flags & XT_RPFILTER_LOOSE) == 0)
|
||||||
fl6.flowi6_oif = dev->ifindex;
|
fl6.flowi6_oif = dev->ifindex;
|
||||||
|
|
||||||
rt = (void *)ip6_route_lookup(net, &fl6, skb, lookup_flags);
|
rt = (void *)ip6_route_lookup(net, &fl6, skb, lookup_flags);
|
||||||
|
|
|
@ -1117,24 +1117,28 @@ static int ip_vs_conn_seq_show(struct seq_file *seq, void *v)
|
||||||
#ifdef CONFIG_IP_VS_IPV6
|
#ifdef CONFIG_IP_VS_IPV6
|
||||||
if (cp->af == AF_INET6)
|
if (cp->af == AF_INET6)
|
||||||
seq_printf(seq, "%-3s %pI6 %04X %pI6 %04X "
|
seq_printf(seq, "%-3s %pI6 %04X %pI6 %04X "
|
||||||
"%s %04X %-11s %7lu%s\n",
|
"%s %04X %-11s %7u%s\n",
|
||||||
ip_vs_proto_name(cp->protocol),
|
ip_vs_proto_name(cp->protocol),
|
||||||
&cp->caddr.in6, ntohs(cp->cport),
|
&cp->caddr.in6, ntohs(cp->cport),
|
||||||
&cp->vaddr.in6, ntohs(cp->vport),
|
&cp->vaddr.in6, ntohs(cp->vport),
|
||||||
dbuf, ntohs(cp->dport),
|
dbuf, ntohs(cp->dport),
|
||||||
ip_vs_state_name(cp),
|
ip_vs_state_name(cp),
|
||||||
(cp->timer.expires-jiffies)/HZ, pe_data);
|
jiffies_delta_to_msecs(cp->timer.expires -
|
||||||
|
jiffies) / 1000,
|
||||||
|
pe_data);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
seq_printf(seq,
|
seq_printf(seq,
|
||||||
"%-3s %08X %04X %08X %04X"
|
"%-3s %08X %04X %08X %04X"
|
||||||
" %s %04X %-11s %7lu%s\n",
|
" %s %04X %-11s %7u%s\n",
|
||||||
ip_vs_proto_name(cp->protocol),
|
ip_vs_proto_name(cp->protocol),
|
||||||
ntohl(cp->caddr.ip), ntohs(cp->cport),
|
ntohl(cp->caddr.ip), ntohs(cp->cport),
|
||||||
ntohl(cp->vaddr.ip), ntohs(cp->vport),
|
ntohl(cp->vaddr.ip), ntohs(cp->vport),
|
||||||
dbuf, ntohs(cp->dport),
|
dbuf, ntohs(cp->dport),
|
||||||
ip_vs_state_name(cp),
|
ip_vs_state_name(cp),
|
||||||
(cp->timer.expires-jiffies)/HZ, pe_data);
|
jiffies_delta_to_msecs(cp->timer.expires -
|
||||||
|
jiffies) / 1000,
|
||||||
|
pe_data);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1179,26 +1183,28 @@ static int ip_vs_conn_sync_seq_show(struct seq_file *seq, void *v)
|
||||||
#ifdef CONFIG_IP_VS_IPV6
|
#ifdef CONFIG_IP_VS_IPV6
|
||||||
if (cp->af == AF_INET6)
|
if (cp->af == AF_INET6)
|
||||||
seq_printf(seq, "%-3s %pI6 %04X %pI6 %04X "
|
seq_printf(seq, "%-3s %pI6 %04X %pI6 %04X "
|
||||||
"%s %04X %-11s %-6s %7lu\n",
|
"%s %04X %-11s %-6s %7u\n",
|
||||||
ip_vs_proto_name(cp->protocol),
|
ip_vs_proto_name(cp->protocol),
|
||||||
&cp->caddr.in6, ntohs(cp->cport),
|
&cp->caddr.in6, ntohs(cp->cport),
|
||||||
&cp->vaddr.in6, ntohs(cp->vport),
|
&cp->vaddr.in6, ntohs(cp->vport),
|
||||||
dbuf, ntohs(cp->dport),
|
dbuf, ntohs(cp->dport),
|
||||||
ip_vs_state_name(cp),
|
ip_vs_state_name(cp),
|
||||||
ip_vs_origin_name(cp->flags),
|
ip_vs_origin_name(cp->flags),
|
||||||
(cp->timer.expires-jiffies)/HZ);
|
jiffies_delta_to_msecs(cp->timer.expires -
|
||||||
|
jiffies) / 1000);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
seq_printf(seq,
|
seq_printf(seq,
|
||||||
"%-3s %08X %04X %08X %04X "
|
"%-3s %08X %04X %08X %04X "
|
||||||
"%s %04X %-11s %-6s %7lu\n",
|
"%s %04X %-11s %-6s %7u\n",
|
||||||
ip_vs_proto_name(cp->protocol),
|
ip_vs_proto_name(cp->protocol),
|
||||||
ntohl(cp->caddr.ip), ntohs(cp->cport),
|
ntohl(cp->caddr.ip), ntohs(cp->cport),
|
||||||
ntohl(cp->vaddr.ip), ntohs(cp->vport),
|
ntohl(cp->vaddr.ip), ntohs(cp->vport),
|
||||||
dbuf, ntohs(cp->dport),
|
dbuf, ntohs(cp->dport),
|
||||||
ip_vs_state_name(cp),
|
ip_vs_state_name(cp),
|
||||||
ip_vs_origin_name(cp->flags),
|
ip_vs_origin_name(cp->flags),
|
||||||
(cp->timer.expires-jiffies)/HZ);
|
jiffies_delta_to_msecs(cp->timer.expires -
|
||||||
|
jiffies) / 1000);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1972,13 +1972,20 @@ ip_vs_in(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int
|
||||||
if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) {
|
if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) {
|
||||||
/* the destination server is not available */
|
/* the destination server is not available */
|
||||||
|
|
||||||
if (sysctl_expire_nodest_conn(ipvs)) {
|
__u32 flags = cp->flags;
|
||||||
|
|
||||||
|
/* when timer already started, silently drop the packet.*/
|
||||||
|
if (timer_pending(&cp->timer))
|
||||||
|
__ip_vs_conn_put(cp);
|
||||||
|
else
|
||||||
|
ip_vs_conn_put(cp);
|
||||||
|
|
||||||
|
if (sysctl_expire_nodest_conn(ipvs) &&
|
||||||
|
!(flags & IP_VS_CONN_F_ONE_PACKET)) {
|
||||||
/* try to expire the connection immediately */
|
/* try to expire the connection immediately */
|
||||||
ip_vs_conn_expire_now(cp);
|
ip_vs_conn_expire_now(cp);
|
||||||
}
|
}
|
||||||
/* don't restart its timer, and silently
|
|
||||||
drop the packet. */
|
|
||||||
__ip_vs_conn_put(cp);
|
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -846,6 +846,21 @@ ctnetlink_alloc_filter(const struct nlattr * const cda[])
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ctnetlink_start(struct netlink_callback *cb)
|
||||||
|
{
|
||||||
|
const struct nlattr * const *cda = cb->data;
|
||||||
|
struct ctnetlink_filter *filter = NULL;
|
||||||
|
|
||||||
|
if (cda[CTA_MARK] && cda[CTA_MARK_MASK]) {
|
||||||
|
filter = ctnetlink_alloc_filter(cda);
|
||||||
|
if (IS_ERR(filter))
|
||||||
|
return PTR_ERR(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
cb->data = filter;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int ctnetlink_filter_match(struct nf_conn *ct, void *data)
|
static int ctnetlink_filter_match(struct nf_conn *ct, void *data)
|
||||||
{
|
{
|
||||||
struct ctnetlink_filter *filter = data;
|
struct ctnetlink_filter *filter = data;
|
||||||
|
@ -1290,19 +1305,12 @@ static int ctnetlink_get_conntrack(struct net *net, struct sock *ctnl,
|
||||||
|
|
||||||
if (nlh->nlmsg_flags & NLM_F_DUMP) {
|
if (nlh->nlmsg_flags & NLM_F_DUMP) {
|
||||||
struct netlink_dump_control c = {
|
struct netlink_dump_control c = {
|
||||||
|
.start = ctnetlink_start,
|
||||||
.dump = ctnetlink_dump_table,
|
.dump = ctnetlink_dump_table,
|
||||||
.done = ctnetlink_done,
|
.done = ctnetlink_done,
|
||||||
|
.data = (void *)cda,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (cda[CTA_MARK] && cda[CTA_MARK_MASK]) {
|
|
||||||
struct ctnetlink_filter *filter;
|
|
||||||
|
|
||||||
filter = ctnetlink_alloc_filter(cda);
|
|
||||||
if (IS_ERR(filter))
|
|
||||||
return PTR_ERR(filter);
|
|
||||||
|
|
||||||
c.data = filter;
|
|
||||||
}
|
|
||||||
return netlink_dump_start(ctnl, skb, nlh, &c);
|
return netlink_dump_start(ctnl, skb, nlh, &c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -312,7 +312,9 @@ void nf_ct_l4proto_unregister_one(const struct nf_conntrack_l4proto *l4proto)
|
||||||
__nf_ct_l4proto_unregister_one(l4proto);
|
__nf_ct_l4proto_unregister_one(l4proto);
|
||||||
mutex_unlock(&nf_ct_proto_mutex);
|
mutex_unlock(&nf_ct_proto_mutex);
|
||||||
|
|
||||||
synchronize_rcu();
|
synchronize_net();
|
||||||
|
/* Remove all contrack entries for this protocol */
|
||||||
|
nf_ct_iterate_destroy(kill_l4proto, (void *)l4proto);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nf_ct_l4proto_unregister_one);
|
EXPORT_SYMBOL_GPL(nf_ct_l4proto_unregister_one);
|
||||||
|
|
||||||
|
@ -333,14 +335,17 @@ static void
|
||||||
nf_ct_l4proto_unregister(const struct nf_conntrack_l4proto * const l4proto[],
|
nf_ct_l4proto_unregister(const struct nf_conntrack_l4proto * const l4proto[],
|
||||||
unsigned int num_proto)
|
unsigned int num_proto)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
mutex_lock(&nf_ct_proto_mutex);
|
mutex_lock(&nf_ct_proto_mutex);
|
||||||
while (num_proto-- != 0)
|
for (i = 0; i < num_proto; i++)
|
||||||
__nf_ct_l4proto_unregister_one(l4proto[num_proto]);
|
__nf_ct_l4proto_unregister_one(l4proto[i]);
|
||||||
mutex_unlock(&nf_ct_proto_mutex);
|
mutex_unlock(&nf_ct_proto_mutex);
|
||||||
|
|
||||||
synchronize_net();
|
synchronize_net();
|
||||||
/* Remove all contrack entries for this protocol */
|
|
||||||
nf_ct_iterate_destroy(kill_l4proto, (void *)l4proto);
|
for (i = 0; i < num_proto; i++)
|
||||||
|
nf_ct_iterate_destroy(kill_l4proto, (void *)l4proto[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
|
@ -3354,7 +3354,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
|
||||||
struct nft_set *set;
|
struct nft_set *set;
|
||||||
struct nft_ctx ctx;
|
struct nft_ctx ctx;
|
||||||
char *name;
|
char *name;
|
||||||
unsigned int size;
|
u64 size;
|
||||||
u64 timeout;
|
u64 timeout;
|
||||||
u32 ktype, dtype, flags, policy, gc_int, objtype;
|
u32 ktype, dtype, flags, policy, gc_int, objtype;
|
||||||
struct nft_set_desc desc;
|
struct nft_set_desc desc;
|
||||||
|
@ -5925,10 +5925,7 @@ static int nf_tables_flowtable_event(struct notifier_block *this,
|
||||||
if (event != NETDEV_UNREGISTER)
|
if (event != NETDEV_UNREGISTER)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
net = maybe_get_net(dev_net(dev));
|
net = dev_net(dev);
|
||||||
if (!net)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
mutex_lock(&net->nft.commit_mutex);
|
mutex_lock(&net->nft.commit_mutex);
|
||||||
list_for_each_entry(table, &net->nft.tables, list) {
|
list_for_each_entry(table, &net->nft.tables, list) {
|
||||||
list_for_each_entry(flowtable, &table->flowtables, list) {
|
list_for_each_entry(flowtable, &table->flowtables, list) {
|
||||||
|
@ -5936,7 +5933,7 @@ static int nf_tables_flowtable_event(struct notifier_block *this,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&net->nft.commit_mutex);
|
mutex_unlock(&net->nft.commit_mutex);
|
||||||
put_net(net);
|
|
||||||
return NOTIFY_DONE;
|
return NOTIFY_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7273,21 +7270,36 @@ static int __init nf_tables_module_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
nft_chain_filter_init();
|
err = register_pernet_subsys(&nf_tables_net_ops);
|
||||||
|
|
||||||
err = nf_tables_core_module_init();
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
err = nft_chain_filter_init();
|
||||||
|
if (err < 0)
|
||||||
|
goto err1;
|
||||||
|
|
||||||
|
err = nf_tables_core_module_init();
|
||||||
|
if (err < 0)
|
||||||
|
goto err2;
|
||||||
|
|
||||||
|
err = register_netdevice_notifier(&nf_tables_flowtable_notifier);
|
||||||
|
if (err < 0)
|
||||||
|
goto err3;
|
||||||
|
|
||||||
|
/* must be last */
|
||||||
err = nfnetlink_subsys_register(&nf_tables_subsys);
|
err = nfnetlink_subsys_register(&nf_tables_subsys);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto err;
|
goto err4;
|
||||||
|
|
||||||
register_netdevice_notifier(&nf_tables_flowtable_notifier);
|
return err;
|
||||||
|
err4:
|
||||||
return register_pernet_subsys(&nf_tables_net_ops);
|
unregister_netdevice_notifier(&nf_tables_flowtable_notifier);
|
||||||
err:
|
err3:
|
||||||
nf_tables_core_module_exit();
|
nf_tables_core_module_exit();
|
||||||
|
err2:
|
||||||
|
nft_chain_filter_fini();
|
||||||
|
err1:
|
||||||
|
unregister_pernet_subsys(&nf_tables_net_ops);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -238,29 +238,33 @@ static const struct nla_policy filter_policy[NFACCT_FILTER_MAX + 1] = {
|
||||||
[NFACCT_FILTER_VALUE] = { .type = NLA_U32 },
|
[NFACCT_FILTER_VALUE] = { .type = NLA_U32 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct nfacct_filter *
|
static int nfnl_acct_start(struct netlink_callback *cb)
|
||||||
nfacct_filter_alloc(const struct nlattr * const attr)
|
|
||||||
{
|
{
|
||||||
struct nfacct_filter *filter;
|
const struct nlattr *const attr = cb->data;
|
||||||
struct nlattr *tb[NFACCT_FILTER_MAX + 1];
|
struct nlattr *tb[NFACCT_FILTER_MAX + 1];
|
||||||
|
struct nfacct_filter *filter;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
if (!attr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
err = nla_parse_nested(tb, NFACCT_FILTER_MAX, attr, filter_policy,
|
err = nla_parse_nested(tb, NFACCT_FILTER_MAX, attr, filter_policy,
|
||||||
NULL);
|
NULL);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return ERR_PTR(err);
|
return err;
|
||||||
|
|
||||||
if (!tb[NFACCT_FILTER_MASK] || !tb[NFACCT_FILTER_VALUE])
|
if (!tb[NFACCT_FILTER_MASK] || !tb[NFACCT_FILTER_VALUE])
|
||||||
return ERR_PTR(-EINVAL);
|
return -EINVAL;
|
||||||
|
|
||||||
filter = kzalloc(sizeof(struct nfacct_filter), GFP_KERNEL);
|
filter = kzalloc(sizeof(struct nfacct_filter), GFP_KERNEL);
|
||||||
if (!filter)
|
if (!filter)
|
||||||
return ERR_PTR(-ENOMEM);
|
return -ENOMEM;
|
||||||
|
|
||||||
filter->mask = ntohl(nla_get_be32(tb[NFACCT_FILTER_MASK]));
|
filter->mask = ntohl(nla_get_be32(tb[NFACCT_FILTER_MASK]));
|
||||||
filter->value = ntohl(nla_get_be32(tb[NFACCT_FILTER_VALUE]));
|
filter->value = ntohl(nla_get_be32(tb[NFACCT_FILTER_VALUE]));
|
||||||
|
cb->data = filter;
|
||||||
|
|
||||||
return filter;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nfnl_acct_get(struct net *net, struct sock *nfnl,
|
static int nfnl_acct_get(struct net *net, struct sock *nfnl,
|
||||||
|
@ -275,18 +279,11 @@ static int nfnl_acct_get(struct net *net, struct sock *nfnl,
|
||||||
if (nlh->nlmsg_flags & NLM_F_DUMP) {
|
if (nlh->nlmsg_flags & NLM_F_DUMP) {
|
||||||
struct netlink_dump_control c = {
|
struct netlink_dump_control c = {
|
||||||
.dump = nfnl_acct_dump,
|
.dump = nfnl_acct_dump,
|
||||||
|
.start = nfnl_acct_start,
|
||||||
.done = nfnl_acct_done,
|
.done = nfnl_acct_done,
|
||||||
|
.data = (void *)tb[NFACCT_FILTER],
|
||||||
};
|
};
|
||||||
|
|
||||||
if (tb[NFACCT_FILTER]) {
|
|
||||||
struct nfacct_filter *filter;
|
|
||||||
|
|
||||||
filter = nfacct_filter_alloc(tb[NFACCT_FILTER]);
|
|
||||||
if (IS_ERR(filter))
|
|
||||||
return PTR_ERR(filter);
|
|
||||||
|
|
||||||
c.data = filter;
|
|
||||||
}
|
|
||||||
return netlink_dump_start(nfnl, skb, nlh, &c);
|
return netlink_dump_start(nfnl, skb, nlh, &c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -293,6 +293,13 @@ static void nft_netdev_event(unsigned long event, struct net_device *dev,
|
||||||
if (strcmp(basechain->dev_name, dev->name) != 0)
|
if (strcmp(basechain->dev_name, dev->name) != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* UNREGISTER events are also happpening on netns exit.
|
||||||
|
*
|
||||||
|
* Altough nf_tables core releases all tables/chains, only
|
||||||
|
* this event handler provides guarantee that
|
||||||
|
* basechain.ops->dev is still accessible, so we cannot
|
||||||
|
* skip exiting net namespaces.
|
||||||
|
*/
|
||||||
__nft_release_basechain(ctx);
|
__nft_release_basechain(ctx);
|
||||||
break;
|
break;
|
||||||
case NETDEV_CHANGENAME:
|
case NETDEV_CHANGENAME:
|
||||||
|
@ -318,10 +325,6 @@ static int nf_tables_netdev_event(struct notifier_block *this,
|
||||||
event != NETDEV_CHANGENAME)
|
event != NETDEV_CHANGENAME)
|
||||||
return NOTIFY_DONE;
|
return NOTIFY_DONE;
|
||||||
|
|
||||||
ctx.net = maybe_get_net(ctx.net);
|
|
||||||
if (!ctx.net)
|
|
||||||
return NOTIFY_DONE;
|
|
||||||
|
|
||||||
mutex_lock(&ctx.net->nft.commit_mutex);
|
mutex_lock(&ctx.net->nft.commit_mutex);
|
||||||
list_for_each_entry(table, &ctx.net->nft.tables, list) {
|
list_for_each_entry(table, &ctx.net->nft.tables, list) {
|
||||||
if (table->family != NFPROTO_NETDEV)
|
if (table->family != NFPROTO_NETDEV)
|
||||||
|
@ -338,7 +341,6 @@ static int nf_tables_netdev_event(struct notifier_block *this,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&ctx.net->nft.commit_mutex);
|
mutex_unlock(&ctx.net->nft.commit_mutex);
|
||||||
put_net(ctx.net);
|
|
||||||
|
|
||||||
return NOTIFY_DONE;
|
return NOTIFY_DONE;
|
||||||
}
|
}
|
||||||
|
@ -392,7 +394,7 @@ int __init nft_chain_filter_init(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __exit nft_chain_filter_fini(void)
|
void nft_chain_filter_fini(void)
|
||||||
{
|
{
|
||||||
nft_chain_filter_bridge_fini();
|
nft_chain_filter_bridge_fini();
|
||||||
nft_chain_filter_inet_fini();
|
nft_chain_filter_inet_fini();
|
||||||
|
|
|
@ -832,12 +832,13 @@ static int nft_ct_timeout_obj_init(const struct nft_ctx *ctx,
|
||||||
__u8 l4num;
|
__u8 l4num;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!tb[NFTA_CT_TIMEOUT_L3PROTO] ||
|
if (!tb[NFTA_CT_TIMEOUT_L4PROTO] ||
|
||||||
!tb[NFTA_CT_TIMEOUT_L4PROTO] ||
|
|
||||||
!tb[NFTA_CT_TIMEOUT_DATA])
|
!tb[NFTA_CT_TIMEOUT_DATA])
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
l3num = ntohs(nla_get_be16(tb[NFTA_CT_TIMEOUT_L3PROTO]));
|
if (tb[NFTA_CT_TIMEOUT_L3PROTO])
|
||||||
|
l3num = ntohs(nla_get_be16(tb[NFTA_CT_TIMEOUT_L3PROTO]));
|
||||||
|
|
||||||
l4num = nla_get_u8(tb[NFTA_CT_TIMEOUT_L4PROTO]);
|
l4num = nla_get_u8(tb[NFTA_CT_TIMEOUT_L4PROTO]);
|
||||||
priv->l4proto = l4num;
|
priv->l4proto = l4num;
|
||||||
|
|
||||||
|
|
|
@ -187,8 +187,6 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
|
||||||
if (tb[NFTA_DYNSET_EXPR] != NULL) {
|
if (tb[NFTA_DYNSET_EXPR] != NULL) {
|
||||||
if (!(set->flags & NFT_SET_EVAL))
|
if (!(set->flags & NFT_SET_EVAL))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!nft_set_is_anonymous(set))
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
|
|
||||||
priv->expr = nft_expr_init(ctx, tb[NFTA_DYNSET_EXPR]);
|
priv->expr = nft_expr_init(ctx, tb[NFTA_DYNSET_EXPR]);
|
||||||
if (IS_ERR(priv->expr))
|
if (IS_ERR(priv->expr))
|
||||||
|
|
|
@ -248,13 +248,13 @@ static inline u32 nft_bitmap_size(u32 klen)
|
||||||
return ((2 << ((klen * BITS_PER_BYTE) - 1)) / BITS_PER_BYTE) << 1;
|
return ((2 << ((klen * BITS_PER_BYTE) - 1)) / BITS_PER_BYTE) << 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 nft_bitmap_total_size(u32 klen)
|
static inline u64 nft_bitmap_total_size(u32 klen)
|
||||||
{
|
{
|
||||||
return sizeof(struct nft_bitmap) + nft_bitmap_size(klen);
|
return sizeof(struct nft_bitmap) + nft_bitmap_size(klen);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int nft_bitmap_privsize(const struct nlattr * const nla[],
|
static u64 nft_bitmap_privsize(const struct nlattr * const nla[],
|
||||||
const struct nft_set_desc *desc)
|
const struct nft_set_desc *desc)
|
||||||
{
|
{
|
||||||
u32 klen = ntohl(nla_get_be32(nla[NFTA_SET_KEY_LEN]));
|
u32 klen = ntohl(nla_get_be32(nla[NFTA_SET_KEY_LEN]));
|
||||||
|
|
||||||
|
|
|
@ -341,8 +341,8 @@ schedule:
|
||||||
nft_set_gc_interval(set));
|
nft_set_gc_interval(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int nft_rhash_privsize(const struct nlattr * const nla[],
|
static u64 nft_rhash_privsize(const struct nlattr * const nla[],
|
||||||
const struct nft_set_desc *desc)
|
const struct nft_set_desc *desc)
|
||||||
{
|
{
|
||||||
return sizeof(struct nft_rhash);
|
return sizeof(struct nft_rhash);
|
||||||
}
|
}
|
||||||
|
@ -585,8 +585,8 @@ cont:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int nft_hash_privsize(const struct nlattr * const nla[],
|
static u64 nft_hash_privsize(const struct nlattr * const nla[],
|
||||||
const struct nft_set_desc *desc)
|
const struct nft_set_desc *desc)
|
||||||
{
|
{
|
||||||
return sizeof(struct nft_hash) +
|
return sizeof(struct nft_hash) +
|
||||||
nft_hash_buckets(desc->size) * sizeof(struct hlist_head);
|
nft_hash_buckets(desc->size) * sizeof(struct hlist_head);
|
||||||
|
|
|
@ -411,8 +411,8 @@ static void nft_rbtree_gc(struct work_struct *work)
|
||||||
nft_set_gc_interval(set));
|
nft_set_gc_interval(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int nft_rbtree_privsize(const struct nlattr * const nla[],
|
static u64 nft_rbtree_privsize(const struct nlattr * const nla[],
|
||||||
const struct nft_set_desc *desc)
|
const struct nft_set_desc *desc)
|
||||||
{
|
{
|
||||||
return sizeof(struct nft_rbtree);
|
return sizeof(struct nft_rbtree);
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,13 +82,15 @@ static void nft_tproxy_eval_v6(const struct nft_expr *expr,
|
||||||
const struct nft_tproxy *priv = nft_expr_priv(expr);
|
const struct nft_tproxy *priv = nft_expr_priv(expr);
|
||||||
struct sk_buff *skb = pkt->skb;
|
struct sk_buff *skb = pkt->skb;
|
||||||
const struct ipv6hdr *iph = ipv6_hdr(skb);
|
const struct ipv6hdr *iph = ipv6_hdr(skb);
|
||||||
struct in6_addr taddr = {0};
|
struct in6_addr taddr;
|
||||||
int thoff = pkt->xt.thoff;
|
int thoff = pkt->xt.thoff;
|
||||||
struct udphdr _hdr, *hp;
|
struct udphdr _hdr, *hp;
|
||||||
__be16 tport = 0;
|
__be16 tport = 0;
|
||||||
struct sock *sk;
|
struct sock *sk;
|
||||||
int l4proto;
|
int l4proto;
|
||||||
|
|
||||||
|
memset(&taddr, 0, sizeof(taddr));
|
||||||
|
|
||||||
if (!pkt->tprot_set) {
|
if (!pkt->tprot_set) {
|
||||||
regs->verdict.code = NFT_BREAK;
|
regs->verdict.code = NFT_BREAK;
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1178,12 +1178,7 @@ struct xt_table_info *xt_alloc_table_info(unsigned int size)
|
||||||
if (sz < sizeof(*info) || sz >= XT_MAX_TABLE_SIZE)
|
if (sz < sizeof(*info) || sz >= XT_MAX_TABLE_SIZE)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* __GFP_NORETRY is not fully supported by kvmalloc but it should
|
info = kvmalloc(sz, GFP_KERNEL_ACCOUNT);
|
||||||
* work reasonably well if sz is too large and bail out rather
|
|
||||||
* than shoot all processes down before realizing there is nothing
|
|
||||||
* more to reclaim.
|
|
||||||
*/
|
|
||||||
info = kvmalloc(sz, GFP_KERNEL | __GFP_NORETRY);
|
|
||||||
if (!info)
|
if (!info)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче