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); 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); 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); 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); 153 break; 154 case NFPROTO_IPV6: 155 nft_set_pktinfo_ipv6(&pkt); 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) < 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) < 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); 242 break; 243 case htons(ETH_P_IPV6): 244 nft_set_pktinfo_ipv6_validate(&pkt); 245 break; 246 default: 247 nft_set_pktinfo_unspec(&pkt); 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); 297 break; 298 case htons(ETH_P_IPV6): 299 nft_set_pktinfo_ipv6_validate(&pkt); 300 break; 301 default: 302 nft_set_pktinfo_unspec(&pkt); 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 (1 << NF_NETDEV_EGRESS), 315 .hooks = { 316 [NF_NETDEV_INGRESS] = nft_do_chain_netdev, 317 [NF_NETDEV_EGRESS] = nft_do_chain_netdev, 318 }, 319 }; 320 321 static void nft_netdev_event(unsigned long event, struct net_device *dev, 322 struct nft_ctx *ctx) 323 { 324 struct nft_base_chain *basechain = nft_base_chain(ctx->chain); 325 struct nft_hook *hook, *found = NULL; 326 int n = 0; 327 328 if (event != NETDEV_UNREGISTER) 329 return; 330 331 list_for_each_entry(hook, &basechain->hook_list, list) { 332 if (hook->ops.dev == dev) 333 found = hook; 334 335 n++; 336 } 337 if (!found) 338 return; 339 340 if (n > 1) { 341 nf_unregister_net_hook(ctx->net, &found->ops); 342 list_del_rcu(&found->list); 343 kfree_rcu(found, rcu); 344 return; 345 } 346 347 __nft_release_basechain(ctx); 348 } 349 350 static int nf_tables_netdev_event(struct notifier_block *this, 351 unsigned long event, void *ptr) 352 { 353 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 354 struct nftables_pernet *nft_net; 355 struct nft_table *table; 356 struct nft_chain *chain, *nr; 357 struct nft_ctx ctx = { 358 .net = dev_net(dev), 359 }; 360 361 if (event != NETDEV_UNREGISTER && 362 event != NETDEV_CHANGENAME) 363 return NOTIFY_DONE; 364 365 if (!check_net(ctx.net)) 366 return NOTIFY_DONE; 367 368 nft_net = nft_pernet(ctx.net); 369 mutex_lock(&nft_net->commit_mutex); 370 list_for_each_entry(table, &nft_net->tables, list) { 371 if (table->family != NFPROTO_NETDEV) 372 continue; 373 374 ctx.family = table->family; 375 ctx.table = table; 376 list_for_each_entry_safe(chain, nr, &table->chains, list) { 377 if (!nft_is_base_chain(chain)) 378 continue; 379 380 ctx.chain = chain; 381 nft_netdev_event(event, dev, &ctx); 382 } 383 } 384 mutex_unlock(&nft_net->commit_mutex); 385 386 return NOTIFY_DONE; 387 } 388 389 static struct notifier_block nf_tables_netdev_notifier = { 390 .notifier_call = nf_tables_netdev_event, 391 }; 392 393 static int nft_chain_filter_netdev_init(void) 394 { 395 int err; 396 397 nft_register_chain_type(&nft_chain_filter_netdev); 398 399 err = register_netdevice_notifier(&nf_tables_netdev_notifier); 400 if (err) 401 goto err_register_netdevice_notifier; 402 403 return 0; 404 405 err_register_netdevice_notifier: 406 nft_unregister_chain_type(&nft_chain_filter_netdev); 407 408 return err; 409 } 410 411 static void nft_chain_filter_netdev_fini(void) 412 { 413 nft_unregister_chain_type(&nft_chain_filter_netdev); 414 unregister_netdevice_notifier(&nf_tables_netdev_notifier); 415 } 416 #else 417 static inline int nft_chain_filter_netdev_init(void) { return 0; } 418 static inline void nft_chain_filter_netdev_fini(void) {} 419 #endif /* CONFIG_NF_TABLES_NETDEV */ 420 421 int __init nft_chain_filter_init(void) 422 { 423 int err; 424 425 err = nft_chain_filter_netdev_init(); 426 if (err < 0) 427 return err; 428 429 nft_chain_filter_ipv4_init(); 430 nft_chain_filter_ipv6_init(); 431 nft_chain_filter_arp_init(); 432 nft_chain_filter_inet_init(); 433 nft_chain_filter_bridge_init(); 434 435 return 0; 436 } 437 438 void nft_chain_filter_fini(void) 439 { 440 nft_chain_filter_bridge_fini(); 441 nft_chain_filter_inet_fini(); 442 nft_chain_filter_arp_fini(); 443 nft_chain_filter_ipv6_fini(); 444 nft_chain_filter_ipv4_fini(); 445 nft_chain_filter_netdev_fini(); 446 } 447