diff options
-rw-r--r-- | include/linux/netfilter_bridge.h | 12 | ||||
-rw-r--r-- | net/bridge/br_device.c | 5 | ||||
-rw-r--r-- | net/bridge/br_netfilter.c | 32 | ||||
-rw-r--r-- | net/bridge/br_private.h | 5 |
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 | ||
46 | int br_handle_frame_finish(struct sk_buff *skb); | 46 | int br_handle_frame_finish(struct sk_buff *skb); |
47 | /* Only used in br_device.c */ | ||
48 | static 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 | */ | ||
904 | static 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 | |||
917 | int 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 | } | ||
925 | EXPORT_SYMBOL_GPL(br_nf_prerouting_finish_bridge); | ||
926 | |||
895 | void br_netfilter_enable(void) | 927 | void 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) |
767 | int br_nf_prerouting_finish_bridge(struct sk_buff *skb); | ||
767 | int br_nf_core_init(void); | 768 | int br_nf_core_init(void); |
768 | void br_nf_core_fini(void); | 769 | void br_nf_core_fini(void); |
769 | void br_netfilter_rtable_init(struct net_bridge *); | 770 | void br_netfilter_rtable_init(struct net_bridge *); |
770 | #else | 771 | #else |
772 | static inline int br_nf_prerouting_finish_bridge(struct sk_buff *skb) | ||
773 | { | ||
774 | return 0; | ||
775 | } | ||
771 | static inline int br_nf_core_init(void) { return 0; } | 776 | static inline int br_nf_core_init(void) { return 0; } |
772 | static inline void br_nf_core_fini(void) {} | 777 | static inline void br_nf_core_fini(void) {} |
773 | #define br_netfilter_rtable_init(x) | 778 | #define br_netfilter_rtable_init(x) |