0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/kallsyms.h>
0010 #include <linux/kernel.h>
0011 #include <linux/types.h>
0012 #include <linux/skbuff.h>
0013 #include <linux/errno.h>
0014 #include <linux/netlink.h>
0015 #include <linux/slab.h>
0016
0017 #include <linux/netfilter.h>
0018
0019 #include <linux/netfilter/nfnetlink.h>
0020 #include <linux/netfilter/nfnetlink_hook.h>
0021
0022 #include <net/netfilter/nf_tables.h>
0023 #include <net/sock.h>
0024
0025 static const struct nla_policy nfnl_hook_nla_policy[NFNLA_HOOK_MAX + 1] = {
0026 [NFNLA_HOOK_HOOKNUM] = { .type = NLA_U32 },
0027 [NFNLA_HOOK_PRIORITY] = { .type = NLA_U32 },
0028 [NFNLA_HOOK_DEV] = { .type = NLA_STRING,
0029 .len = IFNAMSIZ - 1 },
0030 [NFNLA_HOOK_FUNCTION_NAME] = { .type = NLA_NUL_STRING,
0031 .len = KSYM_NAME_LEN, },
0032 [NFNLA_HOOK_MODULE_NAME] = { .type = NLA_NUL_STRING,
0033 .len = MODULE_NAME_LEN, },
0034 [NFNLA_HOOK_CHAIN_INFO] = { .type = NLA_NESTED, },
0035 };
0036
0037 static int nf_netlink_dump_start_rcu(struct sock *nlsk, struct sk_buff *skb,
0038 const struct nlmsghdr *nlh,
0039 struct netlink_dump_control *c)
0040 {
0041 int err;
0042
0043 if (!try_module_get(THIS_MODULE))
0044 return -EINVAL;
0045
0046 rcu_read_unlock();
0047 err = netlink_dump_start(nlsk, skb, nlh, c);
0048 rcu_read_lock();
0049 module_put(THIS_MODULE);
0050
0051 return err;
0052 }
0053
0054 struct nfnl_dump_hook_data {
0055 char devname[IFNAMSIZ];
0056 unsigned long headv;
0057 u8 hook;
0058 };
0059
0060 static int nfnl_hook_put_nft_chain_info(struct sk_buff *nlskb,
0061 const struct nfnl_dump_hook_data *ctx,
0062 unsigned int seq,
0063 const struct nf_hook_ops *ops)
0064 {
0065 struct net *net = sock_net(nlskb->sk);
0066 struct nlattr *nest, *nest2;
0067 struct nft_chain *chain;
0068 int ret = 0;
0069
0070 if (ops->hook_ops_type != NF_HOOK_OP_NF_TABLES)
0071 return 0;
0072
0073 chain = ops->priv;
0074 if (WARN_ON_ONCE(!chain))
0075 return 0;
0076
0077 if (!nft_is_active(net, chain))
0078 return 0;
0079
0080 nest = nla_nest_start(nlskb, NFNLA_HOOK_CHAIN_INFO);
0081 if (!nest)
0082 return -EMSGSIZE;
0083
0084 ret = nla_put_be32(nlskb, NFNLA_HOOK_INFO_TYPE,
0085 htonl(NFNL_HOOK_TYPE_NFTABLES));
0086 if (ret)
0087 goto cancel_nest;
0088
0089 nest2 = nla_nest_start(nlskb, NFNLA_HOOK_INFO_DESC);
0090 if (!nest2)
0091 goto cancel_nest;
0092
0093 ret = nla_put_string(nlskb, NFNLA_CHAIN_TABLE, chain->table->name);
0094 if (ret)
0095 goto cancel_nest;
0096
0097 ret = nla_put_string(nlskb, NFNLA_CHAIN_NAME, chain->name);
0098 if (ret)
0099 goto cancel_nest;
0100
0101 ret = nla_put_u8(nlskb, NFNLA_CHAIN_FAMILY, chain->table->family);
0102 if (ret)
0103 goto cancel_nest;
0104
0105 nla_nest_end(nlskb, nest2);
0106 nla_nest_end(nlskb, nest);
0107 return ret;
0108
0109 cancel_nest:
0110 nla_nest_cancel(nlskb, nest);
0111 return -EMSGSIZE;
0112 }
0113
0114 static int nfnl_hook_dump_one(struct sk_buff *nlskb,
0115 const struct nfnl_dump_hook_data *ctx,
0116 const struct nf_hook_ops *ops,
0117 int family, unsigned int seq)
0118 {
0119 u16 event = nfnl_msg_type(NFNL_SUBSYS_HOOK, NFNL_MSG_HOOK_GET);
0120 unsigned int portid = NETLINK_CB(nlskb).portid;
0121 struct nlmsghdr *nlh;
0122 int ret = -EMSGSIZE;
0123 u32 hooknum;
0124 #ifdef CONFIG_KALLSYMS
0125 char sym[KSYM_SYMBOL_LEN];
0126 char *module_name;
0127 #endif
0128 nlh = nfnl_msg_put(nlskb, portid, seq, event,
0129 NLM_F_MULTI, family, NFNETLINK_V0, 0);
0130 if (!nlh)
0131 goto nla_put_failure;
0132
0133 #ifdef CONFIG_KALLSYMS
0134 ret = snprintf(sym, sizeof(sym), "%ps", ops->hook);
0135 if (ret >= sizeof(sym)) {
0136 ret = -EINVAL;
0137 goto nla_put_failure;
0138 }
0139
0140 module_name = strstr(sym, " [");
0141 if (module_name) {
0142 char *end;
0143
0144 *module_name = '\0';
0145 module_name += 2;
0146 end = strchr(module_name, ']');
0147 if (end) {
0148 *end = 0;
0149
0150 ret = nla_put_string(nlskb, NFNLA_HOOK_MODULE_NAME, module_name);
0151 if (ret)
0152 goto nla_put_failure;
0153 }
0154 }
0155
0156 ret = nla_put_string(nlskb, NFNLA_HOOK_FUNCTION_NAME, sym);
0157 if (ret)
0158 goto nla_put_failure;
0159 #endif
0160
0161 if (ops->pf == NFPROTO_INET && ops->hooknum == NF_INET_INGRESS)
0162 hooknum = NF_NETDEV_INGRESS;
0163 else
0164 hooknum = ops->hooknum;
0165
0166 ret = nla_put_be32(nlskb, NFNLA_HOOK_HOOKNUM, htonl(hooknum));
0167 if (ret)
0168 goto nla_put_failure;
0169
0170 ret = nla_put_be32(nlskb, NFNLA_HOOK_PRIORITY, htonl(ops->priority));
0171 if (ret)
0172 goto nla_put_failure;
0173
0174 ret = nfnl_hook_put_nft_chain_info(nlskb, ctx, seq, ops);
0175 if (ret)
0176 goto nla_put_failure;
0177
0178 nlmsg_end(nlskb, nlh);
0179 return 0;
0180 nla_put_failure:
0181 nlmsg_trim(nlskb, nlh);
0182 return ret;
0183 }
0184
0185 static const struct nf_hook_entries *
0186 nfnl_hook_entries_head(u8 pf, unsigned int hook, struct net *net, const char *dev)
0187 {
0188 const struct nf_hook_entries *hook_head = NULL;
0189 #if defined(CONFIG_NETFILTER_INGRESS) || defined(CONFIG_NETFILTER_EGRESS)
0190 struct net_device *netdev;
0191 #endif
0192
0193 switch (pf) {
0194 case NFPROTO_IPV4:
0195 if (hook >= ARRAY_SIZE(net->nf.hooks_ipv4))
0196 return ERR_PTR(-EINVAL);
0197 hook_head = rcu_dereference(net->nf.hooks_ipv4[hook]);
0198 break;
0199 case NFPROTO_IPV6:
0200 if (hook >= ARRAY_SIZE(net->nf.hooks_ipv6))
0201 return ERR_PTR(-EINVAL);
0202 hook_head = rcu_dereference(net->nf.hooks_ipv6[hook]);
0203 break;
0204 case NFPROTO_ARP:
0205 #ifdef CONFIG_NETFILTER_FAMILY_ARP
0206 if (hook >= ARRAY_SIZE(net->nf.hooks_arp))
0207 return ERR_PTR(-EINVAL);
0208 hook_head = rcu_dereference(net->nf.hooks_arp[hook]);
0209 #endif
0210 break;
0211 case NFPROTO_BRIDGE:
0212 #ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
0213 if (hook >= ARRAY_SIZE(net->nf.hooks_bridge))
0214 return ERR_PTR(-EINVAL);
0215 hook_head = rcu_dereference(net->nf.hooks_bridge[hook]);
0216 #endif
0217 break;
0218 #if IS_ENABLED(CONFIG_DECNET)
0219 case NFPROTO_DECNET:
0220 if (hook >= ARRAY_SIZE(net->nf.hooks_decnet))
0221 return ERR_PTR(-EINVAL);
0222 hook_head = rcu_dereference(net->nf.hooks_decnet[hook]);
0223 break;
0224 #endif
0225 #if defined(CONFIG_NETFILTER_INGRESS) || defined(CONFIG_NETFILTER_EGRESS)
0226 case NFPROTO_NETDEV:
0227 if (hook >= NF_NETDEV_NUMHOOKS)
0228 return ERR_PTR(-EOPNOTSUPP);
0229
0230 if (!dev)
0231 return ERR_PTR(-ENODEV);
0232
0233 netdev = dev_get_by_name_rcu(net, dev);
0234 if (!netdev)
0235 return ERR_PTR(-ENODEV);
0236
0237 #ifdef CONFIG_NETFILTER_INGRESS
0238 if (hook == NF_NETDEV_INGRESS)
0239 return rcu_dereference(netdev->nf_hooks_ingress);
0240 #endif
0241 #ifdef CONFIG_NETFILTER_EGRESS
0242 if (hook == NF_NETDEV_EGRESS)
0243 return rcu_dereference(netdev->nf_hooks_egress);
0244 #endif
0245 fallthrough;
0246 #endif
0247 default:
0248 return ERR_PTR(-EPROTONOSUPPORT);
0249 }
0250
0251 return hook_head;
0252 }
0253
0254 static int nfnl_hook_dump(struct sk_buff *nlskb,
0255 struct netlink_callback *cb)
0256 {
0257 struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
0258 struct nfnl_dump_hook_data *ctx = cb->data;
0259 int err, family = nfmsg->nfgen_family;
0260 struct net *net = sock_net(nlskb->sk);
0261 struct nf_hook_ops * const *ops;
0262 const struct nf_hook_entries *e;
0263 unsigned int i = cb->args[0];
0264
0265 rcu_read_lock();
0266
0267 e = nfnl_hook_entries_head(family, ctx->hook, net, ctx->devname);
0268 if (!e)
0269 goto done;
0270
0271 if (IS_ERR(e)) {
0272 cb->seq++;
0273 goto done;
0274 }
0275
0276 if ((unsigned long)e != ctx->headv || i >= e->num_hook_entries)
0277 cb->seq++;
0278
0279 ops = nf_hook_entries_get_hook_ops(e);
0280
0281 for (; i < e->num_hook_entries; i++) {
0282 err = nfnl_hook_dump_one(nlskb, ctx, ops[i], family,
0283 cb->nlh->nlmsg_seq);
0284 if (err)
0285 break;
0286 }
0287
0288 done:
0289 nl_dump_check_consistent(cb, nlmsg_hdr(nlskb));
0290 rcu_read_unlock();
0291 cb->args[0] = i;
0292 return nlskb->len;
0293 }
0294
0295 static int nfnl_hook_dump_start(struct netlink_callback *cb)
0296 {
0297 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
0298 const struct nlattr * const *nla = cb->data;
0299 struct nfnl_dump_hook_data *ctx = NULL;
0300 struct net *net = sock_net(cb->skb->sk);
0301 u8 family = nfmsg->nfgen_family;
0302 char name[IFNAMSIZ] = "";
0303 const void *head;
0304 u32 hooknum;
0305
0306 hooknum = ntohl(nla_get_be32(nla[NFNLA_HOOK_HOOKNUM]));
0307 if (hooknum > 255)
0308 return -EINVAL;
0309
0310 if (family == NFPROTO_NETDEV) {
0311 if (!nla[NFNLA_HOOK_DEV])
0312 return -EINVAL;
0313
0314 nla_strscpy(name, nla[NFNLA_HOOK_DEV], sizeof(name));
0315 }
0316
0317 rcu_read_lock();
0318
0319 head = nfnl_hook_entries_head(family, hooknum, net, name);
0320 rcu_read_unlock();
0321
0322 if (head && IS_ERR(head))
0323 return PTR_ERR(head);
0324
0325 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
0326 if (!ctx)
0327 return -ENOMEM;
0328
0329 strscpy(ctx->devname, name, sizeof(ctx->devname));
0330 ctx->headv = (unsigned long)head;
0331 ctx->hook = hooknum;
0332
0333 cb->seq = 1;
0334 cb->data = ctx;
0335
0336 return 0;
0337 }
0338
0339 static int nfnl_hook_dump_stop(struct netlink_callback *cb)
0340 {
0341 kfree(cb->data);
0342 return 0;
0343 }
0344
0345 static int nfnl_hook_get(struct sk_buff *skb,
0346 const struct nfnl_info *info,
0347 const struct nlattr * const nla[])
0348 {
0349 if (!nla[NFNLA_HOOK_HOOKNUM])
0350 return -EINVAL;
0351
0352 if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
0353 struct netlink_dump_control c = {
0354 .start = nfnl_hook_dump_start,
0355 .done = nfnl_hook_dump_stop,
0356 .dump = nfnl_hook_dump,
0357 .module = THIS_MODULE,
0358 .data = (void *)nla,
0359 };
0360
0361 return nf_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c);
0362 }
0363
0364 return -EOPNOTSUPP;
0365 }
0366
0367 static const struct nfnl_callback nfnl_hook_cb[NFNL_MSG_HOOK_MAX] = {
0368 [NFNL_MSG_HOOK_GET] = {
0369 .call = nfnl_hook_get,
0370 .type = NFNL_CB_RCU,
0371 .attr_count = NFNLA_HOOK_MAX,
0372 .policy = nfnl_hook_nla_policy
0373 },
0374 };
0375
0376 static const struct nfnetlink_subsystem nfhook_subsys = {
0377 .name = "nfhook",
0378 .subsys_id = NFNL_SUBSYS_HOOK,
0379 .cb_count = NFNL_MSG_HOOK_MAX,
0380 .cb = nfnl_hook_cb,
0381 };
0382
0383 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_HOOK);
0384
0385 static int __init nfnetlink_hook_init(void)
0386 {
0387 return nfnetlink_subsys_register(&nfhook_subsys);
0388 }
0389
0390 static void __exit nfnetlink_hook_exit(void)
0391 {
0392 nfnetlink_subsys_unregister(&nfhook_subsys);
0393 }
0394
0395 module_init(nfnetlink_hook_init);
0396 module_exit(nfnetlink_hook_exit);
0397
0398 MODULE_LICENSE("GPL");
0399 MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
0400 MODULE_DESCRIPTION("nfnetlink_hook: list registered netfilter hooks");