ILD

bridge netfilter
作者:Yuan Jianpeng 邮箱:yuanjp89@163.com
发布时间:2021-12-20 站点:Inside Linux Development

基于内核4.4.60版本分析。


配置和Make

net/Kconfig

BRIDGE_NETFILTER

依赖于NET [=y] && BRIDGE [=y] && NETFILTER [=n] && INET [=y] && NETFILTER_ADVANCED


net/bridge/netfilter/Kconfig


NF_TABLES_BRIDGE

    依赖于BRIDGE && NETFILTER && NF_TABLES


BRIDGE_NF_EBTABLES

    依赖于NET [=y] && BRIDGE [=y] && NETFILTER [=y] && NETFILTER_XTABLES [=m]

BRIDGE_EBT_802_3

BRIDGE_EBT_AMONG

BRIDGE_EBT_ARP

BRIDGE_EBT_ARPREPLY

BRIDGE_EBT_BROUTE

BRIDGE_EBT_DNAT

BRIDGE_EBT_IP

BRIDGE_EBT_IP6

BRIDGE_EBT_LIMIT

BRIDGE_EBT_LOG

BRIDGE_EBT_MARK

BRIDGE_EBT_MARK_T

BRIDGE_EBT_NFLOG

BRIDGE_EBT_PKTTYPE

BRIDGE_EBT_REDIRECT

BRIDGE_EBT_SNAT

BRIDGE_EBT_STP

BRIDGE_EBT_T_FILTER

BRIDGE_EBT_T_NAT

BRIDGE_EBT_VLAN


net/bridge/Makefile

bridge-$(subst m,y,$(CONFIG_BRIDGE_NETFILTER)) += br_nf_core.o


br_netfilter-y := br_netfilter_hooks.o

br_netfilter-$(subst m,y,$(CONFIG_IPV6)) += br_netfilter_ipv6.o

obj-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.o


obj-$(CONFIG_NETFILTER) += netfilter/


net/bridge/netfilter/Makefile

每个配置项对应一个模块


obj-$(CONFIG_NF_TABLES_BRIDGE) += nf_tables_bridge.o

obj-$(CONFIG_NFT_BRIDGE_META)  += nft_meta_bridge.o

obj-$(CONFIG_NFT_BRIDGE_REJECT)  += nft_reject_bridge.o

...


代码分析

有3个主要的配置

    CONFIG_BRIDGE_NETFILTER

    CONFIG_NF_TABLES_BRIDGE

    CONFIG_BRIDGE_NF_EBTABLES

下面将一一分析。


netfilter的bridge family,定义在<linux/netfilter.h>,NFPROTO_BRIDGE。桥里面共有5个hook,和ipv4一样的5个hook对应。这5个hook定义在<linux/netfilter_bridge.h>,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* Bridge Hooks */
/* After promisc drops, checksum checks. */
#define NF_BR_PRE_ROUTING   0
/* If the packet is destined for this box. */
#define NF_BR_LOCAL_IN      1
/* If the packet is destined for another interface. */
#define NF_BR_FORWARD       2
/* Packets coming from a local process. */
#define NF_BR_LOCAL_OUT     3
/* Packets about to hit the wire. */
#define NF_BR_POST_ROUTING  4
/* Not really a hook, but used for the ebtables broute table */
#define NF_BR_BROUTING      5
#define NF_BR_NUMHOOKS      6


再来看这5个hook是在桥的哪些部分执行的:

NF_BR_PRE_ROUTINGnet/bridge/br_input.cbr_handle_frame()
NF_BR_LOCAL_INnet/bridge/br_input.c

br_pass_frame_up()

br_handle_frame() (link local)

NF_BR_FORWARDnet/bridge/br_forward.c__br_forward()
NF_BR_LOCAL_OUT

net/bridge/br_forward.c

net/bridge/br_multicast.c

__br_deliver()

__br_multicast_send_query()

NF_BR_POST_ROUTINGnet/bridge/br_forward.cbr_forward_finish()


注意:这5个hook的执行是hard code在桥处理代码中的。只要开启了CONFIG_NETFILTER,那么就可以注册桥的hook,和CONFIG_BRIDGE_NETFILTER无关。那么CONFIG_BRIDGE_NETFILTER这宏是做啥用途的呢,接下来分析。


CONFIG_BRIDGE_NETFILTER

这个配置项,是可以让iptables,ip6tables,arptables能勾到桥中的数据包。源代码:net/bridge/br_netfilter_hooks.c。它在NFPROTO_BRIDGE的5个hook点都注册钩子,比如

static struct nf_hook_ops br_nf_ops[] __read_mostly = {

    {

        .hook = br_nf_pre_routing,

        .pf = NFPROTO_BRIDGE,

        .hooknum = NF_BR_PRE_ROUTING,

        .priority = NF_BR_PRI_BRNF,

    },


在br_nf_pre_routing() hook函数中,判断是IPV4包,就执行

    NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, state->net, state->sk, skb,

        skb->dev, NULL,

        br_nf_pre_routing_finish);


sysctl里面,还有几个配置,配置是否启用对应的hook

$ ls -1 /proc/sys/net/bridge/

bridge-nf-call-arptables

bridge-nf-call-ip6tables

bridge-nf-call-iptables

bridge-nf-filter-pppoe-tagged

bridge-nf-filter-vlan-tagged

bridge-nf-pass-vlan-input-dev


CONFIG_NF_TABLES_BRIDGE

对应编译源码:net/bridge/netfilter/nf_tables_bridge.c

它是新的nftables框架中,支持NFPROTO_BRIDGE。


CONFIG_BRIDGE_NF_EBTABLES

ebtables的支持内核代码。


OpenWrt 桥转发性能优化

target/linux/ar71xx/patches-3.3/670-openwrt-bridge_optimize_netfilter_hooks.patch


将NF_HOOK,修改为BR_HOOK,在BR_HOOK里面判断是否走NF_HOOK。增加了一个

/proc/sys/net/bridge/bridge-nf-call-custom选项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
bool br_netfilter_run_hooks(void)
{
    return brnf_call_iptables | brnf_call_ip6tables | brnf_call_arptables |
        brnf_call_ebtables | brnf_call_custom;
}
 
static inline int
BR_HOOK(uint8_t pf, unsigned int hook, struct net *net, struct sock *sk,
    struct sk_buff *skb, struct net_device *in, struct net_device *out,
    int (*okfn)(struct net *, struct sock *, struct sk_buff *))
{
    if (!br_netfilter_run_hooks())
        return okfn(net, sk, skb);
    return NF_HOOK(pf, hook, net, sk, skb, in, out, okfn);
}


用宏CONFIG_BRIDGE_NETFILTER控制,因此需要开启CONFIG_BRIDGE_NETFILTER才能执行5个写死的hook点。这和内核产生了差异,且更改了CONFIG_BRIDGE_NETFILTER的本意。


参考:

https://unix.stackexchange.com/questions/499756/how-does-iptable-work-with-linux-bridge



Copyright © insidelinuxdev.net 2017-2021. Some Rights Reserved.