![David S. Miller](/assets/img/avatar_default.png)
Pablo Neira Ayuso says: ==================== netfilter/ipvs updates for net-next The following patchset contains Netfilter updates for your net-next tree, this includes the NAT redirection support for nf_tables, the cgroup support for nft meta and conntrack zone support for the connlimit match. Coming after those, a bunch of sparse warning fixes, missing netns bits and cleanups. More specifically, they are: 1) Prepare IPv4 and IPv6 NAT redirect code to use it from nf_tables, patches from Arturo Borrero. 2) Introduce the nf_tables redir expression, from Arturo Borrero. 3) Remove an unnecessary assignment in ip_vs_xmit/__ip_vs_get_out_rt(). Patch from Alex Gartrell. 4) Add nft_log_dereference() macro to the nf_log infrastructure, patch from Marcelo Leitner. 5) Add some extra validation when registering logger families, also from Marcelo. 6) Some spelling cleanups from stephen hemminger. 7) Fix sparse warning in nf_logger_find_get(). 8) Add cgroup support to nf_tables meta, patch from Ana Rey. 9) A Kconfig fix for the new redir expression and fix sparse warnings in the new redir expression. 10) Fix several sparse warnings in the netfilter tree, from Florian Westphal. 11) Reduce verbosity when OOM in nfnetlink_log. User can basically do nothing when this situation occurs. 12) Add conntrack zone support to xt_connlimit, again from Florian. 13) Add netnamespace support to the h323 conntrack helper, contributed by Vasily Averin. 14) Remove unnecessary nul-pointer checks before free_percpu() and module_put(), from Markus Elfring. 15) Use pr_fmt in nfnetlink_log, again patch from Marcelo Leitner. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
168 lines
4.3 KiB
C
168 lines
4.3 KiB
C
/* (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 <linux/module.h>
|
|
#include <net/ip.h>
|
|
#include <net/tcp.h>
|
|
#include <net/route.h>
|
|
#include <net/dst.h>
|
|
#include <net/netfilter/ipv4/nf_reject.h>
|
|
#include <linux/netfilter_ipv4.h>
|
|
#include <net/netfilter/ipv4/nf_reject.h>
|
|
|
|
const struct tcphdr *nf_reject_ip_tcphdr_get(struct sk_buff *oldskb,
|
|
struct tcphdr *_oth, int hook)
|
|
{
|
|
const struct tcphdr *oth;
|
|
|
|
/* IP header checks: fragment. */
|
|
if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET))
|
|
return NULL;
|
|
|
|
oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb),
|
|
sizeof(struct tcphdr), _oth);
|
|
if (oth == NULL)
|
|
return NULL;
|
|
|
|
/* No RST for RST. */
|
|
if (oth->rst)
|
|
return NULL;
|
|
|
|
/* Check checksum */
|
|
if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP))
|
|
return NULL;
|
|
|
|
return oth;
|
|
}
|
|
EXPORT_SYMBOL_GPL(nf_reject_ip_tcphdr_get);
|
|
|
|
struct iphdr *nf_reject_iphdr_put(struct sk_buff *nskb,
|
|
const struct sk_buff *oldskb,
|
|
__be16 protocol, int ttl)
|
|
{
|
|
struct iphdr *niph, *oiph = ip_hdr(oldskb);
|
|
|
|
skb_reset_network_header(nskb);
|
|
niph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr));
|
|
niph->version = 4;
|
|
niph->ihl = sizeof(struct iphdr) / 4;
|
|
niph->tos = 0;
|
|
niph->id = 0;
|
|
niph->frag_off = htons(IP_DF);
|
|
niph->protocol = protocol;
|
|
niph->check = 0;
|
|
niph->saddr = oiph->daddr;
|
|
niph->daddr = oiph->saddr;
|
|
niph->ttl = ttl;
|
|
|
|
nskb->protocol = htons(ETH_P_IP);
|
|
|
|
return niph;
|
|
}
|
|
EXPORT_SYMBOL_GPL(nf_reject_iphdr_put);
|
|
|
|
void nf_reject_ip_tcphdr_put(struct sk_buff *nskb, const struct sk_buff *oldskb,
|
|
const struct tcphdr *oth)
|
|
{
|
|
struct iphdr *niph = ip_hdr(nskb);
|
|
struct tcphdr *tcph;
|
|
|
|
skb_reset_transport_header(nskb);
|
|
tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
|
|
memset(tcph, 0, sizeof(*tcph));
|
|
tcph->source = oth->dest;
|
|
tcph->dest = oth->source;
|
|
tcph->doff = sizeof(struct tcphdr) / 4;
|
|
|
|
if (oth->ack) {
|
|
tcph->seq = oth->ack_seq;
|
|
} else {
|
|
tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin +
|
|
oldskb->len - ip_hdrlen(oldskb) -
|
|
(oth->doff << 2));
|
|
tcph->ack = 1;
|
|
}
|
|
|
|
tcph->rst = 1;
|
|
tcph->check = ~tcp_v4_check(sizeof(struct tcphdr), niph->saddr,
|
|
niph->daddr, 0);
|
|
nskb->ip_summed = CHECKSUM_PARTIAL;
|
|
nskb->csum_start = (unsigned char *)tcph - nskb->head;
|
|
nskb->csum_offset = offsetof(struct tcphdr, check);
|
|
}
|
|
EXPORT_SYMBOL_GPL(nf_reject_ip_tcphdr_put);
|
|
|
|
/* Send RST reply */
|
|
void nf_send_reset(struct sk_buff *oldskb, int hook)
|
|
{
|
|
struct sk_buff *nskb;
|
|
const struct iphdr *oiph;
|
|
struct iphdr *niph;
|
|
const struct tcphdr *oth;
|
|
struct tcphdr _oth;
|
|
|
|
oth = nf_reject_ip_tcphdr_get(oldskb, &_oth, hook);
|
|
if (!oth)
|
|
return;
|
|
|
|
if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
|
|
return;
|
|
|
|
oiph = ip_hdr(oldskb);
|
|
|
|
nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
|
|
LL_MAX_HEADER, GFP_ATOMIC);
|
|
if (!nskb)
|
|
return;
|
|
|
|
/* ip_route_me_harder expects skb->dst to be set */
|
|
skb_dst_set_noref(nskb, skb_dst(oldskb));
|
|
|
|
skb_reserve(nskb, LL_MAX_HEADER);
|
|
niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP,
|
|
ip4_dst_hoplimit(skb_dst(nskb)));
|
|
nf_reject_ip_tcphdr_put(nskb, oldskb, oth);
|
|
|
|
if (ip_route_me_harder(nskb, RTN_UNSPEC))
|
|
goto free_nskb;
|
|
|
|
/* "Never happens" */
|
|
if (nskb->len > dst_mtu(skb_dst(nskb)))
|
|
goto free_nskb;
|
|
|
|
nf_ct_attach(nskb, oldskb);
|
|
|
|
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
|
|
/* If we use ip_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;
|
|
niph->tot_len = htons(nskb->len);
|
|
ip_send_check(niph);
|
|
if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol),
|
|
oeth->h_source, oeth->h_dest, nskb->len) < 0)
|
|
goto free_nskb;
|
|
dev_queue_xmit(nskb);
|
|
} else
|
|
#endif
|
|
ip_local_out(nskb);
|
|
|
|
return;
|
|
|
|
free_nskb:
|
|
kfree_skb(nskb);
|
|
}
|
|
EXPORT_SYMBOL_GPL(nf_send_reset);
|
|
|
|
MODULE_LICENSE("GPL");
|