netfilter: ip[6]t_REJECT: tcp-reset using wrong MAC source if bridged
Subsystems (2)
PATCH 1/1 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.
Phil
net/ipv4/netfilter/ipt_REJECT.c +20 -1
@@ -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:
net/ipv6/netfilter/ip6t_REJECT.c +19 -1
@@ -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
Pablo Neira Ayuso
maintainerQuoted 22 lines · Phil Oester
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.
Phil
Signed-off-by Phil Oester <[email protected]>net/ipv4/netfilter/ipt_REJECT.c +0
-1@@ -119,7 +119,26 @@ static void send_reset(struct sk_buff *oldskb, int hook)nf_ct_attach (nskb, oldskb); -ip_local_out (nskb);
net/ipv4/netfilter/ipt_REJECT.c static void send_reset(struct sk_buff *oldskb, int hook) · line 131
Quoted 10 lines
net/ipv4/netfilter/ipt_REJECT.c +10
-0+#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;
This won't work for locally generated traffic, physindev is null in that case.
Quoted 44 lines
net/ipv4/netfilter/ipt_REJECT.c +10
-0+ 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:net/ipv6/netfilter/ip6t_REJECT.c +19
-1@@ -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
Quoted 6 lines · Pablo Neira Ayuso
net/ipv4/netfilter/ipt_REJECT.c static void send_reset(struct sk_buff *oldskb, int hook) · line 131
Quoted 3 lines
net/ipv4/netfilter/ipt_REJECT.c +3
-0+if (oldskb->nf_bridge) { +struct ethhdr *oeth =eth_hdr (oldskb); + nskb->dev = oldskb->nf_bridge->physindev;This won't work for locally generated traffic, physindev is null in that case.
But nf_bridge is NULL for locally generated traffic, so we won't even enter this section at all.
Phil
Quoted 8 lines · Phil Oester
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.
Applied, thanks Phil.