Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
Pablo Neira Ayuso says: ==================== Netfilter/IPVS updates for net-next The following patchset contains another batch with Netfilter/IPVS updates for net-next, they are: 1) Add abstracted ICMP codes to the nf_tables reject expression. We introduce four reasons to reject using ICMP that overlap in IPv4 and IPv6 from the semantic point of view. This should simplify the maintainance of dual stack rule-sets through the inet table. 2) Move nf_send_reset() functions from header files to per-family nf_reject modules, suggested by Patrick McHardy. 3) We have to use IS_ENABLED(CONFIG_BRIDGE_NETFILTER) everywhere in the code now that br_netfilter can be modularized. Convert remaining spots in the network stack code. 4) Use rcu_barrier() in the nf_tables module removal path to ensure that we don't leave object that are still pending to be released via call_rcu (that may likely result in a crash). 5) Remove incomplete arch 32/64 compat from nft_compat. The original (bad) idea was to probe the word size based on the xtables match/target info size, but this assumption is wrong when you have to dump the information back to userspace. 6) Allow to filter from prerouting and postrouting in the nf_tables bridge. In order to emulate the ebtables NAT chains (which are actually simple filter chains with no special semantics), we have support filtering from this hooks too. 7) Add explicit module dependency between xt_physdev and br_netfilter. This provides a way to detect if the user needs br_netfilter from the configuration path. This should reduce the breakage of the br_netfilter modularization. 8) Cleanup coding style in ip_vs.h, from Simon Horman. 9) Fix crash in the recently added nf_tables masq expression. We have to register/unregister the notifiers to clean up the conntrack table entries from the module init/exit path, not from the rule addition / deletion path. From Arturo Borrero. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -40,8 +40,13 @@ config NFT_CHAIN_ROUTE_IPV6
|
||||
fields such as the source, destination, flowlabel, hop-limit and
|
||||
the packet mark.
|
||||
|
||||
config NF_REJECT_IPV6
|
||||
tristate "IPv6 packet rejection"
|
||||
default m if NETFILTER_ADVANCED=n
|
||||
|
||||
config NFT_REJECT_IPV6
|
||||
depends on NF_TABLES_IPV6
|
||||
select NF_REJECT_IPV6
|
||||
default NFT_REJECT
|
||||
tristate
|
||||
|
||||
@@ -208,6 +213,7 @@ config IP6_NF_FILTER
|
||||
config IP6_NF_TARGET_REJECT
|
||||
tristate "REJECT target support"
|
||||
depends on IP6_NF_FILTER
|
||||
select NF_REJECT_IPV6
|
||||
default m if NETFILTER_ADVANCED=n
|
||||
help
|
||||
The REJECT target allows a filtering rule to specify that an ICMPv6
|
||||
|
@@ -27,6 +27,9 @@ obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o
|
||||
# logging
|
||||
obj-$(CONFIG_NF_LOG_IPV6) += nf_log_ipv6.o
|
||||
|
||||
# reject
|
||||
obj-$(CONFIG_NF_REJECT_IPV6) += nf_reject_ipv6.o
|
||||
|
||||
# nf_tables
|
||||
obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o
|
||||
obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o
|
||||
|
@@ -40,7 +40,7 @@ static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
|
||||
zone = nf_ct_zone((struct nf_conn *)skb->nfct);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BRIDGE_NETFILTER
|
||||
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
|
||||
if (skb->nf_bridge &&
|
||||
skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)
|
||||
return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone;
|
||||
|
163
net/ipv6/netfilter/nf_reject_ipv6.c
Normal file
163
net/ipv6/netfilter/nf_reject_ipv6.c
Normal file
@@ -0,0 +1,163 @@
|
||||
/* (C) 1999-2001 Paul `Rusty' Russell
|
||||
* (C) 2002-2004 Netfilter Core Team <coreteam@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 <net/ipv6.h>
|
||||
#include <net/ip6_route.h>
|
||||
#include <net/ip6_fib.h>
|
||||
#include <net/ip6_checksum.h>
|
||||
#include <linux/netfilter_ipv6.h>
|
||||
|
||||
void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
|
||||
{
|
||||
struct sk_buff *nskb;
|
||||
struct tcphdr otcph, *tcph;
|
||||
unsigned int otcplen, hh_len;
|
||||
int tcphoff, needs_ack;
|
||||
const struct ipv6hdr *oip6h = ipv6_hdr(oldskb);
|
||||
struct ipv6hdr *ip6h;
|
||||
#define DEFAULT_TOS_VALUE 0x0U
|
||||
const __u8 tclass = DEFAULT_TOS_VALUE;
|
||||
struct dst_entry *dst = NULL;
|
||||
u8 proto;
|
||||
__be16 frag_off;
|
||||
struct flowi6 fl6;
|
||||
|
||||
if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
|
||||
(!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) {
|
||||
pr_debug("addr is not unicast.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
proto = oip6h->nexthdr;
|
||||
tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto, &frag_off);
|
||||
|
||||
if ((tcphoff < 0) || (tcphoff > oldskb->len)) {
|
||||
pr_debug("Cannot get TCP header.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
otcplen = oldskb->len - tcphoff;
|
||||
|
||||
/* IP header checks: fragment, too short. */
|
||||
if (proto != IPPROTO_TCP || otcplen < sizeof(struct tcphdr)) {
|
||||
pr_debug("proto(%d) != IPPROTO_TCP, "
|
||||
"or too short. otcplen = %d\n",
|
||||
proto, otcplen);
|
||||
return;
|
||||
}
|
||||
|
||||
if (skb_copy_bits(oldskb, tcphoff, &otcph, sizeof(struct tcphdr)))
|
||||
BUG();
|
||||
|
||||
/* No RST for RST. */
|
||||
if (otcph.rst) {
|
||||
pr_debug("RST is set\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check checksum. */
|
||||
if (nf_ip6_checksum(oldskb, hook, tcphoff, IPPROTO_TCP)) {
|
||||
pr_debug("TCP checksum is invalid\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&fl6, 0, sizeof(fl6));
|
||||
fl6.flowi6_proto = IPPROTO_TCP;
|
||||
fl6.saddr = oip6h->daddr;
|
||||
fl6.daddr = oip6h->saddr;
|
||||
fl6.fl6_sport = otcph.dest;
|
||||
fl6.fl6_dport = otcph.source;
|
||||
security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6));
|
||||
dst = ip6_route_output(net, NULL, &fl6);
|
||||
if (dst == NULL || dst->error) {
|
||||
dst_release(dst);
|
||||
return;
|
||||
}
|
||||
dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
|
||||
if (IS_ERR(dst))
|
||||
return;
|
||||
|
||||
hh_len = (dst->dev->hard_header_len + 15)&~15;
|
||||
nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr)
|
||||
+ sizeof(struct tcphdr) + dst->trailer_len,
|
||||
GFP_ATOMIC);
|
||||
|
||||
if (!nskb) {
|
||||
net_dbg_ratelimited("cannot alloc skb\n");
|
||||
dst_release(dst);
|
||||
return;
|
||||
}
|
||||
|
||||
skb_dst_set(nskb, dst);
|
||||
|
||||
skb_reserve(nskb, hh_len + dst->header_len);
|
||||
|
||||
skb_put(nskb, sizeof(struct ipv6hdr));
|
||||
skb_reset_network_header(nskb);
|
||||
ip6h = ipv6_hdr(nskb);
|
||||
ip6_flow_hdr(ip6h, tclass, 0);
|
||||
ip6h->hop_limit = ip6_dst_hoplimit(dst);
|
||||
ip6h->nexthdr = IPPROTO_TCP;
|
||||
ip6h->saddr = oip6h->daddr;
|
||||
ip6h->daddr = oip6h->saddr;
|
||||
|
||||
skb_reset_transport_header(nskb);
|
||||
tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
|
||||
/* Truncate to length (no data) */
|
||||
tcph->doff = sizeof(struct tcphdr)/4;
|
||||
tcph->source = otcph.dest;
|
||||
tcph->dest = otcph.source;
|
||||
|
||||
if (otcph.ack) {
|
||||
needs_ack = 0;
|
||||
tcph->seq = otcph.ack_seq;
|
||||
tcph->ack_seq = 0;
|
||||
} else {
|
||||
needs_ack = 1;
|
||||
tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin
|
||||
+ otcplen - (otcph.doff<<2));
|
||||
tcph->seq = 0;
|
||||
}
|
||||
|
||||
/* Reset flags */
|
||||
((u_int8_t *)tcph)[13] = 0;
|
||||
tcph->rst = 1;
|
||||
tcph->ack = needs_ack;
|
||||
tcph->window = 0;
|
||||
tcph->urg_ptr = 0;
|
||||
tcph->check = 0;
|
||||
|
||||
/* Adjust TCP checksum */
|
||||
tcph->check = csum_ipv6_magic(&ipv6_hdr(nskb)->saddr,
|
||||
&ipv6_hdr(nskb)->daddr,
|
||||
sizeof(struct tcphdr), IPPROTO_TCP,
|
||||
csum_partial(tcph,
|
||||
sizeof(struct tcphdr), 0));
|
||||
|
||||
nf_ct_attach(nskb, oldskb);
|
||||
|
||||
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
|
||||
/* If we use ip6_local_out for bridged traffic, the MAC source on
|
||||
* the RST will be ours, instead of the destination's. This confuses
|
||||
* some routers/firewalls, and they drop the packet. So we need to
|
||||
* build the eth header using the original destination's MAC as the
|
||||
* source, and send the RST packet directly.
|
||||
*/
|
||||
if (oldskb->nf_bridge) {
|
||||
struct ethhdr *oeth = eth_hdr(oldskb);
|
||||
nskb->dev = oldskb->nf_bridge->physindev;
|
||||
nskb->protocol = htons(ETH_P_IPV6);
|
||||
ip6h->payload_len = htons(sizeof(struct tcphdr));
|
||||
if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol),
|
||||
oeth->h_source, oeth->h_dest, nskb->len) < 0)
|
||||
return;
|
||||
dev_queue_xmit(nskb);
|
||||
} else
|
||||
#endif
|
||||
ip6_local_out(nskb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_send_reset6);
|
@@ -32,33 +32,12 @@ static void nft_masq_ipv6_eval(const struct nft_expr *expr,
|
||||
data[NFT_REG_VERDICT].verdict = verdict;
|
||||
}
|
||||
|
||||
static int nft_masq_ipv6_init(const struct nft_ctx *ctx,
|
||||
const struct nft_expr *expr,
|
||||
const struct nlattr * const tb[])
|
||||
{
|
||||
int err;
|
||||
|
||||
err = nft_masq_init(ctx, expr, tb);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
nf_nat_masquerade_ipv6_register_notifier();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nft_masq_ipv6_destroy(const struct nft_ctx *ctx,
|
||||
const struct nft_expr *expr)
|
||||
{
|
||||
nf_nat_masquerade_ipv6_unregister_notifier();
|
||||
}
|
||||
|
||||
static struct nft_expr_type nft_masq_ipv6_type;
|
||||
static const struct nft_expr_ops nft_masq_ipv6_ops = {
|
||||
.type = &nft_masq_ipv6_type,
|
||||
.size = NFT_EXPR_SIZE(sizeof(struct nft_masq)),
|
||||
.eval = nft_masq_ipv6_eval,
|
||||
.init = nft_masq_ipv6_init,
|
||||
.destroy = nft_masq_ipv6_destroy,
|
||||
.init = nft_masq_init,
|
||||
.dump = nft_masq_dump,
|
||||
};
|
||||
|
||||
@@ -73,12 +52,21 @@ static struct nft_expr_type nft_masq_ipv6_type __read_mostly = {
|
||||
|
||||
static int __init nft_masq_ipv6_module_init(void)
|
||||
{
|
||||
return nft_register_expr(&nft_masq_ipv6_type);
|
||||
int ret;
|
||||
|
||||
ret = nft_register_expr(&nft_masq_ipv6_type);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
nf_nat_masquerade_ipv6_register_notifier();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit nft_masq_ipv6_module_exit(void)
|
||||
{
|
||||
nft_unregister_expr(&nft_masq_ipv6_type);
|
||||
nf_nat_masquerade_ipv6_unregister_notifier();
|
||||
}
|
||||
|
||||
module_init(nft_masq_ipv6_module_init);
|
||||
|
Reference in New Issue
Block a user