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>
This commit is contained in:
parent
35fdb94b45
commit
affe759dba
|
@ -119,7 +119,26 @@ static void send_reset(struct sk_buff *oldskb, int hook)
|
||||||
|
|
||||||
nf_ct_attach(nskb, oldskb);
|
nf_ct_attach(nskb, oldskb);
|
||||||
|
|
||||||
|
#ifdef 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);
|
ip_local_out(nskb);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
free_nskb:
|
free_nskb:
|
||||||
|
|
|
@ -169,6 +169,24 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
|
||||||
|
|
||||||
nf_ct_attach(nskb, oldskb);
|
nf_ct_attach(nskb, oldskb);
|
||||||
|
|
||||||
|
#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);
|
ip6_local_out(nskb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue