Patchwork [02/11] netfilter: xtables2: initial Netlink interface

login
register
mail settings
Submitter Jan Engelhardt
Date Nov. 2, 2012, 3:38 a.m.
Message ID <1351827523-10629-3-git-send-email-jengelh@inai.de>
Download mbox | patch
Permalink /patch/196477/
State Not Applicable
Headers show

Comments

Jan Engelhardt - Nov. 2, 2012, 3:38 a.m.
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

Patch

diff --git a/include/uapi/linux/netfilter/Kbuild b/include/uapi/linux/netfilter/Kbuild
index 08f555f..edd789c 100644
--- a/include/uapi/linux/netfilter/Kbuild
+++ b/include/uapi/linux/netfilter/Kbuild
@@ -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
diff --git a/include/uapi/linux/netfilter/nfnetlink.h b/include/uapi/linux/netfilter/nfnetlink.h
index 4a4efaf..d5c3f68 100644
--- a/include/uapi/linux/netfilter/nfnetlink.h
+++ b/include/uapi/linux/netfilter/nfnetlink.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 */
diff --git a/include/uapi/linux/netfilter/nfnetlink_xtables.h b/include/uapi/linux/netfilter/nfnetlink_xtables.h
new file mode 100644
index 0000000..a548394
--- /dev/null
+++ b/include/uapi/linux/netfilter/nfnetlink_xtables.h
@@ -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 */
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 00eab5c..cf716f4 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -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
diff --git a/net/netfilter/xt_core.c b/net/netfilter/xt_core.c
index 89dd0a0..24c418b 100644
--- a/net/netfilter/xt_core.c
+++ b/net/netfilter/xt_core.c
@@ -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);
 }
 
diff --git a/net/netfilter/xt_nfnetlink.c b/net/netfilter/xt_nfnetlink.c
new file mode 100644
index 0000000..8a58bb8
--- /dev/null
+++ b/net/netfilter/xt_nfnetlink.c
@@ -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);
diff --git a/net/netfilter/xt_nfnetlink.h b/net/netfilter/xt_nfnetlink.h
new file mode 100644
index 0000000..f8ed87f
--- /dev/null
+++ b/net/netfilter/xt_nfnetlink.h
@@ -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 */