root/net/netfilter/nft_chain_filter.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nft_do_chain_ipv4
  2. nft_chain_filter_ipv4_init
  3. nft_chain_filter_ipv4_fini
  4. nft_chain_filter_ipv4_init
  5. nft_chain_filter_ipv4_fini
  6. nft_do_chain_arp
  7. nft_chain_filter_arp_init
  8. nft_chain_filter_arp_fini
  9. nft_chain_filter_arp_init
  10. nft_chain_filter_arp_fini
  11. nft_do_chain_ipv6
  12. nft_chain_filter_ipv6_init
  13. nft_chain_filter_ipv6_fini
  14. nft_chain_filter_ipv6_init
  15. nft_chain_filter_ipv6_fini
  16. nft_do_chain_inet
  17. nft_chain_filter_inet_init
  18. nft_chain_filter_inet_fini
  19. nft_chain_filter_inet_init
  20. nft_chain_filter_inet_fini
  21. nft_do_chain_bridge
  22. nft_chain_filter_bridge_init
  23. nft_chain_filter_bridge_fini
  24. nft_chain_filter_bridge_init
  25. nft_chain_filter_bridge_fini
  26. nft_do_chain_netdev
  27. nft_netdev_event
  28. nf_tables_netdev_event
  29. nft_chain_filter_netdev_init
  30. nft_chain_filter_netdev_fini
  31. nft_chain_filter_netdev_init
  32. nft_chain_filter_netdev_fini
  33. nft_chain_filter_init
  34. nft_chain_filter_fini

   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 }

/* [<][>][^][v][top][bottom][index][help] */