aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netfilter_bridge.h12
-rw-r--r--net/bridge/br_device.c5
-rw-r--r--net/bridge/br_netfilter.c32
-rw-r--r--net/bridge/br_private.h5
4 files changed, 38 insertions, 16 deletions
diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h
index dd580a9a1add..bb39113ea596 100644
--- a/include/linux/netfilter_bridge.h
+++ b/include/linux/netfilter_bridge.h
@@ -44,18 +44,6 @@ static inline unsigned int nf_bridge_mtu_reduction(const struct sk_buff *skb)
44} 44}
45 45
46int br_handle_frame_finish(struct sk_buff *skb); 46int br_handle_frame_finish(struct sk_buff *skb);
47/* Only used in br_device.c */
48static inline int br_nf_pre_routing_finish_bridge_slow(struct sk_buff *skb)
49{
50 struct nf_bridge_info *nf_bridge = skb->nf_bridge;
51
52 skb_pull(skb, ETH_HLEN);
53 nf_bridge->mask ^= BRNF_BRIDGED_DNAT;
54 skb_copy_to_linear_data_offset(skb, -(ETH_HLEN-ETH_ALEN),
55 skb->nf_bridge->data, ETH_HLEN-ETH_ALEN);
56 skb->dev = nf_bridge->physindev;
57 return br_handle_frame_finish(skb);
58}
59 47
60/* This is called by the IP fragmenting code and it ensures there is 48/* This is called by the IP fragmenting code and it ensures there is
61 * enough room for the encapsulating header (if there is one). */ 49 * enough room for the encapsulating header (if there is one). */
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index ffd379db5938..294cbcc49263 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -36,13 +36,10 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
36 u16 vid = 0; 36 u16 vid = 0;
37 37
38 rcu_read_lock(); 38 rcu_read_lock();
39#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) 39 if (br_nf_prerouting_finish_bridge(skb)) {
40 if (skb->nf_bridge && (skb->nf_bridge->mask & BRNF_BRIDGED_DNAT)) {
41 br_nf_pre_routing_finish_bridge_slow(skb);
42 rcu_read_unlock(); 40 rcu_read_unlock();
43 return NETDEV_TX_OK; 41 return NETDEV_TX_OK;
44 } 42 }
45#endif
46 43
47 u64_stats_update_begin(&brstats->syncp); 44 u64_stats_update_begin(&brstats->syncp);
48 brstats->tx_packets++; 45 brstats->tx_packets++;
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index ef1fe281ca11..a8361c7cdf81 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -892,6 +892,38 @@ static unsigned int ip_sabotage_in(const struct nf_hook_ops *ops,
892 return NF_ACCEPT; 892 return NF_ACCEPT;
893} 893}
894 894
895/* This is called when br_netfilter has called into iptables/netfilter,
896 * and DNAT has taken place on a bridge-forwarded packet.
897 *
898 * neigh->output has created a new MAC header, with local br0 MAC
899 * as saddr.
900 *
901 * This restores the original MAC saddr of the bridged packet
902 * before invoking bridge forward logic to transmit the packet.
903 */
904static void br_nf_pre_routing_finish_bridge_slow(struct sk_buff *skb)
905{
906 struct nf_bridge_info *nf_bridge = skb->nf_bridge;
907
908 skb_pull(skb, ETH_HLEN);
909 nf_bridge->mask &= ~BRNF_BRIDGED_DNAT;
910
911 skb_copy_to_linear_data_offset(skb, -(ETH_HLEN-ETH_ALEN),
912 skb->nf_bridge->data, ETH_HLEN-ETH_ALEN);
913 skb->dev = nf_bridge->physindev;
914 br_handle_frame_finish(skb);
915}
916
917int br_nf_prerouting_finish_bridge(struct sk_buff *skb)
918{
919 if (skb->nf_bridge && (skb->nf_bridge->mask & BRNF_BRIDGED_DNAT)) {
920 br_nf_pre_routing_finish_bridge_slow(skb);
921 return 1;
922 }
923 return 0;
924}
925EXPORT_SYMBOL_GPL(br_nf_prerouting_finish_bridge);
926
895void br_netfilter_enable(void) 927void br_netfilter_enable(void)
896{ 928{
897} 929}
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index de0919975a25..d63fc17fe4f4 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -764,10 +764,15 @@ static inline int br_vlan_enabled(struct net_bridge *br)
764 764
765/* br_netfilter.c */ 765/* br_netfilter.c */
766#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) 766#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
767int br_nf_prerouting_finish_bridge(struct sk_buff *skb);
767int br_nf_core_init(void); 768int br_nf_core_init(void);
768void br_nf_core_fini(void); 769void br_nf_core_fini(void);
769void br_netfilter_rtable_init(struct net_bridge *); 770void br_netfilter_rtable_init(struct net_bridge *);
770#else 771#else
772static inline int br_nf_prerouting_finish_bridge(struct sk_buff *skb)
773{
774 return 0;
775}
771static inline int br_nf_core_init(void) { return 0; } 776static inline int br_nf_core_init(void) { return 0; }
772static inline void br_nf_core_fini(void) {} 777static inline void br_nf_core_fini(void) {}
773#define br_netfilter_rtable_init(x) 778#define br_netfilter_rtable_init(x)