diff options
author | Phil Oester <kernel@linuxace.com> | 2013-06-26 17:16:28 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2013-08-28 00:13:12 +0200 |
commit | affe759dbaa9e6c08b0da0a11d1933b61f199f51 (patch) | |
tree | f232ec8dcf549c3903b3a959480e79e9dba573c1 /net/ipv6 | |
parent | 35fdb94b453bc69b7bc74b717f1e03d41d4bcdba (diff) | |
download | kernel_goldelico_gta04-affe759dbaa9e6c08b0da0a11d1933b61f199f51.zip kernel_goldelico_gta04-affe759dbaa9e6c08b0da0a11d1933b61f199f51.tar.gz kernel_goldelico_gta04-affe759dbaa9e6c08b0da0a11d1933b61f199f51.tar.bz2 |
netfilter: ip[6]t_REJECT: tcp-reset using wrong MAC source if bridged
As reported by Casper Gripenberg, in a bridged setup, using ip[6]t_REJECT
with the tcp-reset option sends out reset packets with the src MAC address
of the local bridge interface, instead of the MAC address of the intended
destination. This causes some routers/firewalls to drop the reset packet
as it appears to be spoofed. Fix this by bypassing ip[6]_local_out and
setting the MAC of the sender in the tcp reset packet.
This closes netfilter bugzilla #531.
Signed-off-by: Phil Oester <kernel@linuxace.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/netfilter/ip6t_REJECT.c | 20 |
1 files changed, 19 insertions, 1 deletions
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 70f9abc..56eef30 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c @@ -169,7 +169,25 @@ static void send_reset(struct net *net, struct sk_buff *oldskb) nf_ct_attach(nskb, oldskb); - ip6_local_out(nskb); +#ifdef 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); } static inline void |