Skip to content

Commit

Permalink
netfilter: ip[6]t_REJECT: tcp-reset using wrong MAC source if bridged
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Phil Oester authored and Pablo Neira Ayuso committed Aug 27, 2013
1 parent 35fdb94 commit affe759
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 2 deletions.
21 changes: 20 additions & 1 deletion net/ipv4/netfilter/ipt_REJECT.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,26 @@ static void send_reset(struct sk_buff *oldskb, int hook)

nf_ct_attach(nskb, oldskb);

ip_local_out(nskb);
#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);

return;

free_nskb:
Expand Down
20 changes: 19 additions & 1 deletion net/ipv6/netfilter/ip6t_REJECT.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit affe759

Please sign in to comment.