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 unsigned int nft_do_chain_inet_ingress(void *priv, struct sk_buff *skb, 165 const struct nf_hook_state *state) 166 { 167 struct nf_hook_state ingress_state = *state; 168 struct nft_pktinfo pkt; 169 170 switch (skb->protocol) { 171 case htons(ETH_P_IP): 172 /* Original hook is NFPROTO_NETDEV and NF_NETDEV_INGRESS. */ 173 ingress_state.pf = NFPROTO_IPV4; 174 ingress_state.hook = NF_INET_INGRESS; 175 nft_set_pktinfo(&pkt, skb, &ingress_state); 176 177 if (nft_set_pktinfo_ipv4_ingress(&pkt, skb) < 0) 178 return NF_DROP; 179 break; 180 case htons(ETH_P_IPV6): 181 ingress_state.pf = NFPROTO_IPV6; 182 ingress_state.hook = NF_INET_INGRESS; 183 nft_set_pktinfo(&pkt, skb, &ingress_state); 184 185 if (nft_set_pktinfo_ipv6_ingress(&pkt, skb) < 0) 186 return NF_DROP; 187 break; 188 default: 189 return NF_ACCEPT; 190 } 191 192 return nft_do_chain(&pkt, priv); 193 } 194 195 static const struct nft_chain_type nft_chain_filter_inet = { 196 .name = "filter", 197 .type = NFT_CHAIN_T_DEFAULT, 198 .family = NFPROTO_INET, 199 .hook_mask = (1 << NF_INET_INGRESS) | 200 (1 << NF_INET_LOCAL_IN) | 201 (1 << NF_INET_LOCAL_OUT) | 202 (1 << NF_INET_FORWARD) | 203 (1 << NF_INET_PRE_ROUTING) | 204 (1 << NF_INET_POST_ROUTING), 205 .hooks = { 206 [NF_INET_INGRESS] = nft_do_chain_inet_ingress, 207 [NF_INET_LOCAL_IN] = nft_do_chain_inet, 208 [NF_INET_LOCAL_OUT] = nft_do_chain_inet, 209 [NF_INET_FORWARD] = nft_do_chain_inet, 210 [NF_INET_PRE_ROUTING] = nft_do_chain_inet, 211 [NF_INET_POST_ROUTING] = nft_do_chain_inet, 212 }, 213 }; 214 215 static void nft_chain_filter_inet_init(void) 216 { 217 nft_register_chain_type(&nft_chain_filter_inet); 218 } 219 220 static void nft_chain_filter_inet_fini(void) 221 { 222 nft_unregister_chain_type(&nft_chain_filter_inet); 223 } 224 #else 225 static inline void nft_chain_filter_inet_init(void) {} 226 static inline void nft_chain_filter_inet_fini(void) {} 227 #endif /* CONFIG_NF_TABLES_IPV6 */ 228 229 #if IS_ENABLED(CONFIG_NF_TABLES_BRIDGE) 230 static unsigned int 231 nft_do_chain_bridge(void *priv, 232 struct sk_buff *skb, 233 const struct nf_hook_state *state) 234 { 235 struct nft_pktinfo pkt; 236 237 nft_set_pktinfo(&pkt, skb, state); 238 239 switch (eth_hdr(skb)->h_proto) { 240 case htons(ETH_P_IP): 241 nft_set_pktinfo_ipv4_validate(&pkt, skb); 242 break; 243 case htons(ETH_P_IPV6): 244 nft_set_pktinfo_ipv6_validate(&pkt, skb); 245 break; 246 default: 247 nft_set_pktinfo_unspec(&pkt, skb); 248 break; 249 } 250 251 return nft_do_chain(&pkt, priv); 252 } 253 254 static const struct nft_chain_type nft_chain_filter_bridge = { 255 .name = "filter", 256 .type = NFT_CHAIN_T_DEFAULT, 257 .family = NFPROTO_BRIDGE, 258 .hook_mask = (1 << NF_BR_PRE_ROUTING) | 259 (1 << NF_BR_LOCAL_IN) | 260 (1 << NF_BR_FORWARD) | 261 (1 << NF_BR_LOCAL_OUT) | 262 (1 << NF_BR_POST_ROUTING), 263 .hooks = { 264 [NF_BR_PRE_ROUTING] = nft_do_chain_bridge, 265 [NF_BR_LOCAL_IN] = nft_do_chain_bridge, 266 [NF_BR_FORWARD] = nft_do_chain_bridge, 267 [NF_BR_LOCAL_OUT] = nft_do_chain_bridge, 268 [NF_BR_POST_ROUTING] = nft_do_chain_bridge, 269 }, 270 }; 271 272 static void nft_chain_filter_bridge_init(void) 273 { 274 nft_register_chain_type(&nft_chain_filter_bridge); 275 } 276 277 static void nft_chain_filter_bridge_fini(void) 278 { 279 nft_unregister_chain_type(&nft_chain_filter_bridge); 280 } 281 #else 282 static inline void nft_chain_filter_bridge_init(void) {} 283 static inline void nft_chain_filter_bridge_fini(void) {} 284 #endif /* CONFIG_NF_TABLES_BRIDGE */ 285 286 #ifdef CONFIG_NF_TABLES_NETDEV 287 static unsigned int nft_do_chain_netdev(void *priv, struct sk_buff *skb, 288 const struct nf_hook_state *state) 289 { 290 struct nft_pktinfo pkt; 291 292 nft_set_pktinfo(&pkt, skb, state); 293 294 switch (skb->protocol) { 295 case htons(ETH_P_IP): 296 nft_set_pktinfo_ipv4_validate(&pkt, skb); 297 break; 298 case htons(ETH_P_IPV6): 299 nft_set_pktinfo_ipv6_validate(&pkt, skb); 300 break; 301 default: 302 nft_set_pktinfo_unspec(&pkt, skb); 303 break; 304 } 305 306 return nft_do_chain(&pkt, priv); 307 } 308 309 static const struct nft_chain_type nft_chain_filter_netdev = { 310 .name = "filter", 311 .type = NFT_CHAIN_T_DEFAULT, 312 .family = NFPROTO_NETDEV, 313 .hook_mask = (1 << NF_NETDEV_INGRESS), 314 .hooks = { 315 [NF_NETDEV_INGRESS] = nft_do_chain_netdev, 316 }, 317 }; 318 319 static void nft_netdev_event(unsigned long event, struct net_device *dev, 320 struct nft_ctx *ctx) 321 { 322 struct nft_base_chain *basechain = nft_base_chain(ctx->chain); 323 struct nft_hook *hook, *found = NULL; 324 int n = 0; 325 326 if (event != NETDEV_UNREGISTER) 327 return; 328 329 list_for_each_entry(hook, &basechain->hook_list, list) { 330 if (hook->ops.dev == dev) 331 found = hook; 332 333 n++; 334 } 335 if (!found) 336 return; 337 338 if (n > 1) { 339 nf_unregister_net_hook(ctx->net, &found->ops); 340 list_del_rcu(&found->list); 341 kfree_rcu(found, rcu); 342 return; 343 } 344 345 /* UNREGISTER events are also happening on netns exit. 346 * 347 * Although nf_tables core releases all tables/chains, only this event 348 * handler provides guarantee that hook->ops.dev is still accessible, 349 * so we cannot skip exiting net namespaces. 350 */ 351 __nft_release_basechain(ctx); 352 } 353 354 static int nf_tables_netdev_event(struct notifier_block *this, 355 unsigned long event, void *ptr) 356 { 357 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 358 struct nft_table *table; 359 struct nft_chain *chain, *nr; 360 struct nft_ctx ctx = { 361 .net = dev_net(dev), 362 }; 363 364 if (event != NETDEV_UNREGISTER && 365 event != NETDEV_CHANGENAME) 366 return NOTIFY_DONE; 367 368 mutex_lock(&ctx.net->nft.commit_mutex); 369 list_for_each_entry(table, &ctx.net->nft.tables, list) { 370 if (table->family != NFPROTO_NETDEV) 371 continue; 372 373 ctx.family = table->family; 374 ctx.table = table; 375 list_for_each_entry_safe(chain, nr, &table->chains, list) { 376 if (!nft_is_base_chain(chain)) 377 continue; 378 379 ctx.chain = chain; 380 nft_netdev_event(event, dev, &ctx); 381 } 382 } 383 mutex_unlock(&ctx.net->nft.commit_mutex); 384 385 return NOTIFY_DONE; 386 } 387 388 static struct notifier_block nf_tables_netdev_notifier = { 389 .notifier_call = nf_tables_netdev_event, 390 }; 391 392 static int nft_chain_filter_netdev_init(void) 393 { 394 int err; 395 396 nft_register_chain_type(&nft_chain_filter_netdev); 397 398 err = register_netdevice_notifier(&nf_tables_netdev_notifier); 399 if (err) 400 goto err_register_netdevice_notifier; 401 402 return 0; 403 404 err_register_netdevice_notifier: 405 nft_unregister_chain_type(&nft_chain_filter_netdev); 406 407 return err; 408 } 409 410 static void nft_chain_filter_netdev_fini(void) 411 { 412 nft_unregister_chain_type(&nft_chain_filter_netdev); 413 unregister_netdevice_notifier(&nf_tables_netdev_notifier); 414 } 415 #else 416 static inline int nft_chain_filter_netdev_init(void) { return 0; } 417 static inline void nft_chain_filter_netdev_fini(void) {} 418 #endif /* CONFIG_NF_TABLES_NETDEV */ 419 420 int __init nft_chain_filter_init(void) 421 { 422 int err; 423 424 err = nft_chain_filter_netdev_init(); 425 if (err < 0) 426 return err; 427 428 nft_chain_filter_ipv4_init(); 429 nft_chain_filter_ipv6_init(); 430 nft_chain_filter_arp_init(); 431 nft_chain_filter_inet_init(); 432 nft_chain_filter_bridge_init(); 433 434 return 0; 435 } 436 437 void nft_chain_filter_fini(void) 438 { 439 nft_chain_filter_bridge_fini(); 440 nft_chain_filter_inet_fini(); 441 nft_chain_filter_arp_fini(); 442 nft_chain_filter_ipv6_fini(); 443 nft_chain_filter_ipv4_fini(); 444 nft_chain_filter_netdev_fini(); 445 } 446