Skip to content

Commit affe759

Browse files
Phil Oesterummakynes
authored andcommitted
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 torvalds#531. Signed-off-by: Phil Oester <kernel@linuxace.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
1 parent 35fdb94 commit affe759

File tree

2 files changed

+39
-2
lines changed

2 files changed

+39
-2
lines changed

net/ipv4/netfilter/ipt_REJECT.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,26 @@ static void send_reset(struct sk_buff *oldskb, int hook)
119119

120120
nf_ct_attach(nskb, oldskb);
121121

122-
ip_local_out(nskb);
122+
#ifdef CONFIG_BRIDGE_NETFILTER
123+
/* If we use ip_local_out for bridged traffic, the MAC source on
124+
* the RST will be ours, instead of the destination's. This confuses
125+
* some routers/firewalls, and they drop the packet. So we need to
126+
* build the eth header using the original destination's MAC as the
127+
* source, and send the RST packet directly.
128+
*/
129+
if (oldskb->nf_bridge) {
130+
struct ethhdr *oeth = eth_hdr(oldskb);
131+
nskb->dev = oldskb->nf_bridge->physindev;
132+
niph->tot_len = htons(nskb->len);
133+
ip_send_check(niph);
134+
if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol),
135+
oeth->h_source, oeth->h_dest, nskb->len) < 0)
136+
goto free_nskb;
137+
dev_queue_xmit(nskb);
138+
} else
139+
#endif
140+
ip_local_out(nskb);
141+
123142
return;
124143

125144
free_nskb:

net/ipv6/netfilter/ip6t_REJECT.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,25 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
169169

170170
nf_ct_attach(nskb, oldskb);
171171

172-
ip6_local_out(nskb);
172+
#ifdef CONFIG_BRIDGE_NETFILTER
173+
/* If we use ip6_local_out for bridged traffic, the MAC source on
174+
* the RST will be ours, instead of the destination's. This confuses
175+
* some routers/firewalls, and they drop the packet. So we need to
176+
* build the eth header using the original destination's MAC as the
177+
* source, and send the RST packet directly.
178+
*/
179+
if (oldskb->nf_bridge) {
180+
struct ethhdr *oeth = eth_hdr(oldskb);
181+
nskb->dev = oldskb->nf_bridge->physindev;
182+
nskb->protocol = htons(ETH_P_IPV6);
183+
ip6h->payload_len = htons(sizeof(struct tcphdr));
184+
if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol),
185+
oeth->h_source, oeth->h_dest, nskb->len) < 0)
186+
return;
187+
dev_queue_xmit(nskb);
188+
} else
189+
#endif
190+
ip6_local_out(nskb);
173191
}
174192

175193
static inline void

0 commit comments

Comments
 (0)