cregit-Linux how code gets into the kernel

Release 4.11 net/netfilter/nf_tables_api.c

Directory: net/netfilter
/*
 * Copyright (c) 2007-2009 Patrick McHardy <kaber@trash.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * Development of this code funded by Astaro AG (http://www.astaro.com/)
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/netfilter.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables_core.h>
#include <net/netfilter/nf_tables.h>
#include <net/net_namespace.h>
#include <net/sock.h>

static LIST_HEAD(nf_tables_expressions);
static LIST_HEAD(nf_tables_objects);

/**
 *      nft_register_afinfo - register nf_tables address family info
 *
 *      @afi: address family info to register
 *
 *      Register the address family for use with nf_tables. Returns zero on
 *      success or a negative errno code otherwise.
 */

int nft_register_afinfo(struct net *net, struct nft_af_info *afi) { INIT_LIST_HEAD(&afi->tables); nfnl_lock(NFNL_SUBSYS_NFTABLES); list_add_tail_rcu(&afi->list, &net->nft.af_info); nfnl_unlock(NFNL_SUBSYS_NFTABLES); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Patrick McHardy4078.43%133.33%
Pablo Neira Ayuso1121.57%266.67%
Total51100.00%3100.00%

EXPORT_SYMBOL_GPL(nft_register_afinfo); static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi); /** * nft_unregister_afinfo - unregister nf_tables address family info * * @afi: address family info to unregister * * Unregister the address family for use with nf_tables. */
void nft_unregister_afinfo(struct net *net, struct nft_af_info *afi) { nfnl_lock(NFNL_SUBSYS_NFTABLES); __nft_release_afinfo(net, afi); list_del_rcu(&afi->list); nfnl_unlock(NFNL_SUBSYS_NFTABLES); }

Contributors

PersonTokensPropCommitsCommitProp
Patrick McHardy2767.50%133.33%
Pablo Neira Ayuso1332.50%266.67%
Total40100.00%3100.00%

EXPORT_SYMBOL_GPL(nft_unregister_afinfo);
static struct nft_af_info *nft_afinfo_lookup(struct net *net, int family) { struct nft_af_info *afi; list_for_each_entry(afi, &net->nft.af_info, list) { if (afi->family == family) return afi; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Patrick McHardy3986.67%150.00%
Pablo Neira Ayuso613.33%150.00%
Total45100.00%2100.00%


static struct nft_af_info * nf_tables_afinfo_lookup(struct net *net, int family, bool autoload) { struct nft_af_info *afi; afi = nft_afinfo_lookup(net, family); if (afi != NULL) return afi; #ifdef CONFIG_MODULES if (autoload) { nfnl_unlock(NFNL_SUBSYS_NFTABLES); request_module("nft-afinfo-%u", family); nfnl_lock(NFNL_SUBSYS_NFTABLES); afi = nft_afinfo_lookup(net, family); if (afi != NULL) return ERR_PTR(-EAGAIN); } #endif return ERR_PTR(-EAFNOSUPPORT); }

Contributors

PersonTokensPropCommitsCommitProp
Patrick McHardy9090.91%150.00%
Pablo Neira Ayuso99.09%150.00%
Total99100.00%2100.00%


static void nft_ctx_init(struct nft_ctx *ctx, struct net *net, const struct sk_buff *skb, const struct nlmsghdr *nlh, struct nft_af_info *afi, struct nft_table *table, struct nft_chain *chain, const struct nlattr * const *nla) { ctx->net = net; ctx->afi = afi; ctx->table = table; ctx->chain = chain; ctx->nla = nla; ctx->portid = NETLINK_CB(skb).portid; ctx->report = nlmsg_report(nlh); ctx->seq = nlh->nlmsg_seq; }

Contributors

PersonTokensPropCommitsCommitProp
Pablo Neira Ayuso109100.00%3100.00%
Total109100.00%3100.00%


static struct nft_trans *nft_trans_alloc_gfp(const struct nft_ctx *ctx, int msg_type, u32 size, gfp_t gfp) { struct nft_trans *trans; trans = kzalloc(sizeof(struct nft_trans) + size, gfp); if (trans == NULL) return NULL; trans->msg_type = msg_type; trans->ctx = *ctx; return trans; }

Contributors

PersonTokensPropCommitsCommitProp
Pablo Neira Ayuso68100.00%4100.00%
Total68100.00%4100.00%


static struct nft_trans *nft_trans_alloc(const struct nft_ctx *ctx, int msg_type, u32 size) { return nft_trans_alloc_gfp(ctx, msg_type, size, GFP_KERNEL); }

Contributors

PersonTokensPropCommitsCommitProp
Pablo Neira Ayuso32100.00%1100.00%
Total32100.00%1100.00%


static void nft_trans_destroy(struct nft_trans *trans) { list_del(&trans->list); kfree(trans); }

Contributors

PersonTokensPropCommitsCommitProp
Pablo Neira Ayuso24100.00%1100.00%
Total24100.00%1100.00%


static int nf_tables_register_hooks(struct net *net, const struct nft_table *table, struct nft_chain *chain, unsigned int hook_nops) { if (table->flags & NFT_TABLE_F_DORMANT || !(chain->flags & NFT_BASE_CHAIN)) return 0; return nf_register_net_hooks(net, nft_base_chain(chain)->ops, hook_nops); }

Contributors

PersonTokensPropCommitsCommitProp
Pablo Neira Ayuso3862.30%360.00%
Arturo Borrero Gonzalez2032.79%120.00%
Eric W. Biedermann34.92%120.00%
Total61100.00%5100.00%


static void nf_tables_unregister_hooks(struct net *net, const struct nft_table *table, struct nft_chain *chain, unsigned int hook_nops) { if (table->flags & NFT_TABLE_F_DORMANT || !(chain->flags & NFT_BASE_CHAIN)) return; nf_unregister_net_hooks(net, nft_base_chain(chain)->ops, hook_nops); }

Contributors

PersonTokensPropCommitsCommitProp
Pablo Neira Ayuso3763.79%266.67%
Arturo Borrero Gonzalez2136.21%133.33%
Total58100.00%3100.00%


static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type) { struct nft_trans *trans; trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_table)); if (trans == NULL) return -ENOMEM; if (msg_type == NFT_MSG_NEWTABLE) nft_activate_next(ctx->net, ctx->table); list_add_tail(&trans->list, &ctx->net->nft.commit_list); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Arturo Borrero Gonzalez5162.96%133.33%
Patrick McHardy2328.40%133.33%
Pablo Neira Ayuso78.64%133.33%
Total81100.00%3100.00%


static int nft_deltable(struct nft_ctx *ctx) { int err; err = nft_trans_table_add(ctx, NFT_MSG_DELTABLE); if (err < 0) return err; nft_deactivate_next(ctx->net, ctx->table); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Arturo Borrero Gonzalez2758.70%133.33%
Patrick McHardy1430.43%133.33%
Pablo Neira Ayuso510.87%133.33%
Total46100.00%3100.00%


static int nft_trans_chain_add(struct nft_ctx *ctx, int msg_type) { struct nft_trans *trans; trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_chain)); if (trans == NULL) return -ENOMEM; if (msg_type == NFT_MSG_NEWCHAIN) nft_activate_next(ctx->net, ctx->chain); list_add_tail(&trans->list, &ctx->net->nft.commit_list); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Arturo Borrero Gonzalez5972.84%125.00%
Pablo Neira Ayuso1113.58%250.00%
Patrick McHardy1113.58%125.00%
Total81100.00%4100.00%


static int nft_delchain(struct nft_ctx *ctx) { int err; err = nft_trans_chain_add(ctx, NFT_MSG_DELCHAIN); if (err < 0) return err; ctx->table->use--; nft_deactivate_next(ctx->net, ctx->chain); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Arturo Borrero Gonzalez3871.70%133.33%
Pablo Neira Ayuso1528.30%266.67%
Total53100.00%3100.00%


static int nf_tables_delrule_deactivate(struct nft_ctx *ctx, struct nft_rule *rule) { /* You cannot delete the same rule twice */ if (nft_is_active_next(ctx->net, rule)) { nft_deactivate_next(ctx->net, rule); ctx->chain->use--; return 0; } return -ENOENT; }

Contributors

PersonTokensPropCommitsCommitProp
Arturo Borrero Gonzalez3362.26%120.00%
Patrick McHardy1528.30%240.00%
Pablo Neira Ayuso59.43%240.00%
Total53100.00%5100.00%


static struct nft_trans *nft_trans_rule_add(struct nft_ctx *ctx, int msg_type, struct nft_rule *rule) { struct nft_trans *trans; trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_rule)); if (trans == NULL) return NULL; if (msg_type == NFT_MSG_NEWRULE && ctx->nla[NFTA_RULE_ID] != NULL) { nft_trans_rule_id(trans) = ntohl(nla_get_be32(ctx->nla[NFTA_RULE_ID])); } nft_trans_rule(trans) = rule; list_add_tail(&trans->list, &ctx->net->nft.commit_list); return trans; }

Contributors

PersonTokensPropCommitsCommitProp
Patrick McHardy4035.71%120.00%
Pablo Neira Ayuso3733.04%240.00%
Arturo Borrero Gonzalez3430.36%120.00%
Tomasz Bursztyka10.89%120.00%
Total112100.00%5100.00%


static int nft_delrule(struct nft_ctx *ctx, struct nft_rule *rule) { struct nft_trans *trans; int err; trans = nft_trans_rule_add(ctx, NFT_MSG_DELRULE, rule); if (trans == NULL) return -ENOMEM; err = nf_tables_delrule_deactivate(ctx, rule); if (err < 0) { nft_trans_destroy(trans); return err; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Patrick McHardy4257.53%125.00%
Arturo Borrero Gonzalez2736.99%125.00%
Pablo Neira Ayuso45.48%250.00%
Total73100.00%4100.00%


static int nft_delrule_by_chain(struct nft_ctx *ctx) { struct nft_rule *rule; int err; list_for_each_entry(rule, &ctx->chain->rules, list) { err = nft_delrule(ctx, rule); if (err < 0) return err; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Arturo Borrero Gonzalez3162.00%133.33%
Patrick McHardy1734.00%133.33%
Pablo Neira Ayuso24.00%133.33%
Total50100.00%3100.00%


static int nft_trans_set_add(struct nft_ctx *ctx, int msg_type, struct nft_set *set) { struct nft_trans *trans; trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_set)); if (trans == NULL) return -ENOMEM; if (msg_type == NFT_MSG_NEWSET && ctx->nla[NFTA_SET_ID] != NULL) { nft_trans_set_id(trans) = ntohl(nla_get_be32(ctx->nla[NFTA_SET_ID])); nft_activate_next(ctx->net, set); } nft_trans_set(trans) = set; list_add_tail(&trans->list, &ctx->net->nft.commit_list); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Arturo Borrero Gonzalez7260.00%120.00%
Patrick McHardy3831.67%120.00%
Pablo Neira Ayuso108.33%360.00%
Total120100.00%5100.00%


static int nft_delset(struct nft_ctx *ctx, struct nft_set *set) { int err; err = nft_trans_set_add(ctx, NFT_MSG_DELSET, set); if (err < 0) return err; nft_deactivate_next(ctx->net, set); ctx->table->use--; return err; }

Contributors

PersonTokensPropCommitsCommitProp
Arturo Borrero Gonzalez3967.24%125.00%
Patrick McHardy1118.97%125.00%
Pablo Neira Ayuso813.79%250.00%
Total58100.00%4100.00%


static int nft_trans_obj_add(struct nft_ctx *ctx, int msg_type, struct nft_object *obj) { struct nft_trans *trans; trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_obj)); if (trans == NULL) return -ENOMEM; if (msg_type == NFT_MSG_NEWOBJ) nft_activate_next(ctx->net, obj); nft_trans_obj(trans) = obj; list_add_tail(&trans->list, &ctx->net->nft.commit_list); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Pablo Neira Ayuso91100.00%1100.00%
Total91100.00%1100.00%


static int nft_delobj(struct nft_ctx *ctx, struct nft_object *obj) { int err; err = nft_trans_obj_add(ctx, NFT_MSG_DELOBJ, obj); if (err < 0) return err; nft_deactivate_next(ctx->net, obj); ctx->table->use--; return err; }

Contributors

PersonTokensPropCommitsCommitProp
Pablo Neira Ayuso58100.00%1100.00%
Total58100.00%1100.00%

/* * Tables */
static struct nft_table *nft_table_lookup(const struct nft_af_info *afi, const struct nlattr *nla, u8 genmask) { struct nft_table *table; list_for_each_entry(table, &afi->tables, list) { if (!nla_strcmp(nla, table->name) && nft_active_genmask(table, genmask)) return table; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Patrick McHardy2641.27%125.00%
Arturo Borrero Gonzalez2539.68%125.00%
Pablo Neira Ayuso1219.05%250.00%
Total63100.00%4100.00%


static struct nft_table *nf_tables_table_lookup(const struct nft_af_info *afi, const struct nlattr *nla, u8 genmask) { struct nft_table *table; if (nla == NULL) return ERR_PTR(-EINVAL); table = nft_table_lookup(afi, nla, genmask); if (table != NULL) return table; return ERR_PTR(-ENOENT); }

Contributors

PersonTokensPropCommitsCommitProp
Arturo Borrero Gonzalez3551.47%125.00%
Patrick McHardy2536.76%125.00%
Pablo Neira Ayuso811.76%250.00%
Total68100.00%4100.00%


static inline u64 nf_tables_alloc_handle(struct nft_table *table) { return ++table->hgenerator; }

Contributors

PersonTokensPropCommitsCommitProp
Arturo Borrero Gonzalez1477.78%150.00%
Patrick McHardy422.22%150.00%
Total18100.00%2100.00%

static const struct nf_chain_type *chain_type[AF_MAX][NFT_CHAIN_T_MAX];
static const struct nf_chain_type * __nf_tables_chain_type_lookup(int family, const struct nlattr *nla) { int i; for (i = 0; i < NFT_CHAIN_T_MAX; i++) { if (chain_type[family][i] != NULL && !nla_strcmp(nla, chain_type[family][i]->name)) return chain_type[family][i]; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Arturo Borrero Gonzalez4863.16%133.33%
Pablo Neira Ayuso2228.95%133.33%
Patrick McHardy67.89%133.33%
Total76100.00%3100.00%


static const struct nf_chain_type * nf_tables_chain_type_lookup(const struct nft_af_info *afi, const struct nlattr *nla, bool autoload) { const struct nf_chain_type *type; type = __nf_tables_chain_type_lookup(afi->family, nla); if (type != NULL) return type; #ifdef CONFIG_MODULES if (autoload) { nfnl_unlock(NFNL_SUBSYS_NFTABLES); request_module("nft-chain-%u-%.*s", afi->family, nla_len(nla), (const char *)nla_data(nla)); nfnl_lock(NFNL_SUBSYS_NFTABLES); type = __nf_tables_chain_type_lookup(afi->family, nla); if (type != NULL) return ERR_PTR(-EAGAIN); } #endif return ERR_PTR(-ENOENT); }

Contributors

PersonTokensPropCommitsCommitProp
Arturo Borrero Gonzalez9575.40%125.00%
Pablo Neira Ayuso2217.46%250.00%
Patrick McHardy97.14%125.00%
Total126100.00%4100.00%

static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = { [NFTA_TABLE_NAME] = { .type = NLA_STRING, .len = NFT_TABLE_MAXNAMELEN - 1 }, [NFTA_TABLE_FLAGS] = { .type = NLA_U32 }, };
static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net, u32 portid, u32 seq, int event, u32 flags, int family, const struct nft_table *table) { struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; event |= NFNL_SUBSYS_NFTABLES << 8; nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags); if (nlh == NULL) goto nla_put_failure; nfmsg = nlmsg_data(nlh); nfmsg->nfgen_family = family; nfmsg->version = NFNETLINK_V0; nfmsg->res_id = htons(net->nft.base_seq & 0xffff); if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) || nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) || nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use))) goto nla_put_failure; nlmsg_end(skb, nlh); return 0; nla_put_failure: nlmsg_trim(skb, nlh); return -1; }

Contributors

PersonTokensPropCommitsCommitProp
Arturo Borrero Gonzalez10959.24%116.67%
Pablo Neira Ayuso7239.13%466.67%
Johannes Berg31.63%116.67%
Total184100.00%6100.00%


static void nf_tables_table_notify(const struct nft_ctx *ctx, int event) { struct sk_buff *skb; int err; if (!ctx->report && !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES)) return; skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); if (skb == NULL) goto err; err = nf_tables_fill_table_info(skb, ctx->net, ctx->portid, ctx->seq, event, 0, ctx->afi->family, ctx->table); if (err < 0) { kfree_skb(skb); goto err; } nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES, ctx->report, GFP_KERNEL); return; err: nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS); }

Contributors

PersonTokensPropCommitsCommitProp
Arturo Borrero Gonzalez10973.65%116.67%
Pablo Neira Ayuso2919.59%466.67%
Patrick McHardy106.76%116.67%
Total148100.00%6100.00%


static int nf_tables_dump_tables(struct sk_buff *skb, struct netlink_callback *cb) { const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); const struct nft_af_info *afi; const struct nft_table *table; unsigned int idx = 0, s_idx = cb->args[0]; struct net *net = sock_net(skb->sk); int family = nfmsg->nfgen_family; rcu_read_lock(); cb->seq = net->nft.base_seq; list_for_each_entry_rcu(afi, &net->nft.af_info, list) { if (family != NFPROTO_UNSPEC && family != afi->family) continue; list_for_each_entry_rcu(table, &afi->tables, list) { if (idx < s_idx) goto cont; if (idx > s_idx) memset(&cb->args[1], 0, sizeof(cb->args) - sizeof(cb->args[0])); if (!nft_is_active(net, table)) continue; if (nf_tables_fill_table_info(skb, net, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, NFT_MSG_NEWTABLE, NLM_F_MULTI, afi->family, table) < 0) goto done; nl_dump_check_consistent(cb, nlmsg_hdr(skb)); cont: idx++; } } done: rcu_read_unlock(); cb->args[0] = idx; return skb->len; }

Contributors

PersonTokensPropCommitsCommitProp
Arturo Borrero Gonzalez15361.20%116.67%
Patrick McHardy6927.60%116.67%
Pablo Neira Ayuso2811.20%466.67%
Total250100.00%6100.00%


static int nf_tables_gettable(struct net *net, struct sock *nlsk, struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const nla[]) { const struct nfgenmsg *nfmsg = nlmsg_data(nlh); u8 genmask = nft_genmask_cur(net); const struct nft_af_info *afi; const struct nft_table *table; struct sk_buff *skb2; int family = nfmsg->nfgen_family; int err; if (nlh->nlmsg_flags & NLM_F_DUMP) { struct netlink_dump_control c = { .dump = nf_tables_dump_tables, }; return netlink_dump_start(nlsk, skb, nlh, &c); } afi = nf_tables_afinfo_lookup(net, family, false); if (IS_ERR(afi)) return PTR_ERR(afi); table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME], genmask); if (IS_ERR(table)) return PTR_ERR(table); skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb2) return -ENOMEM; err = nf_tables_fill_table_info(skb2, net, NETLINK_CB(skb).portid, nlh->nlmsg_seq, NFT_MSG_NEWTABLE, 0, family, table); if (err < 0) goto err; return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid); err: kfree_skb(skb2); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Arturo Borrero Gonzalez15362.20%111.11%
Pablo Neira Ayuso4919.92%666.67%
Patrick McHardy4417.89%222.22%
Total246100.00%9100.00%


static void _nf_tables_table_disable(struct net *net, const struct nft_af_info *afi, struct nft_table *table, u32 cnt) { struct nft_chain *chain; u32 i = 0; list_for_each_entry(chain, &table->chains, list) { if (!nft_is_active_next(net, chain)) continue; if (!(chain->flags & NFT_BASE_CHAIN)) continue; if (cnt && i++ == cnt) break; nf_unregister_net_hooks(net, nft_base_chain(chain)->ops, afi->nops); } }

Contributors

PersonTokensPropCommitsCommitProp
Arturo Borrero Gonzalez2930.85%114.29%
Pablo Neira Ayuso2526.60%457.14%
Patrick McHardy2122.34%114.29%
Gao Feng1920.21%114.29%
Total94100.00%7100.00%


static int nf_tables_table_enable(struct net *net, const struct nft_af_info *afi