2019-05-27 06:55:01 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* Handle firewalling
|
|
|
|
* Linux ethernet bridge
|
|
|
|
*
|
|
|
|
* Authors:
|
2010-04-13 09:40:41 +00:00
|
|
|
* Lennert Buytenhek <buytenh@gnu.org>
|
|
|
|
* Bart De Schuymer <bdschuym@pandora.be>
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
|
|
|
* Lennert dedicates this file to Kerstin Wurdinger.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/kernel.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 08:04:11 +00:00
|
|
|
#include <linux/slab.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <linux/ip.h>
|
|
|
|
#include <linux/netdevice.h>
|
|
|
|
#include <linux/skbuff.h>
|
2005-12-27 04:43:12 +00:00
|
|
|
#include <linux/if_arp.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <linux/if_ether.h>
|
|
|
|
#include <linux/if_vlan.h>
|
2007-04-13 05:14:23 +00:00
|
|
|
#include <linux/if_pppox.h>
|
|
|
|
#include <linux/ppp_defs.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <linux/netfilter_bridge.h>
|
2018-08-03 11:36:13 +00:00
|
|
|
#include <uapi/linux/netfilter_bridge.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <linux/netfilter_ipv4.h>
|
|
|
|
#include <linux/netfilter_ipv6.h>
|
|
|
|
#include <linux/netfilter_arp.h>
|
|
|
|
#include <linux/in_route.h>
|
2016-09-21 15:35:01 +00:00
|
|
|
#include <linux/rculist.h>
|
2006-12-05 21:45:21 +00:00
|
|
|
#include <linux/inetdevice.h>
|
2005-12-27 04:43:12 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <net/ip.h>
|
|
|
|
#include <net/ipv6.h>
|
2015-05-30 13:30:16 +00:00
|
|
|
#include <net/addrconf.h>
|
2005-12-27 04:43:12 +00:00
|
|
|
#include <net/route.h>
|
2014-11-13 09:04:16 +00:00
|
|
|
#include <net/netfilter/br_netfilter.h>
|
2016-02-25 09:08:37 +00:00
|
|
|
#include <net/netns/generic.h>
|
2005-12-27 04:43:12 +00:00
|
|
|
|
2016-12-24 19:46:01 +00:00
|
|
|
#include <linux/uaccess.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include "br_private.h"
|
|
|
|
#ifdef CONFIG_SYSCTL
|
|
|
|
#include <linux/sysctl.h>
|
|
|
|
#endif
|
|
|
|
|
netns: make struct pernet_operations::id unsigned int
Make struct pernet_operations::id unsigned.
There are 2 reasons to do so:
1)
This field is really an index into an zero based array and
thus is unsigned entity. Using negative value is out-of-bound
access by definition.
2)
On x86_64 unsigned 32-bit data which are mixed with pointers
via array indexing or offsets added or subtracted to pointers
are preffered to signed 32-bit data.
"int" being used as an array index needs to be sign-extended
to 64-bit before being used.
void f(long *p, int i)
{
g(p[i]);
}
roughly translates to
movsx rsi, esi
mov rdi, [rsi+...]
call g
MOVSX is 3 byte instruction which isn't necessary if the variable is
unsigned because x86_64 is zero extending by default.
Now, there is net_generic() function which, you guessed it right, uses
"int" as an array index:
static inline void *net_generic(const struct net *net, int id)
{
...
ptr = ng->ptr[id - 1];
...
}
And this function is used a lot, so those sign extensions add up.
Patch snipes ~1730 bytes on allyesconfig kernel (without all junk
messing with code generation):
add/remove: 0/0 grow/shrink: 70/598 up/down: 396/-2126 (-1730)
Unfortunately some functions actually grow bigger.
This is a semmingly random artefact of code generation with register
allocator being used differently. gcc decides that some variable
needs to live in new r8+ registers and every access now requires REX
prefix. Or it is shifted into r12, so [r12+0] addressing mode has to be
used which is longer than [r8]
However, overall balance is in negative direction:
add/remove: 0/0 grow/shrink: 70/598 up/down: 396/-2126 (-1730)
function old new delta
nfsd4_lock 3886 3959 +73
tipc_link_build_proto_msg 1096 1140 +44
mac80211_hwsim_new_radio 2776 2808 +32
tipc_mon_rcv 1032 1058 +26
svcauth_gss_legacy_init 1413 1429 +16
tipc_bcbase_select_primary 379 392 +13
nfsd4_exchange_id 1247 1260 +13
nfsd4_setclientid_confirm 782 793 +11
...
put_client_renew_locked 494 480 -14
ip_set_sockfn_get 730 716 -14
geneve_sock_add 829 813 -16
nfsd4_sequence_done 721 703 -18
nlmclnt_lookup_host 708 686 -22
nfsd4_lockt 1085 1063 -22
nfs_get_client 1077 1050 -27
tcf_bpf_init 1106 1076 -30
nfsd4_encode_fattr 5997 5930 -67
Total: Before=154856051, After=154854321, chg -0.00%
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-11-17 01:58:21 +00:00
|
|
|
static unsigned int brnf_net_id __read_mostly;
|
2016-02-25 09:08:37 +00:00
|
|
|
|
2019-06-10 21:26:05 +00:00
|
|
|
struct brnf_net {
|
|
|
|
bool enabled;
|
|
|
|
|
2019-06-10 21:26:06 +00:00
|
|
|
#ifdef CONFIG_SYSCTL
|
|
|
|
struct ctl_table_header *ctl_hdr;
|
|
|
|
#endif
|
|
|
|
|
2019-06-10 21:26:05 +00:00
|
|
|
/* default value is 1 */
|
|
|
|
int call_iptables;
|
|
|
|
int call_ip6tables;
|
|
|
|
int call_arptables;
|
|
|
|
|
|
|
|
/* default value is 0 */
|
|
|
|
int filter_vlan_tagged;
|
|
|
|
int filter_pppoe_tagged;
|
|
|
|
int pass_vlan_indev;
|
|
|
|
};
|
|
|
|
|
bridge: netfilter: don't call iptables on vlan packets if sysctl is off
When net.bridge.bridge-nf-filter-vlan-tagged is 0 (default), vlan packets
arriving should not be sent to ip(6)tables by bridge netfilter.
However, it turns out that we currently always send VLAN packets to
netfilter, if ..
a), CONFIG_VLAN_8021Q is enabled ; or
b), CONFIG_VLAN_8021Q is not set but rx vlan offload is enabled
on the bridge port.
This is because bridge netfilter treats skb with
skb->protocol == ETH_P_IP{V6} as "non-vlan packet".
With rx vlan offload on or CONFIG_VLAN_8021Q=y, the vlan header has
already been removed here, and we cannot rely on skb->protocol alone.
Fix this by only using skb->protocol if the skb has no vlan tag,
or if a vlan tag is present and filter-vlan-tagged bridge netfilter
sysctl is enabled.
We cannot remove the skb->protocol == htons(ETH_P_8021Q) test
because the vlan tag is still around in the CONFIG_VLAN_8021Q=n &&
"ethtool -K $itf rxvlan off" case.
reproducer:
iptables -t raw -I PREROUTING -i br0
iptables -t raw -I PREROUTING -i br0.1
Then send packets to an ip address configured on br0.1 interface.
Even with net.bridge.bridge-nf-filter-vlan-tagged=0, the 1st rule
will match instead of the 2nd one.
With this patch applied, the 2nd rule will match instead.
In the non-local address case, netfilter won't be consulted after
this patch unless the sysctl is switched on.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2012-03-06 01:22:54 +00:00
|
|
|
#define IS_IP(skb) \
|
2015-01-13 16:13:44 +00:00
|
|
|
(!skb_vlan_tag_present(skb) && skb->protocol == htons(ETH_P_IP))
|
bridge: netfilter: don't call iptables on vlan packets if sysctl is off
When net.bridge.bridge-nf-filter-vlan-tagged is 0 (default), vlan packets
arriving should not be sent to ip(6)tables by bridge netfilter.
However, it turns out that we currently always send VLAN packets to
netfilter, if ..
a), CONFIG_VLAN_8021Q is enabled ; or
b), CONFIG_VLAN_8021Q is not set but rx vlan offload is enabled
on the bridge port.
This is because bridge netfilter treats skb with
skb->protocol == ETH_P_IP{V6} as "non-vlan packet".
With rx vlan offload on or CONFIG_VLAN_8021Q=y, the vlan header has
already been removed here, and we cannot rely on skb->protocol alone.
Fix this by only using skb->protocol if the skb has no vlan tag,
or if a vlan tag is present and filter-vlan-tagged bridge netfilter
sysctl is enabled.
We cannot remove the skb->protocol == htons(ETH_P_8021Q) test
because the vlan tag is still around in the CONFIG_VLAN_8021Q=n &&
"ethtool -K $itf rxvlan off" case.
reproducer:
iptables -t raw -I PREROUTING -i br0
iptables -t raw -I PREROUTING -i br0.1
Then send packets to an ip address configured on br0.1 interface.
Even with net.bridge.bridge-nf-filter-vlan-tagged=0, the 1st rule
will match instead of the 2nd one.
With this patch applied, the 2nd rule will match instead.
In the non-local address case, netfilter won't be consulted after
this patch unless the sysctl is switched on.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2012-03-06 01:22:54 +00:00
|
|
|
|
|
|
|
#define IS_IPV6(skb) \
|
2015-01-13 16:13:44 +00:00
|
|
|
(!skb_vlan_tag_present(skb) && skb->protocol == htons(ETH_P_IPV6))
|
bridge: netfilter: don't call iptables on vlan packets if sysctl is off
When net.bridge.bridge-nf-filter-vlan-tagged is 0 (default), vlan packets
arriving should not be sent to ip(6)tables by bridge netfilter.
However, it turns out that we currently always send VLAN packets to
netfilter, if ..
a), CONFIG_VLAN_8021Q is enabled ; or
b), CONFIG_VLAN_8021Q is not set but rx vlan offload is enabled
on the bridge port.
This is because bridge netfilter treats skb with
skb->protocol == ETH_P_IP{V6} as "non-vlan packet".
With rx vlan offload on or CONFIG_VLAN_8021Q=y, the vlan header has
already been removed here, and we cannot rely on skb->protocol alone.
Fix this by only using skb->protocol if the skb has no vlan tag,
or if a vlan tag is present and filter-vlan-tagged bridge netfilter
sysctl is enabled.
We cannot remove the skb->protocol == htons(ETH_P_8021Q) test
because the vlan tag is still around in the CONFIG_VLAN_8021Q=n &&
"ethtool -K $itf rxvlan off" case.
reproducer:
iptables -t raw -I PREROUTING -i br0
iptables -t raw -I PREROUTING -i br0.1
Then send packets to an ip address configured on br0.1 interface.
Even with net.bridge.bridge-nf-filter-vlan-tagged=0, the 1st rule
will match instead of the 2nd one.
With this patch applied, the 2nd rule will match instead.
In the non-local address case, netfilter won't be consulted after
this patch unless the sysctl is switched on.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2012-03-06 01:22:54 +00:00
|
|
|
|
|
|
|
#define IS_ARP(skb) \
|
2015-01-13 16:13:44 +00:00
|
|
|
(!skb_vlan_tag_present(skb) && skb->protocol == htons(ETH_P_ARP))
|
bridge: netfilter: don't call iptables on vlan packets if sysctl is off
When net.bridge.bridge-nf-filter-vlan-tagged is 0 (default), vlan packets
arriving should not be sent to ip(6)tables by bridge netfilter.
However, it turns out that we currently always send VLAN packets to
netfilter, if ..
a), CONFIG_VLAN_8021Q is enabled ; or
b), CONFIG_VLAN_8021Q is not set but rx vlan offload is enabled
on the bridge port.
This is because bridge netfilter treats skb with
skb->protocol == ETH_P_IP{V6} as "non-vlan packet".
With rx vlan offload on or CONFIG_VLAN_8021Q=y, the vlan header has
already been removed here, and we cannot rely on skb->protocol alone.
Fix this by only using skb->protocol if the skb has no vlan tag,
or if a vlan tag is present and filter-vlan-tagged bridge netfilter
sysctl is enabled.
We cannot remove the skb->protocol == htons(ETH_P_8021Q) test
because the vlan tag is still around in the CONFIG_VLAN_8021Q=n &&
"ethtool -K $itf rxvlan off" case.
reproducer:
iptables -t raw -I PREROUTING -i br0
iptables -t raw -I PREROUTING -i br0.1
Then send packets to an ip address configured on br0.1 interface.
Even with net.bridge.bridge-nf-filter-vlan-tagged=0, the 1st rule
will match instead of the 2nd one.
With this patch applied, the 2nd rule will match instead.
In the non-local address case, netfilter won't be consulted after
this patch unless the sysctl is switched on.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2012-03-06 01:22:54 +00:00
|
|
|
|
2007-03-22 19:27:49 +00:00
|
|
|
static inline __be16 vlan_proto(const struct sk_buff *skb)
|
2006-03-21 06:58:05 +00:00
|
|
|
{
|
2015-01-13 16:13:44 +00:00
|
|
|
if (skb_vlan_tag_present(skb))
|
2010-10-20 13:56:01 +00:00
|
|
|
return skb->protocol;
|
|
|
|
else if (skb->protocol == htons(ETH_P_8021Q))
|
|
|
|
return vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
|
|
|
|
else
|
|
|
|
return 0;
|
2006-03-21 06:58:05 +00:00
|
|
|
}
|
|
|
|
|
2019-06-10 21:26:05 +00:00
|
|
|
static inline bool is_vlan_ip(const struct sk_buff *skb, const struct net *net)
|
|
|
|
{
|
|
|
|
struct brnf_net *brnet = net_generic(net, brnf_net_id);
|
|
|
|
|
|
|
|
return vlan_proto(skb) == htons(ETH_P_IP) && brnet->filter_vlan_tagged;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool is_vlan_ipv6(const struct sk_buff *skb,
|
|
|
|
const struct net *net)
|
|
|
|
{
|
|
|
|
struct brnf_net *brnet = net_generic(net, brnf_net_id);
|
2006-03-21 06:58:05 +00:00
|
|
|
|
2019-06-10 21:26:05 +00:00
|
|
|
return vlan_proto(skb) == htons(ETH_P_IPV6) &&
|
|
|
|
brnet->filter_vlan_tagged;
|
|
|
|
}
|
2006-03-21 06:58:05 +00:00
|
|
|
|
2019-06-10 21:26:05 +00:00
|
|
|
static inline bool is_vlan_arp(const struct sk_buff *skb, const struct net *net)
|
|
|
|
{
|
|
|
|
struct brnf_net *brnet = net_generic(net, brnf_net_id);
|
|
|
|
|
|
|
|
return vlan_proto(skb) == htons(ETH_P_ARP) && brnet->filter_vlan_tagged;
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-04-13 05:14:23 +00:00
|
|
|
static inline __be16 pppoe_proto(const struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
return *((__be16 *)(skb_mac_header(skb) + ETH_HLEN +
|
|
|
|
sizeof(struct pppoe_hdr)));
|
|
|
|
}
|
|
|
|
|
2019-06-10 21:26:05 +00:00
|
|
|
static inline bool is_pppoe_ip(const struct sk_buff *skb, const struct net *net)
|
|
|
|
{
|
|
|
|
struct brnf_net *brnet = net_generic(net, brnf_net_id);
|
|
|
|
|
|
|
|
return skb->protocol == htons(ETH_P_PPP_SES) &&
|
|
|
|
pppoe_proto(skb) == htons(PPP_IP) && brnet->filter_pppoe_tagged;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool is_pppoe_ipv6(const struct sk_buff *skb,
|
|
|
|
const struct net *net)
|
|
|
|
{
|
|
|
|
struct brnf_net *brnet = net_generic(net, brnf_net_id);
|
2007-04-13 05:14:23 +00:00
|
|
|
|
2019-06-10 21:26:05 +00:00
|
|
|
return skb->protocol == htons(ETH_P_PPP_SES) &&
|
|
|
|
pppoe_proto(skb) == htons(PPP_IPV6) &&
|
|
|
|
brnet->filter_pppoe_tagged;
|
|
|
|
}
|
2007-04-13 05:14:23 +00:00
|
|
|
|
2015-04-02 12:31:40 +00:00
|
|
|
/* largest possible L2 header, see br_nf_dev_queue_xmit() */
|
|
|
|
#define NF_BRIDGE_MAX_MAC_HEADER_LENGTH (PPPOE_SES_HLEN + ETH_HLEN)
|
|
|
|
|
|
|
|
struct brnf_frag_data {
|
|
|
|
char mac[NF_BRIDGE_MAX_MAC_HEADER_LENGTH];
|
|
|
|
u8 encap_size;
|
|
|
|
u8 size;
|
2015-06-05 11:27:13 +00:00
|
|
|
u16 vlan_tci;
|
|
|
|
__be16 vlan_proto;
|
2015-04-02 12:31:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static DEFINE_PER_CPU(struct brnf_frag_data, brnf_frag_data_storage);
|
|
|
|
|
2015-05-03 20:06:07 +00:00
|
|
|
static void nf_bridge_info_free(struct sk_buff *skb)
|
|
|
|
{
|
2018-12-18 16:15:17 +00:00
|
|
|
skb_ext_del(skb, SKB_EXT_BRIDGE_NF);
|
2015-05-03 20:06:07 +00:00
|
|
|
}
|
|
|
|
|
2006-02-10 01:09:38 +00:00
|
|
|
static inline struct net_device *bridge_parent(const struct net_device *dev)
|
|
|
|
{
|
2010-11-15 06:38:13 +00:00
|
|
|
struct net_bridge_port *port;
|
2006-02-10 01:09:38 +00:00
|
|
|
|
2010-11-15 06:38:13 +00:00
|
|
|
port = br_port_get_rcu(dev);
|
|
|
|
return port ? port->br->dev : NULL;
|
2006-02-10 01:09:38 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2008-01-20 14:25:48 +00:00
|
|
|
static inline struct nf_bridge_info *nf_bridge_unshare(struct sk_buff *skb)
|
|
|
|
{
|
2018-12-18 16:15:17 +00:00
|
|
|
return skb_ext_add(skb, SKB_EXT_BRIDGE_NF);
|
2008-01-20 14:25:48 +00:00
|
|
|
}
|
|
|
|
|
2015-06-16 12:07:03 +00:00
|
|
|
unsigned int nf_bridge_encap_header_len(const struct sk_buff *skb)
|
2015-03-18 19:55:31 +00:00
|
|
|
{
|
|
|
|
switch (skb->protocol) {
|
|
|
|
case __cpu_to_be16(ETH_P_8021Q):
|
|
|
|
return VLAN_HLEN;
|
|
|
|
case __cpu_to_be16(ETH_P_PPP_SES):
|
|
|
|
return PPPOE_SES_HLEN;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-03 10:36:16 +00:00
|
|
|
static inline void nf_bridge_pull_encap_header(struct sk_buff *skb)
|
2006-03-21 06:58:21 +00:00
|
|
|
{
|
2007-05-03 10:36:16 +00:00
|
|
|
unsigned int len = nf_bridge_encap_header_len(skb);
|
|
|
|
|
|
|
|
skb_pull(skb, len);
|
|
|
|
skb->network_header += len;
|
|
|
|
}
|
2006-03-21 06:58:21 +00:00
|
|
|
|
2007-05-03 10:36:16 +00:00
|
|
|
static inline void nf_bridge_pull_encap_header_rcsum(struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
unsigned int len = nf_bridge_encap_header_len(skb);
|
|
|
|
|
|
|
|
skb_pull_rcsum(skb, len);
|
|
|
|
skb->network_header += len;
|
|
|
|
}
|
|
|
|
|
2010-09-19 09:34:33 +00:00
|
|
|
/* When handing a packet over to the IP layer
|
|
|
|
* check whether we have a skb that is in the
|
|
|
|
* expected format
|
|
|
|
*/
|
|
|
|
|
2015-09-25 21:52:51 +00:00
|
|
|
static int br_validate_ipv4(struct net *net, struct sk_buff *skb)
|
2010-09-19 09:34:33 +00:00
|
|
|
{
|
2011-04-22 04:53:02 +00:00
|
|
|
const struct iphdr *iph;
|
2010-09-19 09:34:33 +00:00
|
|
|
u32 len;
|
|
|
|
|
2012-10-10 01:15:01 +00:00
|
|
|
if (!pskb_may_pull(skb, sizeof(struct iphdr)))
|
|
|
|
goto inhdr_error;
|
|
|
|
|
2010-09-19 09:34:33 +00:00
|
|
|
iph = ip_hdr(skb);
|
|
|
|
|
|
|
|
/* Basic sanity checks */
|
|
|
|
if (iph->ihl < 5 || iph->version != 4)
|
|
|
|
goto inhdr_error;
|
|
|
|
|
|
|
|
if (!pskb_may_pull(skb, iph->ihl*4))
|
|
|
|
goto inhdr_error;
|
|
|
|
|
|
|
|
iph = ip_hdr(skb);
|
|
|
|
if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
|
2018-02-16 19:18:15 +00:00
|
|
|
goto csum_error;
|
2010-09-19 09:34:33 +00:00
|
|
|
|
|
|
|
len = ntohs(iph->tot_len);
|
|
|
|
if (skb->len < len) {
|
2016-04-27 23:44:35 +00:00
|
|
|
__IP_INC_STATS(net, IPSTATS_MIB_INTRUNCATEDPKTS);
|
2010-09-19 09:34:33 +00:00
|
|
|
goto drop;
|
|
|
|
} else if (len < (iph->ihl*4))
|
|
|
|
goto inhdr_error;
|
|
|
|
|
|
|
|
if (pskb_trim_rcsum(skb, len)) {
|
2016-04-27 23:44:35 +00:00
|
|
|
__IP_INC_STATS(net, IPSTATS_MIB_INDISCARDS);
|
2010-09-19 09:34:33 +00:00
|
|
|
goto drop;
|
|
|
|
}
|
|
|
|
|
2011-04-12 20:39:14 +00:00
|
|
|
memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
|
2014-10-04 14:18:02 +00:00
|
|
|
/* We should really parse IP options here but until
|
|
|
|
* somebody who actually uses IP options complains to
|
|
|
|
* us we'll just silently ignore the options because
|
|
|
|
* we're lazy!
|
|
|
|
*/
|
2010-09-19 09:34:33 +00:00
|
|
|
return 0;
|
|
|
|
|
2018-02-16 19:18:15 +00:00
|
|
|
csum_error:
|
|
|
|
__IP_INC_STATS(net, IPSTATS_MIB_CSUMERRORS);
|
2010-09-19 09:34:33 +00:00
|
|
|
inhdr_error:
|
2016-04-27 23:44:35 +00:00
|
|
|
__IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS);
|
2010-09-19 09:34:33 +00:00
|
|
|
drop:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-06-16 12:07:03 +00:00
|
|
|
void nf_bridge_update_protocol(struct sk_buff *skb)
|
2015-03-04 23:52:34 +00:00
|
|
|
{
|
2018-12-18 16:15:15 +00:00
|
|
|
const struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
|
|
|
|
|
|
|
|
switch (nf_bridge->orig_proto) {
|
2015-04-02 12:31:44 +00:00
|
|
|
case BRNF_PROTO_8021Q:
|
2015-03-04 23:52:34 +00:00
|
|
|
skb->protocol = htons(ETH_P_8021Q);
|
2015-04-02 12:31:44 +00:00
|
|
|
break;
|
|
|
|
case BRNF_PROTO_PPPOE:
|
2015-03-04 23:52:34 +00:00
|
|
|
skb->protocol = htons(ETH_P_PPP_SES);
|
2015-04-02 12:31:44 +00:00
|
|
|
break;
|
|
|
|
case BRNF_PROTO_UNCHANGED:
|
|
|
|
break;
|
|
|
|
}
|
2015-03-04 23:52:34 +00:00
|
|
|
}
|
|
|
|
|
2010-04-15 10:26:39 +00:00
|
|
|
/* Obtain the correct destination MAC address, while preserving the original
|
|
|
|
* source MAC address. If we already know this address, we just copy it. If we
|
|
|
|
* don't, we use the neighbour framework to find out. In both cases, we make
|
|
|
|
* sure that br_handle_frame_finish() is called afterwards.
|
|
|
|
*/
|
2015-09-16 01:04:18 +00:00
|
|
|
int br_nf_pre_routing_finish_bridge(struct net *net, struct sock *sk, struct sk_buff *skb)
|
2010-04-15 10:26:39 +00:00
|
|
|
{
|
2011-07-14 14:53:20 +00:00
|
|
|
struct neighbour *neigh;
|
2010-04-15 10:26:39 +00:00
|
|
|
struct dst_entry *dst;
|
|
|
|
|
|
|
|
skb->dev = bridge_parent(skb->dev);
|
|
|
|
if (!skb->dev)
|
|
|
|
goto free_skb;
|
|
|
|
dst = skb_dst(skb);
|
2012-07-03 05:12:59 +00:00
|
|
|
neigh = dst_neigh_lookup_skb(dst, skb);
|
|
|
|
if (neigh) {
|
2015-04-02 12:31:43 +00:00
|
|
|
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
|
2012-07-03 05:12:59 +00:00
|
|
|
int ret;
|
|
|
|
|
2019-01-06 03:28:13 +00:00
|
|
|
if ((neigh->nud_state & NUD_CONNECTED) && neigh->hh.hh_len) {
|
2012-07-03 05:12:59 +00:00
|
|
|
neigh_hh_bridge(&neigh->hh, skb);
|
|
|
|
skb->dev = nf_bridge->physindev;
|
2015-09-16 01:04:18 +00:00
|
|
|
ret = br_handle_frame_finish(net, sk, skb);
|
2012-07-03 05:12:59 +00:00
|
|
|
} else {
|
|
|
|
/* the neighbour function below overwrites the complete
|
|
|
|
* MAC header, so we save the Ethernet source address and
|
|
|
|
* protocol number.
|
|
|
|
*/
|
|
|
|
skb_copy_from_linear_data_offset(skb,
|
|
|
|
-(ETH_HLEN-ETH_ALEN),
|
2015-04-02 12:31:40 +00:00
|
|
|
nf_bridge->neigh_header,
|
2012-07-03 05:12:59 +00:00
|
|
|
ETH_HLEN-ETH_ALEN);
|
|
|
|
/* tell br_dev_xmit to continue with forwarding */
|
2015-07-23 14:21:30 +00:00
|
|
|
nf_bridge->bridged_dnat = 1;
|
2014-10-05 04:00:22 +00:00
|
|
|
/* FIXME Need to refragment */
|
2012-07-03 05:12:59 +00:00
|
|
|
ret = neigh->output(neigh, skb);
|
|
|
|
}
|
|
|
|
neigh_release(neigh);
|
|
|
|
return ret;
|
2010-04-15 10:26:39 +00:00
|
|
|
}
|
|
|
|
free_skb:
|
|
|
|
kfree_skb(skb);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-16 12:07:03 +00:00
|
|
|
static inline bool
|
|
|
|
br_nf_ipv4_daddr_was_changed(const struct sk_buff *skb,
|
|
|
|
const struct nf_bridge_info *nf_bridge)
|
2015-05-30 13:26:57 +00:00
|
|
|
{
|
2015-06-16 12:07:03 +00:00
|
|
|
return ip_hdr(skb)->daddr != nf_bridge->ipv4_daddr;
|
2015-05-30 13:26:57 +00:00
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/* This requires some explaining. If DNAT has taken place,
|
2010-04-15 10:14:51 +00:00
|
|
|
* we will need to fix up the destination Ethernet address.
|
2015-05-20 11:42:25 +00:00
|
|
|
* This is also true when SNAT takes place (for the reply direction).
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
|
|
|
* There are two cases to consider:
|
|
|
|
* 1. The packet was DNAT'ed to a device in the same bridge
|
|
|
|
* port group as it was received on. We can still bridge
|
|
|
|
* the packet.
|
|
|
|
* 2. The packet was DNAT'ed to a different device, either
|
|
|
|
* a non-bridged device or another bridge port group.
|
|
|
|
* The packet will need to be routed.
|
|
|
|
*
|
|
|
|
* The correct way of distinguishing between these two cases is to
|
|
|
|
* call ip_route_input() and to look at skb->dst->dev, which is
|
|
|
|
* changed to the destination device if ip_route_input() succeeds.
|
|
|
|
*
|
2010-04-15 10:14:51 +00:00
|
|
|
* Let's first consider the case that ip_route_input() succeeds:
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
2010-04-15 10:14:51 +00:00
|
|
|
* If the output device equals the logical bridge device the packet
|
|
|
|
* came in on, we can consider this bridging. The corresponding MAC
|
|
|
|
* address will be obtained in br_nf_pre_routing_finish_bridge.
|
2005-04-16 22:20:36 +00:00
|
|
|
* Otherwise, the packet is considered to be routed and we just
|
|
|
|
* change the destination MAC address so that the packet will
|
2006-12-05 21:45:21 +00:00
|
|
|
* later be passed up to the IP stack to be routed. For a redirected
|
|
|
|
* packet, ip_route_input() will give back the localhost as output device,
|
|
|
|
* which differs from the bridge device.
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
2010-04-15 10:14:51 +00:00
|
|
|
* Let's now consider the case that ip_route_input() fails:
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
2006-12-05 21:45:21 +00:00
|
|
|
* This can be because the destination address is martian, in which case
|
|
|
|
* the packet will be dropped.
|
2010-04-15 10:14:51 +00:00
|
|
|
* If IP forwarding is disabled, ip_route_input() will fail, while
|
|
|
|
* ip_route_output_key() can return success. The source
|
|
|
|
* address for ip_route_output_key() is set to zero, so ip_route_output_key()
|
2005-04-16 22:20:36 +00:00
|
|
|
* thinks we're handling a locally generated packet and won't care
|
2010-04-15 10:14:51 +00:00
|
|
|
* if IP forwarding is enabled. If the output device equals the logical bridge
|
|
|
|
* device, we proceed as if ip_route_input() succeeded. If it differs from the
|
|
|
|
* logical bridge port or if ip_route_output_key() fails we drop the packet.
|
|
|
|
*/
|
2015-09-16 01:04:18 +00:00
|
|
|
static int br_nf_pre_routing_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct net_device *dev = skb->dev;
|
2007-04-21 05:47:35 +00:00
|
|
|
struct iphdr *iph = ip_hdr(skb);
|
2015-04-02 12:31:43 +00:00
|
|
|
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
|
2009-06-02 05:14:27 +00:00
|
|
|
struct rtable *rt;
|
2006-12-05 21:45:21 +00:00
|
|
|
int err;
|
2014-10-05 04:00:22 +00:00
|
|
|
|
2015-05-30 13:28:28 +00:00
|
|
|
nf_bridge->frag_max_size = IPCB(skb)->frag_max_size;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-04-02 12:31:45 +00:00
|
|
|
if (nf_bridge->pkt_otherhost) {
|
2005-04-16 22:20:36 +00:00
|
|
|
skb->pkt_type = PACKET_OTHERHOST;
|
2015-04-02 12:31:45 +00:00
|
|
|
nf_bridge->pkt_otherhost = false;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2015-07-23 14:21:30 +00:00
|
|
|
nf_bridge->in_prerouting = 0;
|
2015-06-16 12:07:03 +00:00
|
|
|
if (br_nf_ipv4_daddr_was_changed(skb, nf_bridge)) {
|
2006-12-05 21:45:21 +00:00
|
|
|
if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) {
|
2009-08-24 17:35:38 +00:00
|
|
|
struct in_device *in_dev = __in_dev_get_rcu(dev);
|
2006-12-05 21:45:21 +00:00
|
|
|
|
|
|
|
/* If err equals -EHOSTUNREACH the error is due to a
|
|
|
|
* martian destination or due to the fact that
|
|
|
|
* forwarding is disabled. For most martian packets,
|
|
|
|
* ip_route_output_key() will fail. It won't fail for 2 types of
|
|
|
|
* martian destinations: loopback destinations and destination
|
|
|
|
* 0.0.0.0. In both cases the packet will be dropped because the
|
|
|
|
* destination is the loopback device and not the bridge. */
|
|
|
|
if (err != -EHOSTUNREACH || !in_dev || IN_DEV_FORWARD(in_dev))
|
|
|
|
goto free_skb;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-09-16 01:04:14 +00:00
|
|
|
rt = ip_route_output(net, iph->daddr, 0,
|
2011-03-12 05:00:52 +00:00
|
|
|
RT_TOS(iph->tos), 0);
|
2011-03-02 22:31:35 +00:00
|
|
|
if (!IS_ERR(rt)) {
|
2005-09-15 03:55:16 +00:00
|
|
|
/* - Bridged-and-DNAT'ed traffic doesn't
|
2006-12-05 21:45:21 +00:00
|
|
|
* require ip_forwarding. */
|
2011-03-02 22:31:35 +00:00
|
|
|
if (rt->dst.dev == dev) {
|
|
|
|
skb_dst_set(skb, &rt->dst);
|
2005-04-16 22:20:36 +00:00
|
|
|
goto bridged_dnat;
|
|
|
|
}
|
2011-03-02 22:31:35 +00:00
|
|
|
ip_rt_put(rt);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2006-12-05 21:45:21 +00:00
|
|
|
free_skb:
|
2005-04-16 22:20:36 +00:00
|
|
|
kfree_skb(skb);
|
|
|
|
return 0;
|
|
|
|
} else {
|
2009-06-02 05:19:30 +00:00
|
|
|
if (skb_dst(skb)->dev == dev) {
|
2005-04-16 22:20:36 +00:00
|
|
|
bridged_dnat:
|
|
|
|
skb->dev = nf_bridge->physindev;
|
2010-04-15 10:26:39 +00:00
|
|
|
nf_bridge_update_protocol(skb);
|
2007-05-03 10:36:16 +00:00
|
|
|
nf_bridge_push_encap_header(skb);
|
2016-09-21 15:35:01 +00:00
|
|
|
br_nf_hook_thresh(NF_BR_PRE_ROUTING,
|
|
|
|
net, sk, skb, skb->dev,
|
|
|
|
NULL,
|
2016-12-30 16:46:36 +00:00
|
|
|
br_nf_pre_routing_finish_bridge);
|
2005-04-16 22:20:36 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2014-02-23 08:05:26 +00:00
|
|
|
ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr);
|
2005-04-16 22:20:36 +00:00
|
|
|
skb->pkt_type = PACKET_HOST;
|
|
|
|
}
|
|
|
|
} else {
|
2009-06-02 05:14:27 +00:00
|
|
|
rt = bridge_parent_rtable(nf_bridge->physindev);
|
|
|
|
if (!rt) {
|
2008-07-30 23:27:55 +00:00
|
|
|
kfree_skb(skb);
|
|
|
|
return 0;
|
|
|
|
}
|
2010-06-15 15:31:06 +00:00
|
|
|
skb_dst_set_noref(skb, &rt->dst);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
skb->dev = nf_bridge->physindev;
|
2010-04-15 10:26:39 +00:00
|
|
|
nf_bridge_update_protocol(skb);
|
2007-05-03 10:36:16 +00:00
|
|
|
nf_bridge_push_encap_header(skb);
|
2016-09-21 15:35:01 +00:00
|
|
|
br_nf_hook_thresh(NF_BR_PRE_ROUTING, net, sk, skb, skb->dev, NULL,
|
|
|
|
br_handle_frame_finish);
|
2005-04-16 22:20:36 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-10 21:26:05 +00:00
|
|
|
static struct net_device *brnf_get_logical_dev(struct sk_buff *skb,
|
|
|
|
const struct net_device *dev,
|
|
|
|
const struct net *net)
|
2012-05-08 17:36:44 +00:00
|
|
|
{
|
|
|
|
struct net_device *vlan, *br;
|
2019-06-10 21:26:05 +00:00
|
|
|
struct brnf_net *brnet = net_generic(net, brnf_net_id);
|
2012-05-08 17:36:44 +00:00
|
|
|
|
|
|
|
br = bridge_parent(dev);
|
2019-06-10 21:26:05 +00:00
|
|
|
|
|
|
|
if (brnet->pass_vlan_indev == 0 || !skb_vlan_tag_present(skb))
|
2012-05-08 17:36:44 +00:00
|
|
|
return br;
|
|
|
|
|
2014-05-09 06:58:05 +00:00
|
|
|
vlan = __vlan_find_dev_deep_rcu(br, skb->vlan_proto,
|
2015-01-13 16:13:44 +00:00
|
|
|
skb_vlan_tag_get(skb) & VLAN_VID_MASK);
|
2012-05-08 17:36:44 +00:00
|
|
|
|
|
|
|
return vlan ? vlan : br;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/* Some common code for IPv4/IPv6 */
|
2019-06-10 21:26:05 +00:00
|
|
|
struct net_device *setup_pre_routing(struct sk_buff *skb, const struct net *net)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2015-04-02 12:31:43 +00:00
|
|
|
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
if (skb->pkt_type == PACKET_OTHERHOST) {
|
|
|
|
skb->pkt_type = PACKET_HOST;
|
2015-04-02 12:31:45 +00:00
|
|
|
nf_bridge->pkt_otherhost = true;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2015-07-23 14:21:30 +00:00
|
|
|
nf_bridge->in_prerouting = 1;
|
2005-04-16 22:20:36 +00:00
|
|
|
nf_bridge->physindev = skb->dev;
|
2019-06-10 21:26:05 +00:00
|
|
|
skb->dev = brnf_get_logical_dev(skb, skb->dev, net);
|
2015-04-02 12:31:44 +00:00
|
|
|
|
2010-04-15 10:26:39 +00:00
|
|
|
if (skb->protocol == htons(ETH_P_8021Q))
|
2015-04-02 12:31:44 +00:00
|
|
|
nf_bridge->orig_proto = BRNF_PROTO_8021Q;
|
2010-04-15 10:26:39 +00:00
|
|
|
else if (skb->protocol == htons(ETH_P_PPP_SES))
|
2015-04-02 12:31:44 +00:00
|
|
|
nf_bridge->orig_proto = BRNF_PROTO_PPPOE;
|
2006-02-10 01:09:38 +00:00
|
|
|
|
2013-10-24 19:32:42 +00:00
|
|
|
/* Must drop socket now because of tproxy. */
|
|
|
|
skb_orphan(skb);
|
2006-02-10 01:09:38 +00:00
|
|
|
return skb->dev;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Direct IPv6 traffic to br_nf_pre_routing_ipv6.
|
|
|
|
* Replicate the checks that IPv4 does on packet reception.
|
|
|
|
* Set skb->dev to the bridge device (i.e. parent of the
|
|
|
|
* receiving device) to make netfilter happy, the REDIRECT
|
|
|
|
* target in particular. Save the original destination IP
|
|
|
|
* address to be able to detect DNAT afterwards. */
|
2015-09-18 19:33:06 +00:00
|
|
|
static unsigned int br_nf_pre_routing(void *priv,
|
2013-10-10 07:21:55 +00:00
|
|
|
struct sk_buff *skb,
|
2015-04-04 00:32:56 +00:00
|
|
|
const struct nf_hook_state *state)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2015-05-20 11:42:25 +00:00
|
|
|
struct nf_bridge_info *nf_bridge;
|
2010-07-02 07:32:57 +00:00
|
|
|
struct net_bridge_port *p;
|
|
|
|
struct net_bridge *br;
|
2007-08-25 06:36:29 +00:00
|
|
|
__u32 len = nf_bridge_encap_header_len(skb);
|
2019-06-10 21:26:05 +00:00
|
|
|
struct brnf_net *brnet;
|
2007-08-25 06:36:29 +00:00
|
|
|
|
|
|
|
if (unlikely(!pskb_may_pull(skb, len)))
|
2010-12-09 17:38:11 +00:00
|
|
|
return NF_DROP;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-04-04 00:32:56 +00:00
|
|
|
p = br_port_get_rcu(state->in);
|
2010-07-02 07:32:57 +00:00
|
|
|
if (p == NULL)
|
2010-12-09 17:38:11 +00:00
|
|
|
return NF_DROP;
|
2010-07-02 07:32:57 +00:00
|
|
|
br = p->br;
|
|
|
|
|
2019-06-10 21:26:05 +00:00
|
|
|
brnet = net_generic(state->net, brnf_net_id);
|
|
|
|
if (IS_IPV6(skb) || is_vlan_ipv6(skb, state->net) ||
|
|
|
|
is_pppoe_ipv6(skb, state->net)) {
|
|
|
|
if (!brnet->call_ip6tables &&
|
2018-09-26 14:01:01 +00:00
|
|
|
!br_opt_get(br, BROPT_NF_CALL_IP6TABLES))
|
2005-04-16 22:20:36 +00:00
|
|
|
return NF_ACCEPT;
|
2019-08-31 04:40:33 +00:00
|
|
|
if (!ipv6_mod_enabled()) {
|
|
|
|
pr_warn_once("Module ipv6 is disabled, so call_ip6tables is not supported.");
|
|
|
|
return NF_DROP;
|
|
|
|
}
|
2010-07-02 07:32:57 +00:00
|
|
|
|
2007-05-03 10:36:16 +00:00
|
|
|
nf_bridge_pull_encap_header_rcsum(skb);
|
2015-09-18 19:33:06 +00:00
|
|
|
return br_nf_pre_routing_ipv6(priv, skb, state);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2010-07-02 07:32:57 +00:00
|
|
|
|
2019-06-10 21:26:05 +00:00
|
|
|
if (!brnet->call_iptables && !br_opt_get(br, BROPT_NF_CALL_IPTABLES))
|
2005-04-16 22:20:36 +00:00
|
|
|
return NF_ACCEPT;
|
|
|
|
|
2019-06-10 21:26:05 +00:00
|
|
|
if (!IS_IP(skb) && !is_vlan_ip(skb, state->net) &&
|
|
|
|
!is_pppoe_ip(skb, state->net))
|
2005-04-16 22:20:36 +00:00
|
|
|
return NF_ACCEPT;
|
|
|
|
|
2007-05-03 10:36:16 +00:00
|
|
|
nf_bridge_pull_encap_header_rcsum(skb);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-09-25 21:52:51 +00:00
|
|
|
if (br_validate_ipv4(state->net, skb))
|
2010-12-09 17:38:11 +00:00
|
|
|
return NF_DROP;
|
2010-07-05 21:29:28 +00:00
|
|
|
|
2006-03-21 06:58:21 +00:00
|
|
|
if (!nf_bridge_alloc(skb))
|
2005-04-16 22:20:36 +00:00
|
|
|
return NF_DROP;
|
2019-06-10 21:26:05 +00:00
|
|
|
if (!setup_pre_routing(skb, state->net))
|
2006-02-10 01:09:38 +00:00
|
|
|
return NF_DROP;
|
2015-03-10 04:08:19 +00:00
|
|
|
|
2015-05-20 11:42:25 +00:00
|
|
|
nf_bridge = nf_bridge_info_get(skb);
|
|
|
|
nf_bridge->ipv4_daddr = ip_hdr(skb)->daddr;
|
|
|
|
|
2010-04-15 10:26:39 +00:00
|
|
|
skb->protocol = htons(ETH_P_IP);
|
2019-03-13 08:33:29 +00:00
|
|
|
skb->transport_header = skb->network_header + ip_hdr(skb)->ihl * 4;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-09-16 01:04:16 +00:00
|
|
|
NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, state->net, state->sk, skb,
|
2015-04-06 02:19:04 +00:00
|
|
|
skb->dev, NULL,
|
2005-04-16 22:20:36 +00:00
|
|
|
br_nf_pre_routing_finish);
|
|
|
|
|
|
|
|
return NF_STOLEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* PF_BRIDGE/FORWARD *************************************************/
|
2015-09-16 01:04:18 +00:00
|
|
|
static int br_nf_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2015-04-02 12:31:43 +00:00
|
|
|
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
|
2005-04-16 22:20:36 +00:00
|
|
|
struct net_device *in;
|
|
|
|
|
2019-06-10 21:26:05 +00:00
|
|
|
if (!IS_ARP(skb) && !is_vlan_arp(skb, net)) {
|
2015-04-01 20:36:27 +00:00
|
|
|
|
2015-05-30 13:30:16 +00:00
|
|
|
if (skb->protocol == htons(ETH_P_IP))
|
2015-05-30 13:28:28 +00:00
|
|
|
nf_bridge->frag_max_size = IPCB(skb)->frag_max_size;
|
2015-05-30 13:30:16 +00:00
|
|
|
|
|
|
|
if (skb->protocol == htons(ETH_P_IPV6))
|
|
|
|
nf_bridge->frag_max_size = IP6CB(skb)->frag_max_size;
|
2015-04-01 20:36:27 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
in = nf_bridge->physindev;
|
2015-04-02 12:31:45 +00:00
|
|
|
if (nf_bridge->pkt_otherhost) {
|
2005-04-16 22:20:36 +00:00
|
|
|
skb->pkt_type = PACKET_OTHERHOST;
|
2015-04-02 12:31:45 +00:00
|
|
|
nf_bridge->pkt_otherhost = false;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2010-05-13 12:55:34 +00:00
|
|
|
nf_bridge_update_protocol(skb);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
|
|
|
in = *((struct net_device **)(skb->cb));
|
|
|
|
}
|
2007-05-03 10:36:16 +00:00
|
|
|
nf_bridge_push_encap_header(skb);
|
2010-04-15 10:26:39 +00:00
|
|
|
|
2016-11-03 09:56:12 +00:00
|
|
|
br_nf_hook_thresh(NF_BR_FORWARD, net, sk, skb, in, skb->dev,
|
|
|
|
br_forward_finish);
|
2005-04-16 22:20:36 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
bridge: netfilter: don't call iptables on vlan packets if sysctl is off
When net.bridge.bridge-nf-filter-vlan-tagged is 0 (default), vlan packets
arriving should not be sent to ip(6)tables by bridge netfilter.
However, it turns out that we currently always send VLAN packets to
netfilter, if ..
a), CONFIG_VLAN_8021Q is enabled ; or
b), CONFIG_VLAN_8021Q is not set but rx vlan offload is enabled
on the bridge port.
This is because bridge netfilter treats skb with
skb->protocol == ETH_P_IP{V6} as "non-vlan packet".
With rx vlan offload on or CONFIG_VLAN_8021Q=y, the vlan header has
already been removed here, and we cannot rely on skb->protocol alone.
Fix this by only using skb->protocol if the skb has no vlan tag,
or if a vlan tag is present and filter-vlan-tagged bridge netfilter
sysctl is enabled.
We cannot remove the skb->protocol == htons(ETH_P_8021Q) test
because the vlan tag is still around in the CONFIG_VLAN_8021Q=n &&
"ethtool -K $itf rxvlan off" case.
reproducer:
iptables -t raw -I PREROUTING -i br0
iptables -t raw -I PREROUTING -i br0.1
Then send packets to an ip address configured on br0.1 interface.
Even with net.bridge.bridge-nf-filter-vlan-tagged=0, the 1st rule
will match instead of the 2nd one.
With this patch applied, the 2nd rule will match instead.
In the non-local address case, netfilter won't be consulted after
this patch unless the sysctl is switched on.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2012-03-06 01:22:54 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/* This is the 'purely bridged' case. For IP, we pass the packet to
|
|
|
|
* netfilter with indev and outdev set to the bridge device,
|
|
|
|
* but we are still able to filter on the 'real' indev/outdev
|
|
|
|
* because of the physdev module. For ARP, indev and outdev are the
|
|
|
|
* bridge ports. */
|
2015-09-18 19:33:06 +00:00
|
|
|
static unsigned int br_nf_forward_ip(void *priv,
|
2013-10-10 07:21:55 +00:00
|
|
|
struct sk_buff *skb,
|
2015-04-04 00:32:56 +00:00
|
|
|
const struct nf_hook_state *state)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct nf_bridge_info *nf_bridge;
|
2006-02-10 01:09:38 +00:00
|
|
|
struct net_device *parent;
|
2008-10-08 09:35:00 +00:00
|
|
|
u_int8_t pf;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2018-12-18 16:15:15 +00:00
|
|
|
nf_bridge = nf_bridge_info_get(skb);
|
|
|
|
if (!nf_bridge)
|
2005-04-16 22:20:36 +00:00
|
|
|
return NF_ACCEPT;
|
|
|
|
|
2008-01-20 14:25:48 +00:00
|
|
|
/* Need exclusive nf_bridge_info since we might have multiple
|
|
|
|
* different physoutdevs. */
|
|
|
|
if (!nf_bridge_unshare(skb))
|
|
|
|
return NF_DROP;
|
|
|
|
|
2015-04-02 12:31:43 +00:00
|
|
|
nf_bridge = nf_bridge_info_get(skb);
|
|
|
|
if (!nf_bridge)
|
|
|
|
return NF_DROP;
|
|
|
|
|
2015-04-04 00:32:56 +00:00
|
|
|
parent = bridge_parent(state->out);
|
2006-02-10 01:09:38 +00:00
|
|
|
if (!parent)
|
|
|
|
return NF_DROP;
|
|
|
|
|
2019-06-10 21:26:05 +00:00
|
|
|
if (IS_IP(skb) || is_vlan_ip(skb, state->net) ||
|
|
|
|
is_pppoe_ip(skb, state->net))
|
2012-05-14 03:56:36 +00:00
|
|
|
pf = NFPROTO_IPV4;
|
2019-06-10 21:26:05 +00:00
|
|
|
else if (IS_IPV6(skb) || is_vlan_ipv6(skb, state->net) ||
|
|
|
|
is_pppoe_ipv6(skb, state->net))
|
2012-05-14 03:56:36 +00:00
|
|
|
pf = NFPROTO_IPV6;
|
2009-01-12 00:06:02 +00:00
|
|
|
else
|
|
|
|
return NF_ACCEPT;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-10-15 07:53:15 +00:00
|
|
|
nf_bridge_pull_encap_header(skb);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
if (skb->pkt_type == PACKET_OTHERHOST) {
|
|
|
|
skb->pkt_type = PACKET_HOST;
|
2015-04-02 12:31:45 +00:00
|
|
|
nf_bridge->pkt_otherhost = true;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2015-04-01 20:36:27 +00:00
|
|
|
if (pf == NFPROTO_IPV4) {
|
2015-09-25 21:52:51 +00:00
|
|
|
if (br_validate_ipv4(state->net, skb))
|
2015-04-01 20:36:27 +00:00
|
|
|
return NF_DROP;
|
2015-05-30 13:28:28 +00:00
|
|
|
IPCB(skb)->frag_max_size = nf_bridge->frag_max_size;
|
2015-04-01 20:36:27 +00:00
|
|
|
}
|
2011-03-18 05:27:28 +00:00
|
|
|
|
2015-05-30 13:30:16 +00:00
|
|
|
if (pf == NFPROTO_IPV6) {
|
2015-09-25 21:52:51 +00:00
|
|
|
if (br_validate_ipv6(state->net, skb))
|
2015-05-30 13:30:16 +00:00
|
|
|
return NF_DROP;
|
|
|
|
IP6CB(skb)->frag_max_size = nf_bridge->frag_max_size;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
nf_bridge->physoutdev = skb->dev;
|
2012-05-14 03:56:36 +00:00
|
|
|
if (pf == NFPROTO_IPV4)
|
2010-04-15 10:26:39 +00:00
|
|
|
skb->protocol = htons(ETH_P_IP);
|
|
|
|
else
|
|
|
|
skb->protocol = htons(ETH_P_IPV6);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-09-16 01:04:16 +00:00
|
|
|
NF_HOOK(pf, NF_INET_FORWARD, state->net, NULL, skb,
|
2019-06-10 21:26:05 +00:00
|
|
|
brnf_get_logical_dev(skb, state->in, state->net),
|
2015-04-04 00:32:56 +00:00
|
|
|
parent, br_nf_forward_finish);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
return NF_STOLEN;
|
|
|
|
}
|
|
|
|
|
2015-09-18 19:33:06 +00:00
|
|
|
static unsigned int br_nf_forward_arp(void *priv,
|
2013-10-10 07:21:55 +00:00
|
|
|
struct sk_buff *skb,
|
2015-04-04 00:32:56 +00:00
|
|
|
const struct nf_hook_state *state)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2010-07-02 07:32:57 +00:00
|
|
|
struct net_bridge_port *p;
|
|
|
|
struct net_bridge *br;
|
2005-04-16 22:20:36 +00:00
|
|
|
struct net_device **d = (struct net_device **)(skb->cb);
|
2019-06-10 21:26:05 +00:00
|
|
|
struct brnf_net *brnet;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-04-04 00:32:56 +00:00
|
|
|
p = br_port_get_rcu(state->out);
|
2010-07-02 07:32:57 +00:00
|
|
|
if (p == NULL)
|
|
|
|
return NF_ACCEPT;
|
|
|
|
br = p->br;
|
|
|
|
|
2019-06-10 21:26:05 +00:00
|
|
|
brnet = net_generic(state->net, brnf_net_id);
|
|
|
|
if (!brnet->call_arptables && !br_opt_get(br, BROPT_NF_CALL_ARPTABLES))
|
2005-04-16 22:20:36 +00:00
|
|
|
return NF_ACCEPT;
|
|
|
|
|
bridge: netfilter: don't call iptables on vlan packets if sysctl is off
When net.bridge.bridge-nf-filter-vlan-tagged is 0 (default), vlan packets
arriving should not be sent to ip(6)tables by bridge netfilter.
However, it turns out that we currently always send VLAN packets to
netfilter, if ..
a), CONFIG_VLAN_8021Q is enabled ; or
b), CONFIG_VLAN_8021Q is not set but rx vlan offload is enabled
on the bridge port.
This is because bridge netfilter treats skb with
skb->protocol == ETH_P_IP{V6} as "non-vlan packet".
With rx vlan offload on or CONFIG_VLAN_8021Q=y, the vlan header has
already been removed here, and we cannot rely on skb->protocol alone.
Fix this by only using skb->protocol if the skb has no vlan tag,
or if a vlan tag is present and filter-vlan-tagged bridge netfilter
sysctl is enabled.
We cannot remove the skb->protocol == htons(ETH_P_8021Q) test
because the vlan tag is still around in the CONFIG_VLAN_8021Q=n &&
"ethtool -K $itf rxvlan off" case.
reproducer:
iptables -t raw -I PREROUTING -i br0
iptables -t raw -I PREROUTING -i br0.1
Then send packets to an ip address configured on br0.1 interface.
Even with net.bridge.bridge-nf-filter-vlan-tagged=0, the 1st rule
will match instead of the 2nd one.
With this patch applied, the 2nd rule will match instead.
In the non-local address case, netfilter won't be consulted after
this patch unless the sysctl is switched on.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2012-03-06 01:22:54 +00:00
|
|
|
if (!IS_ARP(skb)) {
|
2019-06-10 21:26:05 +00:00
|
|
|
if (!is_vlan_arp(skb, state->net))
|
2005-04-16 22:20:36 +00:00
|
|
|
return NF_ACCEPT;
|
2007-10-15 07:53:15 +00:00
|
|
|
nf_bridge_pull_encap_header(skb);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2019-12-07 22:43:39 +00:00
|
|
|
if (unlikely(!pskb_may_pull(skb, sizeof(struct arphdr))))
|
|
|
|
return NF_DROP;
|
|
|
|
|
2007-03-12 23:56:31 +00:00
|
|
|
if (arp_hdr(skb)->ar_pln != 4) {
|
2019-06-10 21:26:05 +00:00
|
|
|
if (is_vlan_arp(skb, state->net))
|
2007-10-15 07:53:15 +00:00
|
|
|
nf_bridge_push_encap_header(skb);
|
2005-04-16 22:20:36 +00:00
|
|
|
return NF_ACCEPT;
|
|
|
|
}
|
2015-04-04 00:32:56 +00:00
|
|
|
*d = state->in;
|
2015-09-16 01:04:16 +00:00
|
|
|
NF_HOOK(NFPROTO_ARP, NF_ARP_FORWARD, state->net, state->sk, skb,
|
2015-04-06 02:19:04 +00:00
|
|
|
state->in, state->out, br_nf_forward_finish);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
return NF_STOLEN;
|
|
|
|
}
|
|
|
|
|
2015-09-16 01:04:13 +00:00
|
|
|
static int br_nf_push_frag_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)
|
2015-03-04 23:52:33 +00:00
|
|
|
{
|
2015-04-02 12:31:40 +00:00
|
|
|
struct brnf_frag_data *data;
|
2015-03-04 23:52:33 +00:00
|
|
|
int err;
|
|
|
|
|
2015-04-02 12:31:40 +00:00
|
|
|
data = this_cpu_ptr(&brnf_frag_data_storage);
|
|
|
|
err = skb_cow_head(skb, data->size);
|
2015-03-04 23:52:33 +00:00
|
|
|
|
2015-04-02 12:31:40 +00:00
|
|
|
if (err) {
|
2015-03-04 23:52:33 +00:00
|
|
|
kfree_skb(skb);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-08 23:18:03 +00:00
|
|
|
if (data->vlan_proto)
|
|
|
|
__vlan_hwaccel_put_tag(skb, data->vlan_proto, data->vlan_tci);
|
2015-06-05 11:27:13 +00:00
|
|
|
|
2015-04-02 12:31:40 +00:00
|
|
|
skb_copy_to_linear_data_offset(skb, -data->size, data->mac, data->size);
|
|
|
|
__skb_push(skb, data->encap_size);
|
|
|
|
|
2015-05-03 20:06:07 +00:00
|
|
|
nf_bridge_info_free(skb);
|
2015-09-16 01:04:18 +00:00
|
|
|
return br_dev_queue_push_xmit(net, sk, skb);
|
2015-03-04 23:52:33 +00:00
|
|
|
}
|
|
|
|
|
2015-09-16 01:04:12 +00:00
|
|
|
static int
|
|
|
|
br_nf_ip_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
2015-06-13 02:55:31 +00:00
|
|
|
int (*output)(struct net *, struct sock *, struct sk_buff *))
|
2015-05-15 21:15:37 +00:00
|
|
|
{
|
2016-06-29 18:47:03 +00:00
|
|
|
unsigned int mtu = ip_skb_dst_mtu(sk, skb);
|
2015-05-15 21:15:37 +00:00
|
|
|
struct iphdr *iph = ip_hdr(skb);
|
|
|
|
|
|
|
|
if (unlikely(((iph->frag_off & htons(IP_DF)) && !skb->ignore_df) ||
|
|
|
|
(IPCB(skb)->frag_max_size &&
|
|
|
|
IPCB(skb)->frag_max_size > mtu))) {
|
2015-09-16 01:04:12 +00:00
|
|
|
IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS);
|
2015-05-15 21:15:37 +00:00
|
|
|
kfree_skb(skb);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
2015-06-13 02:55:31 +00:00
|
|
|
return ip_do_fragment(net, sk, skb, output);
|
2015-05-15 21:15:37 +00:00
|
|
|
}
|
|
|
|
|
2015-06-05 11:28:38 +00:00
|
|
|
static unsigned int nf_bridge_mtu_reduction(const struct sk_buff *skb)
|
|
|
|
{
|
2018-12-18 16:15:15 +00:00
|
|
|
const struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
|
|
|
|
|
|
|
|
if (nf_bridge->orig_proto == BRNF_PROTO_PPPOE)
|
2015-06-05 11:28:38 +00:00
|
|
|
return PPPOE_SES_HLEN;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-16 01:04:18 +00:00
|
|
|
static int br_nf_dev_queue_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)
|
2006-04-04 20:42:35 +00:00
|
|
|
{
|
2017-03-09 22:22:30 +00:00
|
|
|
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
|
|
|
|
unsigned int mtu, mtu_reserved;
|
2010-09-19 09:34:33 +00:00
|
|
|
|
2015-05-30 13:30:16 +00:00
|
|
|
mtu_reserved = nf_bridge_mtu_reduction(skb);
|
2017-03-09 22:22:30 +00:00
|
|
|
mtu = skb->dev->mtu;
|
|
|
|
|
2020-11-23 17:49:02 +00:00
|
|
|
if (nf_bridge->pkt_otherhost) {
|
|
|
|
skb->pkt_type = PACKET_OTHERHOST;
|
|
|
|
nf_bridge->pkt_otherhost = false;
|
|
|
|
}
|
|
|
|
|
2017-03-09 22:22:30 +00:00
|
|
|
if (nf_bridge->frag_max_size && nf_bridge->frag_max_size < mtu)
|
|
|
|
mtu = nf_bridge->frag_max_size;
|
2015-05-30 13:30:16 +00:00
|
|
|
|
2021-11-23 11:50:31 +00:00
|
|
|
nf_bridge_update_protocol(skb);
|
|
|
|
nf_bridge_push_encap_header(skb);
|
|
|
|
|
2017-03-09 22:22:30 +00:00
|
|
|
if (skb_is_gso(skb) || skb->len + mtu_reserved <= mtu) {
|
2015-05-03 20:06:07 +00:00
|
|
|
nf_bridge_info_free(skb);
|
2015-09-16 01:04:18 +00:00
|
|
|
return br_dev_queue_push_xmit(net, sk, skb);
|
2015-05-03 20:06:07 +00:00
|
|
|
}
|
2015-03-04 23:52:36 +00:00
|
|
|
|
2014-10-05 04:00:22 +00:00
|
|
|
/* This is wrong! We should preserve the original fragment
|
|
|
|
* boundaries by preserving frag_list rather than refragmenting.
|
|
|
|
*/
|
2015-10-08 12:30:15 +00:00
|
|
|
if (IS_ENABLED(CONFIG_NF_DEFRAG_IPV4) &&
|
|
|
|
skb->protocol == htons(ETH_P_IP)) {
|
2015-04-02 12:31:40 +00:00
|
|
|
struct brnf_frag_data *data;
|
|
|
|
|
2015-09-25 21:52:51 +00:00
|
|
|
if (br_validate_ipv4(net, skb))
|
2015-06-30 20:27:51 +00:00
|
|
|
goto drop;
|
2015-05-30 13:28:28 +00:00
|
|
|
|
|
|
|
IPCB(skb)->frag_max_size = nf_bridge->frag_max_size;
|
2015-04-02 12:31:40 +00:00
|
|
|
|
|
|
|
data = this_cpu_ptr(&brnf_frag_data_storage);
|
2015-06-05 11:27:13 +00:00
|
|
|
|
2018-11-08 23:18:03 +00:00
|
|
|
if (skb_vlan_tag_present(skb)) {
|
|
|
|
data->vlan_tci = skb->vlan_tci;
|
|
|
|
data->vlan_proto = skb->vlan_proto;
|
|
|
|
} else {
|
|
|
|
data->vlan_proto = 0;
|
|
|
|
}
|
|
|
|
|
2015-04-02 12:31:40 +00:00
|
|
|
data->encap_size = nf_bridge_encap_header_len(skb);
|
|
|
|
data->size = ETH_HLEN + data->encap_size;
|
|
|
|
|
|
|
|
skb_copy_from_linear_data_offset(skb, -data->size, data->mac,
|
|
|
|
data->size);
|
|
|
|
|
2015-06-13 02:55:31 +00:00
|
|
|
return br_nf_ip_fragment(net, sk, skb, br_nf_push_frag_xmit);
|
2015-04-02 12:31:40 +00:00
|
|
|
}
|
2015-10-08 12:30:15 +00:00
|
|
|
if (IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) &&
|
|
|
|
skb->protocol == htons(ETH_P_IPV6)) {
|
2015-05-30 13:30:16 +00:00
|
|
|
const struct nf_ipv6_ops *v6ops = nf_get_ipv6_ops();
|
|
|
|
struct brnf_frag_data *data;
|
2010-09-19 09:34:33 +00:00
|
|
|
|
2015-09-25 21:52:51 +00:00
|
|
|
if (br_validate_ipv6(net, skb))
|
2015-06-30 20:27:51 +00:00
|
|
|
goto drop;
|
2015-05-30 13:30:16 +00:00
|
|
|
|
|
|
|
IP6CB(skb)->frag_max_size = nf_bridge->frag_max_size;
|
|
|
|
|
|
|
|
data = this_cpu_ptr(&brnf_frag_data_storage);
|
|
|
|
data->encap_size = nf_bridge_encap_header_len(skb);
|
|
|
|
data->size = ETH_HLEN + data->encap_size;
|
|
|
|
|
|
|
|
skb_copy_from_linear_data_offset(skb, -data->size, data->mac,
|
|
|
|
data->size);
|
|
|
|
|
|
|
|
if (v6ops)
|
2015-06-13 03:12:04 +00:00
|
|
|
return v6ops->fragment(net, sk, skb, br_nf_push_frag_xmit);
|
2015-06-30 20:27:51 +00:00
|
|
|
|
|
|
|
kfree_skb(skb);
|
|
|
|
return -EMSGSIZE;
|
2015-05-30 13:30:16 +00:00
|
|
|
}
|
2015-05-03 20:06:07 +00:00
|
|
|
nf_bridge_info_free(skb);
|
2015-09-16 01:04:18 +00:00
|
|
|
return br_dev_queue_push_xmit(net, sk, skb);
|
2015-06-30 20:27:51 +00:00
|
|
|
drop:
|
|
|
|
kfree_skb(skb);
|
|
|
|
return 0;
|
2009-04-20 15:12:35 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/* PF_BRIDGE/POST_ROUTING ********************************************/
|
2015-09-18 19:33:06 +00:00
|
|
|
static unsigned int br_nf_post_routing(void *priv,
|
2013-10-10 07:21:55 +00:00
|
|
|
struct sk_buff *skb,
|
2015-04-04 00:32:56 +00:00
|
|
|
const struct nf_hook_state *state)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2015-04-02 12:31:43 +00:00
|
|
|
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
|
2005-04-16 22:20:36 +00:00
|
|
|
struct net_device *realoutdev = bridge_parent(skb->dev);
|
2008-10-08 09:35:00 +00:00
|
|
|
u_int8_t pf;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-03-10 09:36:48 +00:00
|
|
|
/* if nf_bridge is set, but ->physoutdev is NULL, this packet came in
|
|
|
|
* on a bridge, but was delivered locally and is now being routed:
|
|
|
|
*
|
|
|
|
* POST_ROUTING was already invoked from the ip stack.
|
|
|
|
*/
|
|
|
|
if (!nf_bridge || !nf_bridge->physoutdev)
|
2007-11-13 10:58:44 +00:00
|
|
|
return NF_ACCEPT;
|
|
|
|
|
2006-02-10 01:09:38 +00:00
|
|
|
if (!realoutdev)
|
|
|
|
return NF_DROP;
|
|
|
|
|
2019-06-10 21:26:05 +00:00
|
|
|
if (IS_IP(skb) || is_vlan_ip(skb, state->net) ||
|
|
|
|
is_pppoe_ip(skb, state->net))
|
2012-05-14 03:56:36 +00:00
|
|
|
pf = NFPROTO_IPV4;
|
2019-06-10 21:26:05 +00:00
|
|
|
else if (IS_IPV6(skb) || is_vlan_ipv6(skb, state->net) ||
|
|
|
|
is_pppoe_ipv6(skb, state->net))
|
2012-05-14 03:56:36 +00:00
|
|
|
pf = NFPROTO_IPV6;
|
2009-01-12 00:06:02 +00:00
|
|
|
else
|
|
|
|
return NF_ACCEPT;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
if (skb->pkt_type == PACKET_OTHERHOST) {
|
|
|
|
skb->pkt_type = PACKET_HOST;
|
2015-04-02 12:31:45 +00:00
|
|
|
nf_bridge->pkt_otherhost = true;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2007-05-03 10:36:16 +00:00
|
|
|
nf_bridge_pull_encap_header(skb);
|
2012-05-14 03:56:36 +00:00
|
|
|
if (pf == NFPROTO_IPV4)
|
2010-04-15 10:26:39 +00:00
|
|
|
skb->protocol = htons(ETH_P_IP);
|
|
|
|
else
|
|
|
|
skb->protocol = htons(ETH_P_IPV6);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-09-16 01:04:16 +00:00
|
|
|
NF_HOOK(pf, NF_INET_POST_ROUTING, state->net, state->sk, skb,
|
2015-04-06 02:19:04 +00:00
|
|
|
NULL, realoutdev,
|
2006-04-04 20:42:35 +00:00
|
|
|
br_nf_dev_queue_xmit);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
return NF_STOLEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* IP/SABOTAGE *****************************************************/
|
|
|
|
/* Don't hand locally destined packets to PF_INET(6)/PRE_ROUTING
|
|
|
|
* for the second time. */
|
2015-09-18 19:33:06 +00:00
|
|
|
static unsigned int ip_sabotage_in(void *priv,
|
2013-10-10 07:21:55 +00:00
|
|
|
struct sk_buff *skb,
|
2015-04-04 00:32:56 +00:00
|
|
|
const struct nf_hook_state *state)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2018-12-18 16:15:15 +00:00
|
|
|
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
|
|
|
|
|
|
|
|
if (nf_bridge && !nf_bridge->in_prerouting &&
|
2019-02-26 00:21:14 +00:00
|
|
|
!netif_is_l3_master(skb->dev) &&
|
|
|
|
!netif_is_l3_slave(skb->dev)) {
|
2016-11-03 09:56:17 +00:00
|
|
|
state->okfn(state->net, state->sk, skb);
|
|
|
|
return NF_STOLEN;
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
return NF_ACCEPT;
|
|
|
|
}
|
|
|
|
|
2015-03-09 11:30:12 +00:00
|
|
|
/* 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)
|
|
|
|
{
|
2015-04-02 12:31:43 +00:00
|
|
|
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
|
2015-03-09 11:30:12 +00:00
|
|
|
|
|
|
|
skb_pull(skb, ETH_HLEN);
|
2015-07-23 14:21:30 +00:00
|
|
|
nf_bridge->bridged_dnat = 0;
|
2015-03-09 11:30:12 +00:00
|
|
|
|
2015-04-02 12:31:40 +00:00
|
|
|
BUILD_BUG_ON(sizeof(nf_bridge->neigh_header) != (ETH_HLEN - ETH_ALEN));
|
|
|
|
|
|
|
|
skb_copy_to_linear_data_offset(skb, -(ETH_HLEN - ETH_ALEN),
|
|
|
|
nf_bridge->neigh_header,
|
|
|
|
ETH_HLEN - ETH_ALEN);
|
2015-03-09 11:30:12 +00:00
|
|
|
skb->dev = nf_bridge->physindev;
|
2015-05-03 20:05:28 +00:00
|
|
|
|
|
|
|
nf_bridge->physoutdev = NULL;
|
2015-09-16 01:04:18 +00:00
|
|
|
br_handle_frame_finish(dev_net(skb->dev), NULL, skb);
|
2015-03-09 11:30:12 +00:00
|
|
|
}
|
|
|
|
|
2015-03-10 09:27:18 +00:00
|
|
|
static int br_nf_dev_xmit(struct sk_buff *skb)
|
2015-03-09 11:30:12 +00:00
|
|
|
{
|
2018-12-18 16:15:15 +00:00
|
|
|
const struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
|
|
|
|
|
|
|
|
if (nf_bridge && nf_bridge->bridged_dnat) {
|
2015-03-09 11:30:12 +00:00
|
|
|
br_nf_pre_routing_finish_bridge_slow(skb);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2015-03-10 09:27:18 +00:00
|
|
|
|
|
|
|
static const struct nf_br_ops br_ops = {
|
|
|
|
.br_dev_xmit_hook = br_nf_dev_xmit,
|
|
|
|
};
|
2015-03-09 11:30:12 +00:00
|
|
|
|
2010-04-15 10:14:51 +00:00
|
|
|
/* For br_nf_post_routing, we need (prio = NF_BR_PRI_LAST), because
|
|
|
|
* br_dev_queue_push_xmit is called afterwards */
|
2017-07-26 09:40:52 +00:00
|
|
|
static const struct nf_hook_ops br_nf_ops[] = {
|
2009-07-03 20:11:57 +00:00
|
|
|
{
|
|
|
|
.hook = br_nf_pre_routing,
|
2012-05-14 03:56:36 +00:00
|
|
|
.pf = NFPROTO_BRIDGE,
|
2009-07-03 20:11:57 +00:00
|
|
|
.hooknum = NF_BR_PRE_ROUTING,
|
|
|
|
.priority = NF_BR_PRI_BRNF,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.hook = br_nf_forward_ip,
|
2012-05-14 03:56:36 +00:00
|
|
|
.pf = NFPROTO_BRIDGE,
|
2009-07-03 20:11:57 +00:00
|
|
|
.hooknum = NF_BR_FORWARD,
|
|
|
|
.priority = NF_BR_PRI_BRNF - 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.hook = br_nf_forward_arp,
|
2012-05-14 03:56:36 +00:00
|
|
|
.pf = NFPROTO_BRIDGE,
|
2009-07-03 20:11:57 +00:00
|
|
|
.hooknum = NF_BR_FORWARD,
|
|
|
|
.priority = NF_BR_PRI_BRNF,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.hook = br_nf_post_routing,
|
2012-05-14 03:56:36 +00:00
|
|
|
.pf = NFPROTO_BRIDGE,
|
2009-07-03 20:11:57 +00:00
|
|
|
.hooknum = NF_BR_POST_ROUTING,
|
|
|
|
.priority = NF_BR_PRI_LAST,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.hook = ip_sabotage_in,
|
2012-05-14 03:56:36 +00:00
|
|
|
.pf = NFPROTO_IPV4,
|
2009-07-03 20:11:57 +00:00
|
|
|
.hooknum = NF_INET_PRE_ROUTING,
|
|
|
|
.priority = NF_IP_PRI_FIRST,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.hook = ip_sabotage_in,
|
2012-05-14 03:56:36 +00:00
|
|
|
.pf = NFPROTO_IPV6,
|
2009-07-03 20:11:57 +00:00
|
|
|
.hooknum = NF_INET_PRE_ROUTING,
|
|
|
|
.priority = NF_IP6_PRI_FIRST,
|
|
|
|
},
|
2005-04-16 22:20:36 +00:00
|
|
|
};
|
|
|
|
|
2016-02-25 09:08:37 +00:00
|
|
|
static int brnf_device_event(struct notifier_block *unused, unsigned long event,
|
|
|
|
void *ptr)
|
|
|
|
{
|
|
|
|
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
|
|
|
struct brnf_net *brnet;
|
|
|
|
struct net *net;
|
|
|
|
int ret;
|
|
|
|
|
2021-10-16 11:21:36 +00:00
|
|
|
if (event != NETDEV_REGISTER || !netif_is_bridge_master(dev))
|
2016-02-25 09:08:37 +00:00
|
|
|
return NOTIFY_DONE;
|
|
|
|
|
|
|
|
ASSERT_RTNL();
|
|
|
|
|
|
|
|
net = dev_net(dev);
|
|
|
|
brnet = net_generic(net, brnf_net_id);
|
|
|
|
if (brnet->enabled)
|
|
|
|
return NOTIFY_OK;
|
|
|
|
|
|
|
|
ret = nf_register_net_hooks(net, br_nf_ops, ARRAY_SIZE(br_nf_ops));
|
|
|
|
if (ret)
|
|
|
|
return NOTIFY_BAD;
|
|
|
|
|
|
|
|
brnet->enabled = true;
|
|
|
|
return NOTIFY_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct notifier_block brnf_notifier __read_mostly = {
|
|
|
|
.notifier_call = brnf_device_event,
|
|
|
|
};
|
|
|
|
|
2016-09-21 15:35:01 +00:00
|
|
|
/* recursively invokes nf_hook_slow (again), skipping already-called
|
|
|
|
* hooks (< NF_BR_PRI_BRNF).
|
|
|
|
*
|
|
|
|
* Called with rcu read lock held.
|
|
|
|
*/
|
|
|
|
int br_nf_hook_thresh(unsigned int hook, struct net *net,
|
|
|
|
struct sock *sk, struct sk_buff *skb,
|
|
|
|
struct net_device *indev,
|
|
|
|
struct net_device *outdev,
|
|
|
|
int (*okfn)(struct net *, struct sock *,
|
|
|
|
struct sk_buff *))
|
|
|
|
{
|
2017-08-23 22:08:32 +00:00
|
|
|
const struct nf_hook_entries *e;
|
2016-09-21 15:35:01 +00:00
|
|
|
struct nf_hook_state state;
|
2017-08-23 22:08:32 +00:00
|
|
|
struct nf_hook_ops **ops;
|
|
|
|
unsigned int i;
|
2016-09-21 15:35:01 +00:00
|
|
|
int ret;
|
|
|
|
|
2017-12-02 23:58:47 +00:00
|
|
|
e = rcu_dereference(net->nf.hooks_bridge[hook]);
|
2017-08-23 22:08:32 +00:00
|
|
|
if (!e)
|
2016-09-21 15:35:01 +00:00
|
|
|
return okfn(net, sk, skb);
|
|
|
|
|
2017-08-23 22:08:32 +00:00
|
|
|
ops = nf_hook_entries_get_hook_ops(e);
|
|
|
|
for (i = 0; i < e->num_hook_entries &&
|
|
|
|
ops[i]->priority <= NF_BR_PRI_BRNF; i++)
|
|
|
|
;
|
|
|
|
|
2016-11-03 09:56:35 +00:00
|
|
|
nf_hook_state_init(&state, hook, NFPROTO_BRIDGE, indev, outdev,
|
2016-11-03 09:56:12 +00:00
|
|
|
sk, net, okfn);
|
2016-09-21 15:35:01 +00:00
|
|
|
|
2017-08-23 22:08:32 +00:00
|
|
|
ret = nf_hook_slow(skb, &state, e, i);
|
2016-09-21 15:35:01 +00:00
|
|
|
if (ret == 1)
|
|
|
|
ret = okfn(net, sk, skb);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
#ifdef CONFIG_SYSCTL
|
|
|
|
static
|
2013-06-12 06:04:25 +00:00
|
|
|
int brnf_sysctl_call_tables(struct ctl_table *ctl, int write,
|
2020-04-24 06:43:38 +00:00
|
|
|
void *buffer, size_t *lenp, loff_t *ppos)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2009-09-23 22:57:19 +00:00
|
|
|
ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
if (write && *(int *)(ctl->data))
|
|
|
|
*(int *)(ctl->data) = 1;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-06-12 06:04:25 +00:00
|
|
|
static struct ctl_table brnf_table[] = {
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
.procname = "bridge-nf-call-arptables",
|
|
|
|
.maxlen = sizeof(int),
|
|
|
|
.mode = 0644,
|
2008-11-04 02:21:05 +00:00
|
|
|
.proc_handler = brnf_sysctl_call_tables,
|
2005-04-16 22:20:36 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.procname = "bridge-nf-call-iptables",
|
|
|
|
.maxlen = sizeof(int),
|
|
|
|
.mode = 0644,
|
2008-11-04 02:21:05 +00:00
|
|
|
.proc_handler = brnf_sysctl_call_tables,
|
2005-04-16 22:20:36 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.procname = "bridge-nf-call-ip6tables",
|
|
|
|
.maxlen = sizeof(int),
|
|
|
|
.mode = 0644,
|
2008-11-04 02:21:05 +00:00
|
|
|
.proc_handler = brnf_sysctl_call_tables,
|
2005-04-16 22:20:36 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.procname = "bridge-nf-filter-vlan-tagged",
|
|
|
|
.maxlen = sizeof(int),
|
|
|
|
.mode = 0644,
|
2008-11-04 02:21:05 +00:00
|
|
|
.proc_handler = brnf_sysctl_call_tables,
|
2007-04-13 05:14:23 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.procname = "bridge-nf-filter-pppoe-tagged",
|
|
|
|
.maxlen = sizeof(int),
|
|
|
|
.mode = 0644,
|
2008-11-04 02:21:05 +00:00
|
|
|
.proc_handler = brnf_sysctl_call_tables,
|
2005-04-16 22:20:36 +00:00
|
|
|
},
|
2012-05-08 17:36:44 +00:00
|
|
|
{
|
|
|
|
.procname = "bridge-nf-pass-vlan-input-dev",
|
|
|
|
.maxlen = sizeof(int),
|
|
|
|
.mode = 0644,
|
|
|
|
.proc_handler = brnf_sysctl_call_tables,
|
|
|
|
},
|
2009-11-05 21:32:03 +00:00
|
|
|
{ }
|
2005-04-16 22:20:36 +00:00
|
|
|
};
|
2019-06-10 21:26:05 +00:00
|
|
|
|
|
|
|
static inline void br_netfilter_sysctl_default(struct brnf_net *brnf)
|
|
|
|
{
|
|
|
|
brnf->call_iptables = 1;
|
|
|
|
brnf->call_ip6tables = 1;
|
|
|
|
brnf->call_arptables = 1;
|
|
|
|
brnf->filter_vlan_tagged = 0;
|
|
|
|
brnf->filter_pppoe_tagged = 0;
|
|
|
|
brnf->pass_vlan_indev = 0;
|
|
|
|
}
|
|
|
|
|
2019-06-10 21:26:06 +00:00
|
|
|
static int br_netfilter_sysctl_init_net(struct net *net)
|
|
|
|
{
|
|
|
|
struct ctl_table *table = brnf_table;
|
|
|
|
struct brnf_net *brnet;
|
|
|
|
|
|
|
|
if (!net_eq(net, &init_net)) {
|
|
|
|
table = kmemdup(table, sizeof(brnf_table), GFP_KERNEL);
|
|
|
|
if (!table)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
brnet = net_generic(net, brnf_net_id);
|
|
|
|
table[0].data = &brnet->call_arptables;
|
|
|
|
table[1].data = &brnet->call_iptables;
|
|
|
|
table[2].data = &brnet->call_ip6tables;
|
|
|
|
table[3].data = &brnet->filter_vlan_tagged;
|
|
|
|
table[4].data = &brnet->filter_pppoe_tagged;
|
|
|
|
table[5].data = &brnet->pass_vlan_indev;
|
|
|
|
|
|
|
|
br_netfilter_sysctl_default(brnet);
|
|
|
|
|
|
|
|
brnet->ctl_hdr = register_net_sysctl(net, "net/bridge", table);
|
|
|
|
if (!brnet->ctl_hdr) {
|
|
|
|
if (!net_eq(net, &init_net))
|
|
|
|
kfree(table);
|
|
|
|
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void br_netfilter_sysctl_exit_net(struct net *net,
|
|
|
|
struct brnf_net *brnet)
|
|
|
|
{
|
2019-06-19 17:05:47 +00:00
|
|
|
struct ctl_table *table = brnet->ctl_hdr->ctl_table_arg;
|
|
|
|
|
2019-06-10 21:26:06 +00:00
|
|
|
unregister_net_sysctl_table(brnet->ctl_hdr);
|
|
|
|
if (!net_eq(net, &init_net))
|
2019-06-19 17:05:47 +00:00
|
|
|
kfree(table);
|
2019-06-10 21:26:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int __net_init brnf_init_net(struct net *net)
|
|
|
|
{
|
|
|
|
return br_netfilter_sysctl_init_net(net);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void __net_exit brnf_exit_net(struct net *net)
|
|
|
|
{
|
|
|
|
struct brnf_net *brnet;
|
|
|
|
|
|
|
|
brnet = net_generic(net, brnf_net_id);
|
|
|
|
if (brnet->enabled) {
|
|
|
|
nf_unregister_net_hooks(net, br_nf_ops, ARRAY_SIZE(br_nf_ops));
|
|
|
|
brnet->enabled = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_SYSCTL
|
|
|
|
br_netfilter_sysctl_exit_net(net, brnet);
|
2005-04-16 22:20:36 +00:00
|
|
|
#endif
|
2019-06-10 21:26:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct pernet_operations brnf_net_ops __read_mostly = {
|
|
|
|
#ifdef CONFIG_SYSCTL
|
|
|
|
.init = brnf_init_net,
|
|
|
|
#endif
|
|
|
|
.exit = brnf_exit_net,
|
|
|
|
.id = &brnf_net_id,
|
|
|
|
.size = sizeof(struct brnf_net),
|
|
|
|
};
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2014-09-18 09:29:03 +00:00
|
|
|
static int __init br_netfilter_init(void)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2007-02-07 23:07:22 +00:00
|
|
|
int ret;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2016-02-25 09:08:37 +00:00
|
|
|
ret = register_pernet_subsys(&brnf_net_ops);
|
2007-02-07 23:07:22 +00:00
|
|
|
if (ret < 0)
|
2005-04-16 22:20:36 +00:00
|
|
|
return ret;
|
2010-10-08 06:37:34 +00:00
|
|
|
|
2016-02-25 09:08:37 +00:00
|
|
|
ret = register_netdevice_notifier(&brnf_notifier);
|
|
|
|
if (ret < 0) {
|
|
|
|
unregister_pernet_subsys(&brnf_net_ops);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-03-10 09:27:18 +00:00
|
|
|
RCU_INIT_POINTER(nf_br_ops, &br_ops);
|
2005-04-16 22:20:36 +00:00
|
|
|
printk(KERN_NOTICE "Bridge firewalling registered\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-09-18 09:29:03 +00:00
|
|
|
static void __exit br_netfilter_fini(void)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2015-03-10 09:27:18 +00:00
|
|
|
RCU_INIT_POINTER(nf_br_ops, NULL);
|
2016-02-25 09:08:37 +00:00
|
|
|
unregister_netdevice_notifier(&brnf_notifier);
|
|
|
|
unregister_pernet_subsys(&brnf_net_ops);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2014-09-18 09:29:03 +00:00
|
|
|
|
|
|
|
module_init(br_netfilter_init);
|
|
|
|
module_exit(br_netfilter_fini);
|
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
MODULE_AUTHOR("Lennert Buytenhek <buytenh@gnu.org>");
|
|
|
|
MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
|
|
|
|
MODULE_DESCRIPTION("Linux ethernet netfilter firewall bridge");
|