@@ -14,6 +14,7 @@ header-y += nfnetlink_cthelper.h
header-y += nfnetlink_cttimeout.h
header-y += nfnetlink_log.h
header-y += nfnetlink_queue.h
+header-y += nfnetlink_xtables.h
header-y += x_tables.h
header-y += xt_AUDIT.h
header-y += xt_CHECKSUM.h
@@ -51,6 +51,7 @@ struct nfgenmsg {
#define NFNL_SUBSYS_ACCT 7
#define NFNL_SUBSYS_CTNETLINK_TIMEOUT 8
#define NFNL_SUBSYS_CTHELPER 9
-#define NFNL_SUBSYS_COUNT 10
+#define NFNL_SUBSYS_XTABLES 10
+#define NFNL_SUBSYS_COUNT 11
#endif /* _UAPI_NFNETLINK_H */
new file mode 100644
@@ -0,0 +1,27 @@
+#ifndef _LINUX_NFNETLINK_XTABLES_H
+#define _LINUX_NFNETLINK_XTABLES_H 1
+
+/**
+ * %NFXTM_IDENTIFY: multifunction debug command to inquire about xt2
+ * properties (e.g. match size)
+ */
+enum nfxt_msg_type {
+ NFXTM_IDENTIFY = 1,
+};
+
+/**
+ * %NFXTA_NAME: name of the object being operated on
+ */
+enum nfxt_attr_type {
+ NFXTA_UNSPEC = 0,
+ NFXTA_NAME,
+};
+
+/**
+ * %NFXTE_SUCCESS: the operation completed successfully
+ */
+enum nfxt_errno {
+ NFXTE_SUCCESS = 0,
+};
+
+#endif /* _LINUX_NFNETLINK_XTABLES_H */
@@ -65,7 +65,8 @@ obj-$(CONFIG_NETFILTER_TPROXY) += nf_tproxy_core.o
# generic X tables
obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
-obj-$(CONFIG_NETFILTER_XTABLES2) += xt_core.o
+obj-$(CONFIG_NETFILTER_XTABLES2) += xtables2.o
+xtables2-y := xt_core.o xt_nfnetlink.o
# combos
obj-$(CONFIG_NETFILTER_XT_MARK) += xt_mark.o
@@ -15,6 +15,7 @@
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/netfilter/xt_core.h>
+#include "xt_nfnetlink.h"
MODULE_DESCRIPTION("Netfilter Xtables2 packet filtering");
MODULE_AUTHOR("Jan Engelhardt");
@@ -72,12 +73,23 @@ static struct pernet_operations xtables2_pernet_ops = {
static int __init xtables2_init(void)
{
+ int ret;
+
pr_info("Xtables2, (C) 2009-2012, J.Engelhardt\n");
- return register_pernet_subsys(&xtables2_pernet_ops);
+ ret = register_pernet_subsys(&xtables2_pernet_ops);
+ if (ret < 0)
+ return ret;
+ ret = xtnetlink_init();
+ if (ret < 0) {
+ unregister_pernet_subsys(&xtables2_pernet_ops);
+ return ret;
+ }
+ return 0;
}
static void __exit xtables2_exit(void)
{
+ xtnetlink_exit();
unregister_pernet_subsys(&xtables2_pernet_ops);
}
new file mode 100644
@@ -0,0 +1,156 @@
+/*
+ * Xtables2 nfnetlink interface
+ * Copyright © Jan Engelhardt, 2010-2012
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netlink.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_xtables.h>
+#include <net/netlink.h>
+#include <net/netfilter/xt_core.h>
+#include "xt_nfnetlink.h"
+
+#define MAKE_TAGGED_TYPE(x) ((x) | (NFNL_SUBSYS_XTABLES << 8))
+
+/**
+ * Something to keep all the pointers that NL gives us in one place.
+ * You need quite a lot of variables to construct and send out a packet...
+ */
+struct xtnetlink_pktref {
+ union {
+ struct sk_buff *skb;
+ const struct sk_buff *c_skb;
+ };
+ union {
+ struct nlmsghdr *msg;
+ const struct nlmsghdr *c_msg;
+ };
+ struct sock *sock;
+};
+
+/**
+ * @skb: outgoing skb
+ * @old: pointers to the original incoming skb/nl headers
+ * @flags: extra flags to set in nlmsg
+ *
+ * Fill an skb (for outgoing direction) with NL and NFNL headers, using data
+ * from the original skb for initialization.
+ */
+static struct nlmsghdr *
+xtnetlink_fill(struct sk_buff *skb, const struct xtnetlink_pktref *old,
+ unsigned int flags)
+{
+ uint16_t type = NFNL_MSG_TYPE(old->msg->nlmsg_type);
+ struct nlmsghdr *nlmsg;
+ struct nfgenmsg *hdr;
+
+ nlmsg = nlmsg_put(skb, NETLINK_CB(old->skb).portid,
+ old->msg->nlmsg_seq, MAKE_TAGGED_TYPE(type),
+ sizeof(*hdr), flags);
+ if (nlmsg == NULL) {
+ nlmsg_cancel(skb, nlmsg);
+ return ERR_PTR(-ENOBUFS);
+ }
+
+ hdr = nlmsg_data(nlmsg);
+ hdr->nfgen_family = NFPROTO_UNSPEC;
+ hdr->version = NFNETLINK_V0;
+ hdr->res_id = 0;
+ return nlmsg;
+}
+
+/**
+ * Ran too often into NULL derefs. Now there is a dummy function for unused
+ * message type 0.
+ */
+static int
+xtnetlink_ignore(struct sock *k, struct sk_buff *s,
+ const struct nlmsghdr *n, const struct nlattr *const *a)
+{
+ return -ENXIO;
+}
+
+/**
+ * Respond to a %NFXTM_IDENTIFY inquiry. Reports the Xtables2 version (for
+ * now), and in future the extension info.
+ */
+static int
+xtnetlink_identify2(struct sk_buff *skb, struct netlink_callback *nl_cb)
+{
+ struct xtnetlink_pktref ref = {.c_skb = skb, .c_msg = nl_cb->nlh};
+ struct nlmsghdr *nlmsg = NULL;
+
+ switch (nl_cb->args[0]) {
+ case 0:
+ nlmsg = xtnetlink_fill(skb, &ref, NLM_F_MULTI);
+ if (IS_ERR(nlmsg))
+ return 0;
+ if (nla_put_string(skb, NFXTA_NAME, "Xtables2-xtnl/nfnl") != 0)
+ goto nla_put_failure;
+ ++nl_cb->args[0];
+ break;
+ }
+ if (nlmsg != NULL)
+ nlmsg_end(skb, nlmsg);
+ return skb->len;
+ nla_put_failure:
+ return 0;
+}
+
+static int
+xtnetlink_identify(struct sock *xtnl, struct sk_buff *iskb,
+ const struct nlmsghdr *imsg, const struct nlattr *const *ad)
+{
+ static struct netlink_dump_control ctl __read_mostly = {
+ .dump = xtnetlink_identify2,
+ .module = THIS_MODULE,
+ };
+ return netlink_dump_start(xtnl, iskb, imsg, &ctl);
+}
+
+static const struct nla_policy xtnetlink_policy[] = {
+ [NFXTA_NAME] = {.type = NLA_NUL_STRING},
+};
+
+/*
+ * Use the same policy for all messages. I do not want to see EINVAL anytime
+ * soon again just because I forgot sending an attribute from userspace.
+ * (If such occurs, it will be dealt with %NFXTE_ATTRSET_INCOMPLETE, tbd.)
+ */
+#define pol \
+ .policy = xtnetlink_policy, \
+ .attr_count = ARRAY_SIZE(xtnetlink_policy)
+static const struct nfnl_callback xtnetlink_callback[] = {
+ [0] = {.call = xtnetlink_ignore},
+ [NFXTM_IDENTIFY] = {.call = xtnetlink_identify, pol},
+};
+#undef pol
+
+static const struct nfnetlink_subsystem xtnetlink_subsys = {
+ .name = "xtables",
+ .subsys_id = NFNL_SUBSYS_XTABLES,
+ .cb = xtnetlink_callback,
+ .cb_count = ARRAY_SIZE(xtnetlink_callback),
+};
+
+int __init xtnetlink_init(void)
+{
+ return nfnetlink_subsys_register(&xtnetlink_subsys);
+}
+
+void __exit xtnetlink_exit(void)
+{
+ nfnetlink_subsys_unregister(&xtnetlink_subsys);
+}
+
+MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_XTABLES);
new file mode 100644
@@ -0,0 +1,7 @@
+#ifndef XT_NFNETLINK_H
+#define XT_NFNETLINK_H 1
+
+extern int xtnetlink_init(void);
+extern void xtnetlink_exit(void);
+
+#endif /* XT_NFNETLINK_H */
This populates xt_nfnetlink.c with support for NFXTM_IDENTIFY. Right now that just returns a freeform string but eventually shall dump all the match and target modules' info. Signed-off-by: Jan Engelhardt <jengelh@inai.de> --- include/uapi/linux/netfilter/Kbuild | 1 + include/uapi/linux/netfilter/nfnetlink.h | 3 +- include/uapi/linux/netfilter/nfnetlink_xtables.h | 27 ++++ net/netfilter/Makefile | 3 +- net/netfilter/xt_core.c | 14 +- net/netfilter/xt_nfnetlink.c | 156 ++++++++++++++++++++++ net/netfilter/xt_nfnetlink.h | 7 + 7 files changed, 208 insertions(+), 3 deletions(-) create mode 100644 include/uapi/linux/netfilter/nfnetlink_xtables.h create mode 100644 net/netfilter/xt_nfnetlink.c create mode 100644 net/netfilter/xt_nfnetlink.h