|
@@ -892,6 +892,38 @@ static unsigned int ip_sabotage_in(const struct nf_hook_ops *ops,
|
|
|
return NF_ACCEPT;
|
|
|
}
|
|
|
|
|
|
+/* This is called when br_netfilter has called into iptables/netfilter,
|
|
|
+ * and DNAT has taken place on a bridge-forwarded packet.
|
|
|
+ *
|
|
|
+ * neigh->output has created a new MAC header, with local br0 MAC
|
|
|
+ * as saddr.
|
|
|
+ *
|
|
|
+ * This restores the original MAC saddr of the bridged packet
|
|
|
+ * before invoking bridge forward logic to transmit the packet.
|
|
|
+ */
|
|
|
+static void br_nf_pre_routing_finish_bridge_slow(struct sk_buff *skb)
|
|
|
+{
|
|
|
+ struct nf_bridge_info *nf_bridge = skb->nf_bridge;
|
|
|
+
|
|
|
+ skb_pull(skb, ETH_HLEN);
|
|
|
+ nf_bridge->mask &= ~BRNF_BRIDGED_DNAT;
|
|
|
+
|
|
|
+ skb_copy_to_linear_data_offset(skb, -(ETH_HLEN-ETH_ALEN),
|
|
|
+ skb->nf_bridge->data, ETH_HLEN-ETH_ALEN);
|
|
|
+ skb->dev = nf_bridge->physindev;
|
|
|
+ br_handle_frame_finish(skb);
|
|
|
+}
|
|
|
+
|
|
|
+int br_nf_prerouting_finish_bridge(struct sk_buff *skb)
|
|
|
+{
|
|
|
+ if (skb->nf_bridge && (skb->nf_bridge->mask & BRNF_BRIDGED_DNAT)) {
|
|
|
+ br_nf_pre_routing_finish_bridge_slow(skb);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(br_nf_prerouting_finish_bridge);
|
|
|
+
|
|
|
void br_netfilter_enable(void)
|
|
|
{
|
|
|
}
|