aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorChristian Brauner <christian@brauner.io>2019-06-10 17:26:06 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2019-06-17 10:36:31 -0400
commit22567590b2e634247931b3d2351384ba45720ebe (patch)
treeb31d7091b5fe747151ee8c8ac205abfd11a8c25e /net
parentff6d090d0db41425aef0cfe5dc58bb3cc12514a2 (diff)
netfilter: bridge: namespace bridge netfilter sysctls
Currently, the /proc/sys/net/bridge folder is only created in the initial network namespace. This patch ensures that the /proc/sys/net/bridge folder is available in each network namespace if the module is loaded and disappears from all network namespaces when the module is unloaded. In doing so the patch makes the sysctls: 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 apply per network namespace. This unblocks some use-cases where users would like to e.g. not do bridge filtering for bridges in a specific network namespace while doing so for bridges located in another network namespace. The netfilter rules are afaict already per network namespace so it should be safe for users to specify whether bridge devices inside a network namespace are supposed to go through iptables et al. or not. Also, this can already be done per-bridge by setting an option for each individual bridge via Netlink. It should also be possible to do this for all bridges in a network namespace via sysctls. Cc: Tyler Hicks <tyhicks@canonical.com> Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_netfilter_hooks.c117
1 files changed, 72 insertions, 45 deletions
diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c
index 3c67754d8075..995a498534e9 100644
--- a/net/bridge/br_netfilter_hooks.c
+++ b/net/bridge/br_netfilter_hooks.c
@@ -49,13 +49,13 @@
49 49
50static unsigned int brnf_net_id __read_mostly; 50static unsigned int brnf_net_id __read_mostly;
51 51
52#ifdef CONFIG_SYSCTL
53static struct ctl_table_header *brnf_sysctl_header;
54#endif
55
56struct brnf_net { 52struct brnf_net {
57 bool enabled; 53 bool enabled;
58 54
55#ifdef CONFIG_SYSCTL
56 struct ctl_table_header *ctl_hdr;
57#endif
58
59 /* default value is 1 */ 59 /* default value is 1 */
60 int call_iptables; 60 int call_iptables;
61 int call_ip6tables; 61 int call_ip6tables;
@@ -980,23 +980,6 @@ static int brnf_device_event(struct notifier_block *unused, unsigned long event,
980 return NOTIFY_OK; 980 return NOTIFY_OK;
981} 981}
982 982
983static void __net_exit brnf_exit_net(struct net *net)
984{
985 struct brnf_net *brnet = net_generic(net, brnf_net_id);
986
987 if (!brnet->enabled)
988 return;
989
990 nf_unregister_net_hooks(net, br_nf_ops, ARRAY_SIZE(br_nf_ops));
991 brnet->enabled = false;
992}
993
994static struct pernet_operations brnf_net_ops __read_mostly = {
995 .exit = brnf_exit_net,
996 .id = &brnf_net_id,
997 .size = sizeof(struct brnf_net),
998};
999
1000static struct notifier_block brnf_notifier __read_mostly = { 983static struct notifier_block brnf_notifier __read_mostly = {
1001 .notifier_call = brnf_device_event, 984 .notifier_call = brnf_device_event,
1002}; 985};
@@ -1102,12 +1085,79 @@ static inline void br_netfilter_sysctl_default(struct brnf_net *brnf)
1102 brnf->pass_vlan_indev = 0; 1085 brnf->pass_vlan_indev = 0;
1103} 1086}
1104 1087
1088static int br_netfilter_sysctl_init_net(struct net *net)
1089{
1090 struct ctl_table *table = brnf_table;
1091 struct brnf_net *brnet;
1092
1093 if (!net_eq(net, &init_net)) {
1094 table = kmemdup(table, sizeof(brnf_table), GFP_KERNEL);
1095 if (!table)
1096 return -ENOMEM;
1097 }
1098
1099 brnet = net_generic(net, brnf_net_id);
1100 table[0].data = &brnet->call_arptables;
1101 table[1].data = &brnet->call_iptables;
1102 table[2].data = &brnet->call_ip6tables;
1103 table[3].data = &brnet->filter_vlan_tagged;
1104 table[4].data = &brnet->filter_pppoe_tagged;
1105 table[5].data = &brnet->pass_vlan_indev;
1106
1107 br_netfilter_sysctl_default(brnet);
1108
1109 brnet->ctl_hdr = register_net_sysctl(net, "net/bridge", table);
1110 if (!brnet->ctl_hdr) {
1111 if (!net_eq(net, &init_net))
1112 kfree(table);
1113
1114 return -ENOMEM;
1115 }
1116
1117 return 0;
1118}
1119
1120static void br_netfilter_sysctl_exit_net(struct net *net,
1121 struct brnf_net *brnet)
1122{
1123 unregister_net_sysctl_table(brnet->ctl_hdr);
1124 if (!net_eq(net, &init_net))
1125 kfree(brnet->ctl_hdr->ctl_table_arg);
1126}
1127
1128static int __net_init brnf_init_net(struct net *net)
1129{
1130 return br_netfilter_sysctl_init_net(net);
1131}
1132#endif
1133
1134static void __net_exit brnf_exit_net(struct net *net)
1135{
1136 struct brnf_net *brnet;
1137
1138 brnet = net_generic(net, brnf_net_id);
1139 if (brnet->enabled) {
1140 nf_unregister_net_hooks(net, br_nf_ops, ARRAY_SIZE(br_nf_ops));
1141 brnet->enabled = false;
1142 }
1143
1144#ifdef CONFIG_SYSCTL
1145 br_netfilter_sysctl_exit_net(net, brnet);
1105#endif 1146#endif
1147}
1148
1149static struct pernet_operations brnf_net_ops __read_mostly = {
1150#ifdef CONFIG_SYSCTL
1151 .init = brnf_init_net,
1152#endif
1153 .exit = brnf_exit_net,
1154 .id = &brnf_net_id,
1155 .size = sizeof(struct brnf_net),
1156};
1106 1157
1107static int __init br_netfilter_init(void) 1158static int __init br_netfilter_init(void)
1108{ 1159{
1109 int ret; 1160 int ret;
1110 struct brnf_net *brnet;
1111 1161
1112 ret = register_pernet_subsys(&brnf_net_ops); 1162 ret = register_pernet_subsys(&brnf_net_ops);
1113 if (ret < 0) 1163 if (ret < 0)
@@ -1119,26 +1169,6 @@ static int __init br_netfilter_init(void)
1119 return ret; 1169 return ret;
1120 } 1170 }
1121 1171
1122#ifdef CONFIG_SYSCTL
1123 brnet = net_generic(&init_net, brnf_net_id);
1124 brnf_table[0].data = &brnet->call_arptables;
1125 brnf_table[1].data = &brnet->call_iptables;
1126 brnf_table[2].data = &brnet->call_ip6tables;
1127 brnf_table[3].data = &brnet->filter_vlan_tagged;
1128 brnf_table[4].data = &brnet->filter_pppoe_tagged;
1129 brnf_table[5].data = &brnet->pass_vlan_indev;
1130
1131 br_netfilter_sysctl_default(brnet);
1132
1133 brnf_sysctl_header = register_net_sysctl(&init_net, "net/bridge", brnf_table);
1134 if (brnf_sysctl_header == NULL) {
1135 printk(KERN_WARNING
1136 "br_netfilter: can't register to sysctl.\n");
1137 unregister_netdevice_notifier(&brnf_notifier);
1138 unregister_pernet_subsys(&brnf_net_ops);
1139 return -ENOMEM;
1140 }
1141#endif
1142 RCU_INIT_POINTER(nf_br_ops, &br_ops); 1172 RCU_INIT_POINTER(nf_br_ops, &br_ops);
1143 printk(KERN_NOTICE "Bridge firewalling registered\n"); 1173 printk(KERN_NOTICE "Bridge firewalling registered\n");
1144 return 0; 1174 return 0;
@@ -1149,9 +1179,6 @@ static void __exit br_netfilter_fini(void)
1149 RCU_INIT_POINTER(nf_br_ops, NULL); 1179 RCU_INIT_POINTER(nf_br_ops, NULL);
1150 unregister_netdevice_notifier(&brnf_notifier); 1180 unregister_netdevice_notifier(&brnf_notifier);
1151 unregister_pernet_subsys(&brnf_net_ops); 1181 unregister_pernet_subsys(&brnf_net_ops);
1152#ifdef CONFIG_SYSCTL
1153 unregister_net_sysctl_table(brnf_sysctl_header);
1154#endif
1155} 1182}
1156 1183
1157module_init(br_netfilter_init); 1184module_init(br_netfilter_init);