1 #include <linux/init.h> 2 #include <linux/kernel.h> 3 #include <linux/netdevice.h> 4 #include <net/net_namespace.h> 5 #include <net/netfilter/nf_tables.h> 6 #include <linux/netfilter_ipv4.h> 7 #include <linux/netfilter_ipv6.h> 8 #include <linux/netfilter_bridge.h> 9 #include <linux/netfilter_arp.h> 10 #include <net/netfilter/nf_tables_ipv4.h> 11 #include <net/netfilter/nf_tables_ipv6.h> 12 13 #ifdef CONFIG_NF_TABLES_IPV4 14 static unsigned int nft_do_chain_ipv4(void *priv, 15 struct sk_buff *skb, 16 const struct nf_hook_state *state) 17 { 18 struct nft_pktinfo pkt; 19 20 nft_set_pktinfo(&pkt, skb, state); 21 nft_set_pktinfo_ipv4(&pkt, skb); 22 23 return nft_do_chain(&pkt, priv); 24 } 25 26 static const struct nft_chain_type nft_chain_filter_ipv4 = { 27 .name = "filter", 28 .type = NFT_CHAIN_T_DEFAULT, 29 .family = NFPROTO_IPV4, 30 .hook_mask = (1 << NF_INET_LOCAL_IN) | 31 (1 << NF_INET_LOCAL_OUT) | 32 (1 << NF_INET_FORWARD) | 33 (1 << NF_INET_PRE_ROUTING) | 34 (1 << NF_INET_POST_ROUTING), 35 .hooks = { 36 [NF_INET_LOCAL_IN] = nft_do_chain_ipv4, 37 [NF_INET_LOCAL_OUT] = nft_do_chain_ipv4, 38 [NF_INET_FORWARD] = nft_do_chain_ipv4, 39 [NF_INET_PRE_ROUTING] = nft_do_chain_ipv4, 40 [NF_INET_POST_ROUTING] = nft_do_chain_ipv4, 41 }, 42 }; 43 44 static void nft_chain_filter_ipv4_init(void) 45 { 46 nft_register_chain_type(&nft_chain_filter_ipv4); 47 } 48 static void nft_chain_filter_ipv4_fini(void) 49 { 50 nft_unregister_chain_type(&nft_chain_filter_ipv4); 51 } 52 53 #else 54 static inline void nft_chain_filter_ipv4_init(void) {} 55 static inline void nft_chain_filter_ipv4_fini(void) {} 56 #endif /* CONFIG_NF_TABLES_IPV4 */ 57 58 #ifdef CONFIG_NF_TABLES_ARP 59 static unsigned int nft_do_chain_arp(void *priv, struct sk_buff *skb, 60 const struct nf_hook_state *state) 61 { 62 struct nft_pktinfo pkt; 63 64 nft_set_pktinfo(&pkt, skb, state); 65 nft_set_pktinfo_unspec(&pkt, skb); 66 67 return nft_do_chain(&pkt, priv); 68 } 69 70 static const struct nft_chain_type nft_chain_filter_arp = { 71 .name = "filter", 72 .type = NFT_CHAIN_T_DEFAULT, 73 .family = NFPROTO_ARP, 74 .owner = THIS_MODULE, 75 .hook_mask = (1 << NF_ARP_IN) | 76 (1 << NF_ARP_OUT), 77 .hooks = { 78 [NF_ARP_IN] = nft_do_chain_arp, 79 [NF_ARP_OUT] = nft_do_chain_arp, 80 }, 81 }; 82 83 static void nft_chain_filter_arp_init(void) 84 { 85 nft_register_chain_type(&nft_chain_filter_arp); 86 } 87 88 static void nft_chain_filter_arp_fini(void) 89 { 90 nft_unregister_chain_type(&nft_chain_filter_arp); 91 } 92 #else 93 static inline void nft_chain_filter_arp_init(void) {} 94 static inline void nft_chain_filter_arp_fini(void) {} 95 #endif /* CONFIG_NF_TABLES_ARP */ 96 97 #ifdef CONFIG_NF_TABLES_IPV6 98 static unsigned int nft_do_chain_ipv6(void *priv, 99 struct sk_buff *skb, 100 const struct nf_hook_state *state) 101 { 102 struct nft_pktinfo pkt; 103 104 nft_set_pktinfo(&pkt, skb, state); 105 nft_set_pktinfo_ipv6(&pkt, skb); 106 107 return nft_do_chain(&pkt, priv); 108 } 109 110 static const struct nft_chain_type nft_chain_filter_ipv6 = { 111 .name = "filter", 112 .type = NFT_CHAIN_T_DEFAULT, 113 .family = NFPROTO_IPV6, 114 .hook_mask = (1 << NF_INET_LOCAL_IN) | 115 (1 << NF_INET_LOCAL_OUT) | 116 (1 << NF_INET_FORWARD) | 117 (1 << NF_INET_PRE_ROUTING) | 118 (1 << NF_INET_POST_ROUTING), 119 .hooks = { 120 [NF_INET_LOCAL_IN] = nft_do_chain_ipv6, 121 [NF_INET_LOCAL_OUT] = nft_do_chain_ipv6, 122 [NF_INET_FORWARD] = nft_do_chain_ipv6, 123 [NF_INET_PRE_ROUTING] = nft_do_chain_ipv6, 124 [NF_INET_POST_ROUTING] = nft_do_chain_ipv6, 125 }, 126 }; 127 128 static void nft_chain_filter_ipv6_init(void) 129 { 130 nft_register_chain_type(&nft_chain_filter_ipv6); 131 } 132 133 static void nft_chain_filter_ipv6_fini(void) 134 { 135 nft_unregister_chain_type(&nft_chain_filter_ipv6); 136 } 137 #else 138 static inline void nft_chain_filter_ipv6_init(void) {} 139 static inline void nft_chain_filter_ipv6_fini(void) {} 140 #endif /* CONFIG_NF_TABLES_IPV6 */ 141 142 #ifdef CONFIG_NF_TABLES_INET 143 static unsigned int nft_do_chain_inet(void *priv, struct sk_buff *skb, 144 const struct nf_hook_state *state) 145 { 146 struct nft_pktinfo pkt; 147 148 nft_set_pktinfo(&pkt, skb, state); 149 150 switch (state->pf) { 151 case NFPROTO_IPV4: 152 nft_set_pktinfo_ipv4(&pkt, skb); 153 break; 154 case NFPROTO_IPV6: 155 nft_set_pktinfo_ipv6(&pkt, skb); 156 break; 157 default: 158 break; 159 } 160 161 return nft_do_chain(&pkt, priv); 162 } 163 164 static const struct nft_chain_type nft_chain_filter_inet = { 165 .name = "filter", 166 .type = NFT_CHAIN_T_DEFAULT, 167 .family = NFPROTO_INET, 168 .hook_mask = (1 << NF_INET_LOCAL_IN) | 169 (1 << NF_INET_LOCAL_OUT) | 170 (1 << NF_INET_FORWARD) | 171 (1 << NF_INET_PRE_ROUTING) | 172 (1 << NF_INET_POST_ROUTING), 173 .hooks = { 174 [NF_INET_LOCAL_IN] = nft_do_chain_inet, 175 [NF_INET_LOCAL_OUT] = nft_do_chain_inet, 176 [NF_INET_FORWARD] = nft_do_chain_inet, 177 [NF_INET_PRE_ROUTING] = nft_do_chain_inet, 178 [NF_INET_POST_ROUTING] = nft_do_chain_inet, 179 }, 180 }; 181 182 static void nft_chain_filter_inet_init(void) 183 { 184 nft_register_chain_type(&nft_chain_filter_inet); 185 } 186 187 static void nft_chain_filter_inet_fini(void) 188 { 189 nft_unregister_chain_type(&nft_chain_filter_inet); 190 } 191 #else 192 static inline void nft_chain_filter_inet_init(void) {} 193 static inline void nft_chain_filter_inet_fini(void) {} 194 #endif /* CONFIG_NF_TABLES_IPV6 */ 195 196 #if IS_ENABLED(CONFIG_NF_TABLES_BRIDGE) 197 static unsigned int 198 nft_do_chain_bridge(void *priv, 199 struct sk_buff *skb, 200 const struct nf_hook_state *state) 201 { 202 struct nft_pktinfo pkt; 203 204 nft_set_pktinfo(&pkt, skb, state); 205 206 switch (eth_hdr(skb)->h_proto) { 207 case htons(ETH_P_IP): 208 nft_set_pktinfo_ipv4_validate(&pkt, skb); 209 break; 210 case htons(ETH_P_IPV6): 211 nft_set_pktinfo_ipv6_validate(&pkt, skb); 212 break; 213 default: 214 nft_set_pktinfo_unspec(&pkt, skb); 215 break; 216 } 217 218 return nft_do_chain(&pkt, priv); 219 } 220 221 static const struct nft_chain_type nft_chain_filter_bridge = { 222 .name = "filter", 223 .type = NFT_CHAIN_T_DEFAULT, 224 .family = NFPROTO_BRIDGE, 225 .hook_mask = (1 << NF_BR_PRE_ROUTING) | 226 (1 << NF_BR_LOCAL_IN) | 227 (1 << NF_BR_FORWARD) | 228 (1 << NF_BR_LOCAL_OUT) | 229 (1 << NF_BR_POST_ROUTING), 230 .hooks = { 231 [NF_BR_PRE_ROUTING] = nft_do_chain_bridge, 232 [NF_BR_LOCAL_IN] = nft_do_chain_bridge, 233 [NF_BR_FORWARD] = nft_do_chain_bridge, 234 [NF_BR_LOCAL_OUT] = nft_do_chain_bridge, 235 [NF_BR_POST_ROUTING] = nft_do_chain_bridge, 236 }, 237 }; 238 239 static void nft_chain_filter_bridge_init(void) 240 { 241 nft_register_chain_type(&nft_chain_filter_bridge); 242 } 243 244 static void nft_chain_filter_bridge_fini(void) 245 { 246 nft_unregister_chain_type(&nft_chain_filter_bridge); 247 } 248 #else 249 static inline void nft_chain_filter_bridge_init(void) {} 250 static inline void nft_chain_filter_bridge_fini(void) {} 251 #endif /* CONFIG_NF_TABLES_BRIDGE */ 252 253 #ifdef CONFIG_NF_TABLES_NETDEV 254 static unsigned int nft_do_chain_netdev(void *priv, struct sk_buff *skb, 255 const struct nf_hook_state *state) 256 { 257 struct nft_pktinfo pkt; 258 259 nft_set_pktinfo(&pkt, skb, state); 260 261 switch (skb->protocol) { 262 case htons(ETH_P_IP): 263 nft_set_pktinfo_ipv4_validate(&pkt, skb); 264 break; 265 case htons(ETH_P_IPV6): 266 nft_set_pktinfo_ipv6_validate(&pkt, skb); 267 break; 268 default: 269 nft_set_pktinfo_unspec(&pkt, skb); 270 break; 271 } 272 273 return nft_do_chain(&pkt, priv); 274 } 275 276 static const struct nft_chain_type nft_chain_filter_netdev = { 277 .name = "filter", 278 .type = NFT_CHAIN_T_DEFAULT, 279 .family = NFPROTO_NETDEV, 280 .hook_mask = (1 << NF_NETDEV_INGRESS), 281 .hooks = { 282 [NF_NETDEV_INGRESS] = nft_do_chain_netdev, 283 }, 284 }; 285 286 static void nft_netdev_event(unsigned long event, struct net_device *dev, 287 struct nft_ctx *ctx) 288 { 289 struct nft_base_chain *basechain = nft_base_chain(ctx->chain); 290 291 switch (event) { 292 case NETDEV_UNREGISTER: 293 if (strcmp(basechain->dev_name, dev->name) != 0) 294 return; 295 296 /* UNREGISTER events are also happpening on netns exit. 297 * 298 * Altough nf_tables core releases all tables/chains, only 299 * this event handler provides guarantee that 300 * basechain.ops->dev is still accessible, so we cannot 301 * skip exiting net namespaces. 302 */ 303 __nft_release_basechain(ctx); 304 break; 305 case NETDEV_CHANGENAME: 306 if (dev->ifindex != basechain->ops.dev->ifindex) 307 return; 308 309 strncpy(basechain->dev_name, dev->name, IFNAMSIZ); 310 break; 311 } 312 } 313 314 static int nf_tables_netdev_event(struct notifier_block *this, 315 unsigned long event, void *ptr) 316 { 317 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 318 struct nft_table *table; 319 struct nft_chain *chain, *nr; 320 struct nft_ctx ctx = { 321 .net = dev_net(dev), 322 }; 323 324 if (event != NETDEV_UNREGISTER && 325 event != NETDEV_CHANGENAME) 326 return NOTIFY_DONE; 327 328 mutex_lock(&ctx.net->nft.commit_mutex); 329 list_for_each_entry(table, &ctx.net->nft.tables, list) { 330 if (table->family != NFPROTO_NETDEV) 331 continue; 332 333 ctx.family = table->family; 334 ctx.table = table; 335 list_for_each_entry_safe(chain, nr, &table->chains, list) { 336 if (!nft_is_base_chain(chain)) 337 continue; 338 339 ctx.chain = chain; 340 nft_netdev_event(event, dev, &ctx); 341 } 342 } 343 mutex_unlock(&ctx.net->nft.commit_mutex); 344 345 return NOTIFY_DONE; 346 } 347 348 static struct notifier_block nf_tables_netdev_notifier = { 349 .notifier_call = nf_tables_netdev_event, 350 }; 351 352 static int nft_chain_filter_netdev_init(void) 353 { 354 int err; 355 356 nft_register_chain_type(&nft_chain_filter_netdev); 357 358 err = register_netdevice_notifier(&nf_tables_netdev_notifier); 359 if (err) 360 goto err_register_netdevice_notifier; 361 362 return 0; 363 364 err_register_netdevice_notifier: 365 nft_unregister_chain_type(&nft_chain_filter_netdev); 366 367 return err; 368 } 369 370 static void nft_chain_filter_netdev_fini(void) 371 { 372 nft_unregister_chain_type(&nft_chain_filter_netdev); 373 unregister_netdevice_notifier(&nf_tables_netdev_notifier); 374 } 375 #else 376 static inline int nft_chain_filter_netdev_init(void) { return 0; } 377 static inline void nft_chain_filter_netdev_fini(void) {} 378 #endif /* CONFIG_NF_TABLES_NETDEV */ 379 380 int __init nft_chain_filter_init(void) 381 { 382 int err; 383 384 err = nft_chain_filter_netdev_init(); 385 if (err < 0) 386 return err; 387 388 nft_chain_filter_ipv4_init(); 389 nft_chain_filter_ipv6_init(); 390 nft_chain_filter_arp_init(); 391 nft_chain_filter_inet_init(); 392 nft_chain_filter_bridge_init(); 393 394 return 0; 395 } 396 397 void nft_chain_filter_fini(void) 398 { 399 nft_chain_filter_bridge_fini(); 400 nft_chain_filter_inet_fini(); 401 nft_chain_filter_arp_fini(); 402 nft_chain_filter_ipv6_fini(); 403 nft_chain_filter_ipv4_fini(); 404 nft_chain_filter_netdev_fini(); 405 } 406