Back to home page

OSCL-LXR

 
 

    


0001 #include <linux/init.h>
0002 #include <linux/kernel.h>
0003 #include <linux/netdevice.h>
0004 #include <net/net_namespace.h>
0005 #include <net/netfilter/nf_tables.h>
0006 #include <linux/netfilter_ipv4.h>
0007 #include <linux/netfilter_ipv6.h>
0008 #include <linux/netfilter_bridge.h>
0009 #include <linux/netfilter_arp.h>
0010 #include <net/netfilter/nf_tables_ipv4.h>
0011 #include <net/netfilter/nf_tables_ipv6.h>
0012 
0013 #ifdef CONFIG_NF_TABLES_IPV4
0014 static unsigned int nft_do_chain_ipv4(void *priv,
0015                       struct sk_buff *skb,
0016                       const struct nf_hook_state *state)
0017 {
0018     struct nft_pktinfo pkt;
0019 
0020     nft_set_pktinfo(&pkt, skb, state);
0021     nft_set_pktinfo_ipv4(&pkt);
0022 
0023     return nft_do_chain(&pkt, priv);
0024 }
0025 
0026 static const struct nft_chain_type nft_chain_filter_ipv4 = {
0027     .name       = "filter",
0028     .type       = NFT_CHAIN_T_DEFAULT,
0029     .family     = NFPROTO_IPV4,
0030     .hook_mask  = (1 << NF_INET_LOCAL_IN) |
0031               (1 << NF_INET_LOCAL_OUT) |
0032               (1 << NF_INET_FORWARD) |
0033               (1 << NF_INET_PRE_ROUTING) |
0034               (1 << NF_INET_POST_ROUTING),
0035     .hooks      = {
0036         [NF_INET_LOCAL_IN]  = nft_do_chain_ipv4,
0037         [NF_INET_LOCAL_OUT] = nft_do_chain_ipv4,
0038         [NF_INET_FORWARD]   = nft_do_chain_ipv4,
0039         [NF_INET_PRE_ROUTING]   = nft_do_chain_ipv4,
0040         [NF_INET_POST_ROUTING]  = nft_do_chain_ipv4,
0041     },
0042 };
0043 
0044 static void nft_chain_filter_ipv4_init(void)
0045 {
0046     nft_register_chain_type(&nft_chain_filter_ipv4);
0047 }
0048 static void nft_chain_filter_ipv4_fini(void)
0049 {
0050     nft_unregister_chain_type(&nft_chain_filter_ipv4);
0051 }
0052 
0053 #else
0054 static inline void nft_chain_filter_ipv4_init(void) {}
0055 static inline void nft_chain_filter_ipv4_fini(void) {}
0056 #endif /* CONFIG_NF_TABLES_IPV4 */
0057 
0058 #ifdef CONFIG_NF_TABLES_ARP
0059 static unsigned int nft_do_chain_arp(void *priv, struct sk_buff *skb,
0060                      const struct nf_hook_state *state)
0061 {
0062     struct nft_pktinfo pkt;
0063 
0064     nft_set_pktinfo(&pkt, skb, state);
0065     nft_set_pktinfo_unspec(&pkt);
0066 
0067     return nft_do_chain(&pkt, priv);
0068 }
0069 
0070 static const struct nft_chain_type nft_chain_filter_arp = {
0071     .name       = "filter",
0072     .type       = NFT_CHAIN_T_DEFAULT,
0073     .family     = NFPROTO_ARP,
0074     .owner      = THIS_MODULE,
0075     .hook_mask  = (1 << NF_ARP_IN) |
0076               (1 << NF_ARP_OUT),
0077     .hooks      = {
0078         [NF_ARP_IN]     = nft_do_chain_arp,
0079         [NF_ARP_OUT]        = nft_do_chain_arp,
0080     },
0081 };
0082 
0083 static void nft_chain_filter_arp_init(void)
0084 {
0085     nft_register_chain_type(&nft_chain_filter_arp);
0086 }
0087 
0088 static void nft_chain_filter_arp_fini(void)
0089 {
0090     nft_unregister_chain_type(&nft_chain_filter_arp);
0091 }
0092 #else
0093 static inline void nft_chain_filter_arp_init(void) {}
0094 static inline void nft_chain_filter_arp_fini(void) {}
0095 #endif /* CONFIG_NF_TABLES_ARP */
0096 
0097 #ifdef CONFIG_NF_TABLES_IPV6
0098 static unsigned int nft_do_chain_ipv6(void *priv,
0099                       struct sk_buff *skb,
0100                       const struct nf_hook_state *state)
0101 {
0102     struct nft_pktinfo pkt;
0103 
0104     nft_set_pktinfo(&pkt, skb, state);
0105     nft_set_pktinfo_ipv6(&pkt);
0106 
0107     return nft_do_chain(&pkt, priv);
0108 }
0109 
0110 static const struct nft_chain_type nft_chain_filter_ipv6 = {
0111     .name       = "filter",
0112     .type       = NFT_CHAIN_T_DEFAULT,
0113     .family     = NFPROTO_IPV6,
0114     .hook_mask  = (1 << NF_INET_LOCAL_IN) |
0115               (1 << NF_INET_LOCAL_OUT) |
0116               (1 << NF_INET_FORWARD) |
0117               (1 << NF_INET_PRE_ROUTING) |
0118               (1 << NF_INET_POST_ROUTING),
0119     .hooks      = {
0120         [NF_INET_LOCAL_IN]  = nft_do_chain_ipv6,
0121         [NF_INET_LOCAL_OUT] = nft_do_chain_ipv6,
0122         [NF_INET_FORWARD]   = nft_do_chain_ipv6,
0123         [NF_INET_PRE_ROUTING]   = nft_do_chain_ipv6,
0124         [NF_INET_POST_ROUTING]  = nft_do_chain_ipv6,
0125     },
0126 };
0127 
0128 static void nft_chain_filter_ipv6_init(void)
0129 {
0130     nft_register_chain_type(&nft_chain_filter_ipv6);
0131 }
0132 
0133 static void nft_chain_filter_ipv6_fini(void)
0134 {
0135     nft_unregister_chain_type(&nft_chain_filter_ipv6);
0136 }
0137 #else
0138 static inline void nft_chain_filter_ipv6_init(void) {}
0139 static inline void nft_chain_filter_ipv6_fini(void) {}
0140 #endif /* CONFIG_NF_TABLES_IPV6 */
0141 
0142 #ifdef CONFIG_NF_TABLES_INET
0143 static unsigned int nft_do_chain_inet(void *priv, struct sk_buff *skb,
0144                       const struct nf_hook_state *state)
0145 {
0146     struct nft_pktinfo pkt;
0147 
0148     nft_set_pktinfo(&pkt, skb, state);
0149 
0150     switch (state->pf) {
0151     case NFPROTO_IPV4:
0152         nft_set_pktinfo_ipv4(&pkt);
0153         break;
0154     case NFPROTO_IPV6:
0155         nft_set_pktinfo_ipv6(&pkt);
0156         break;
0157     default:
0158         break;
0159     }
0160 
0161     return nft_do_chain(&pkt, priv);
0162 }
0163 
0164 static unsigned int nft_do_chain_inet_ingress(void *priv, struct sk_buff *skb,
0165                           const struct nf_hook_state *state)
0166 {
0167     struct nf_hook_state ingress_state = *state;
0168     struct nft_pktinfo pkt;
0169 
0170     switch (skb->protocol) {
0171     case htons(ETH_P_IP):
0172         /* Original hook is NFPROTO_NETDEV and NF_NETDEV_INGRESS. */
0173         ingress_state.pf = NFPROTO_IPV4;
0174         ingress_state.hook = NF_INET_INGRESS;
0175         nft_set_pktinfo(&pkt, skb, &ingress_state);
0176 
0177         if (nft_set_pktinfo_ipv4_ingress(&pkt) < 0)
0178             return NF_DROP;
0179         break;
0180     case htons(ETH_P_IPV6):
0181         ingress_state.pf = NFPROTO_IPV6;
0182         ingress_state.hook = NF_INET_INGRESS;
0183         nft_set_pktinfo(&pkt, skb, &ingress_state);
0184 
0185         if (nft_set_pktinfo_ipv6_ingress(&pkt) < 0)
0186             return NF_DROP;
0187         break;
0188     default:
0189         return NF_ACCEPT;
0190     }
0191 
0192     return nft_do_chain(&pkt, priv);
0193 }
0194 
0195 static const struct nft_chain_type nft_chain_filter_inet = {
0196     .name       = "filter",
0197     .type       = NFT_CHAIN_T_DEFAULT,
0198     .family     = NFPROTO_INET,
0199     .hook_mask  = (1 << NF_INET_INGRESS) |
0200               (1 << NF_INET_LOCAL_IN) |
0201               (1 << NF_INET_LOCAL_OUT) |
0202               (1 << NF_INET_FORWARD) |
0203               (1 << NF_INET_PRE_ROUTING) |
0204               (1 << NF_INET_POST_ROUTING),
0205     .hooks      = {
0206         [NF_INET_INGRESS]   = nft_do_chain_inet_ingress,
0207         [NF_INET_LOCAL_IN]  = nft_do_chain_inet,
0208         [NF_INET_LOCAL_OUT] = nft_do_chain_inet,
0209         [NF_INET_FORWARD]   = nft_do_chain_inet,
0210         [NF_INET_PRE_ROUTING]   = nft_do_chain_inet,
0211         [NF_INET_POST_ROUTING]  = nft_do_chain_inet,
0212         },
0213 };
0214 
0215 static void nft_chain_filter_inet_init(void)
0216 {
0217     nft_register_chain_type(&nft_chain_filter_inet);
0218 }
0219 
0220 static void nft_chain_filter_inet_fini(void)
0221 {
0222     nft_unregister_chain_type(&nft_chain_filter_inet);
0223 }
0224 #else
0225 static inline void nft_chain_filter_inet_init(void) {}
0226 static inline void nft_chain_filter_inet_fini(void) {}
0227 #endif /* CONFIG_NF_TABLES_IPV6 */
0228 
0229 #if IS_ENABLED(CONFIG_NF_TABLES_BRIDGE)
0230 static unsigned int
0231 nft_do_chain_bridge(void *priv,
0232             struct sk_buff *skb,
0233             const struct nf_hook_state *state)
0234 {
0235     struct nft_pktinfo pkt;
0236 
0237     nft_set_pktinfo(&pkt, skb, state);
0238 
0239     switch (eth_hdr(skb)->h_proto) {
0240     case htons(ETH_P_IP):
0241         nft_set_pktinfo_ipv4_validate(&pkt);
0242         break;
0243     case htons(ETH_P_IPV6):
0244         nft_set_pktinfo_ipv6_validate(&pkt);
0245         break;
0246     default:
0247         nft_set_pktinfo_unspec(&pkt);
0248         break;
0249     }
0250 
0251     return nft_do_chain(&pkt, priv);
0252 }
0253 
0254 static const struct nft_chain_type nft_chain_filter_bridge = {
0255     .name       = "filter",
0256     .type       = NFT_CHAIN_T_DEFAULT,
0257     .family     = NFPROTO_BRIDGE,
0258     .hook_mask  = (1 << NF_BR_PRE_ROUTING) |
0259               (1 << NF_BR_LOCAL_IN) |
0260               (1 << NF_BR_FORWARD) |
0261               (1 << NF_BR_LOCAL_OUT) |
0262               (1 << NF_BR_POST_ROUTING),
0263     .hooks      = {
0264         [NF_BR_PRE_ROUTING] = nft_do_chain_bridge,
0265         [NF_BR_LOCAL_IN]    = nft_do_chain_bridge,
0266         [NF_BR_FORWARD]     = nft_do_chain_bridge,
0267         [NF_BR_LOCAL_OUT]   = nft_do_chain_bridge,
0268         [NF_BR_POST_ROUTING]    = nft_do_chain_bridge,
0269     },
0270 };
0271 
0272 static void nft_chain_filter_bridge_init(void)
0273 {
0274     nft_register_chain_type(&nft_chain_filter_bridge);
0275 }
0276 
0277 static void nft_chain_filter_bridge_fini(void)
0278 {
0279     nft_unregister_chain_type(&nft_chain_filter_bridge);
0280 }
0281 #else
0282 static inline void nft_chain_filter_bridge_init(void) {}
0283 static inline void nft_chain_filter_bridge_fini(void) {}
0284 #endif /* CONFIG_NF_TABLES_BRIDGE */
0285 
0286 #ifdef CONFIG_NF_TABLES_NETDEV
0287 static unsigned int nft_do_chain_netdev(void *priv, struct sk_buff *skb,
0288                     const struct nf_hook_state *state)
0289 {
0290     struct nft_pktinfo pkt;
0291 
0292     nft_set_pktinfo(&pkt, skb, state);
0293 
0294     switch (skb->protocol) {
0295     case htons(ETH_P_IP):
0296         nft_set_pktinfo_ipv4_validate(&pkt);
0297         break;
0298     case htons(ETH_P_IPV6):
0299         nft_set_pktinfo_ipv6_validate(&pkt);
0300         break;
0301     default:
0302         nft_set_pktinfo_unspec(&pkt);
0303         break;
0304     }
0305 
0306     return nft_do_chain(&pkt, priv);
0307 }
0308 
0309 static const struct nft_chain_type nft_chain_filter_netdev = {
0310     .name       = "filter",
0311     .type       = NFT_CHAIN_T_DEFAULT,
0312     .family     = NFPROTO_NETDEV,
0313     .hook_mask  = (1 << NF_NETDEV_INGRESS) |
0314               (1 << NF_NETDEV_EGRESS),
0315     .hooks      = {
0316         [NF_NETDEV_INGRESS] = nft_do_chain_netdev,
0317         [NF_NETDEV_EGRESS]  = nft_do_chain_netdev,
0318     },
0319 };
0320 
0321 static void nft_netdev_event(unsigned long event, struct net_device *dev,
0322                  struct nft_ctx *ctx)
0323 {
0324     struct nft_base_chain *basechain = nft_base_chain(ctx->chain);
0325     struct nft_hook *hook, *found = NULL;
0326     int n = 0;
0327 
0328     if (event != NETDEV_UNREGISTER)
0329         return;
0330 
0331     list_for_each_entry(hook, &basechain->hook_list, list) {
0332         if (hook->ops.dev == dev)
0333             found = hook;
0334 
0335         n++;
0336     }
0337     if (!found)
0338         return;
0339 
0340     if (n > 1) {
0341         nf_unregister_net_hook(ctx->net, &found->ops);
0342         list_del_rcu(&found->list);
0343         kfree_rcu(found, rcu);
0344         return;
0345     }
0346 
0347     __nft_release_basechain(ctx);
0348 }
0349 
0350 static int nf_tables_netdev_event(struct notifier_block *this,
0351                   unsigned long event, void *ptr)
0352 {
0353     struct net_device *dev = netdev_notifier_info_to_dev(ptr);
0354     struct nftables_pernet *nft_net;
0355     struct nft_table *table;
0356     struct nft_chain *chain, *nr;
0357     struct nft_ctx ctx = {
0358         .net    = dev_net(dev),
0359     };
0360 
0361     if (event != NETDEV_UNREGISTER &&
0362         event != NETDEV_CHANGENAME)
0363         return NOTIFY_DONE;
0364 
0365     if (!check_net(ctx.net))
0366         return NOTIFY_DONE;
0367 
0368     nft_net = nft_pernet(ctx.net);
0369     mutex_lock(&nft_net->commit_mutex);
0370     list_for_each_entry(table, &nft_net->tables, list) {
0371         if (table->family != NFPROTO_NETDEV)
0372             continue;
0373 
0374         ctx.family = table->family;
0375         ctx.table = table;
0376         list_for_each_entry_safe(chain, nr, &table->chains, list) {
0377             if (!nft_is_base_chain(chain))
0378                 continue;
0379 
0380             ctx.chain = chain;
0381             nft_netdev_event(event, dev, &ctx);
0382         }
0383     }
0384     mutex_unlock(&nft_net->commit_mutex);
0385 
0386     return NOTIFY_DONE;
0387 }
0388 
0389 static struct notifier_block nf_tables_netdev_notifier = {
0390     .notifier_call  = nf_tables_netdev_event,
0391 };
0392 
0393 static int nft_chain_filter_netdev_init(void)
0394 {
0395     int err;
0396 
0397     nft_register_chain_type(&nft_chain_filter_netdev);
0398 
0399     err = register_netdevice_notifier(&nf_tables_netdev_notifier);
0400     if (err)
0401         goto err_register_netdevice_notifier;
0402 
0403     return 0;
0404 
0405 err_register_netdevice_notifier:
0406     nft_unregister_chain_type(&nft_chain_filter_netdev);
0407 
0408     return err;
0409 }
0410 
0411 static void nft_chain_filter_netdev_fini(void)
0412 {
0413     nft_unregister_chain_type(&nft_chain_filter_netdev);
0414     unregister_netdevice_notifier(&nf_tables_netdev_notifier);
0415 }
0416 #else
0417 static inline int nft_chain_filter_netdev_init(void) { return 0; }
0418 static inline void nft_chain_filter_netdev_fini(void) {}
0419 #endif /* CONFIG_NF_TABLES_NETDEV */
0420 
0421 int __init nft_chain_filter_init(void)
0422 {
0423     int err;
0424 
0425     err = nft_chain_filter_netdev_init();
0426     if (err < 0)
0427         return err;
0428 
0429     nft_chain_filter_ipv4_init();
0430     nft_chain_filter_ipv6_init();
0431     nft_chain_filter_arp_init();
0432     nft_chain_filter_inet_init();
0433     nft_chain_filter_bridge_init();
0434 
0435     return 0;
0436 }
0437 
0438 void nft_chain_filter_fini(void)
0439 {
0440     nft_chain_filter_bridge_fini();
0441     nft_chain_filter_inet_fini();
0442     nft_chain_filter_arp_fini();
0443     nft_chain_filter_ipv6_fini();
0444     nft_chain_filter_ipv4_fini();
0445     nft_chain_filter_netdev_fini();
0446 }