[PATCH 4/5] trace: implement commands action

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



trace.c is based upon https://git.netfilter.org/libmnl/tree/examples/netfilter/nf-log.c

---
 include/Makefile.am |   1 +
 include/trace.h     |   2 +
 src/Makefile.am     |   1 +
 src/rule.c          |   1 +
 src/trace.c         | 361 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 366 insertions(+)
 create mode 100644 include/trace.h
 create mode 100644 src/trace.c

diff --git a/include/Makefile.am b/include/Makefile.am
index f22561b..c351b55 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -19,4 +19,5 @@ noinst_HEADERS = 	cli.h		\
 			parser.h	\
 			proto.h		\
 			rule.h		\
+			trace.h		\
 			utils.h
diff --git a/include/trace.h b/include/trace.h
new file mode 100644
index 0000000..8c43c86
--- /dev/null
+++ b/include/trace.h
@@ -0,0 +1,2 @@
+int nft_trace(int qnum, int family);
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 2410fd3..db77e8e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -45,6 +45,7 @@ nft_SOURCES =	main.c				\
 		erec.c				\
 		mnl.c				\
 		scanner.l			\
+		trace.c				\
 		parser_bison.y
 
 if BUILD_CLI
diff --git a/src/rule.c b/src/rule.c
index dc65452..cd21de0 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -18,6 +18,7 @@
 
 #include <statement.h>
 #include <rule.h>
+#include <trace.h>
 #include <utils.h>
 #include <netlink.h>
 
diff --git a/src/trace.c b/src/trace.c
new file mode 100644
index 0000000..a9c9b5f
--- /dev/null
+++ b/src/trace.c
@@ -0,0 +1,361 @@
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <arpa/inet.h>
+
+#include <net/ethernet.h>
+
+#include <libmnl/libmnl.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nfnetlink.h>
+
+#ifndef aligned_be64
+#define aligned_be64 u_int64_t __attribute__((aligned(8)))
+#endif
+
+#include <linux/netfilter/nfnetlink_log.h>
+#include <libmnl/libmnl.h>
+
+#include "trace.h"
+#include "rule.h"
+#include "statement.h"
+#include "log.h"
+
+struct prefix
+{
+	char *table;
+	char *chain;
+	char *action;
+	char *num;
+};
+
+static int parse_prefix(char *prefix, struct prefix *td)
+{
+	static const char *TRACE = "TRACE: ";
+	char *pos;
+	char *cur = NULL;
+	char *end = prefix + strlen(prefix);
+	pos = prefix;
+
+	/* "TRACE: filter:input:rule:2 " */
+	if (strncmp(prefix, TRACE, strlen(TRACE)) != 0)
+		return -1;
+
+	pos += strlen(TRACE);
+
+	if (pos >= end)
+		goto invalid_format_error;
+
+	/* "filter:input:rule:2 " */
+	/* TABLE:CHAIN:ACTION:NUM */
+	if ( (cur=strchr(pos, ':')) == NULL || cur+1 >= end)
+		goto invalid_format_error;
+	*cur = '\0';
+	td->table = pos;
+	pos = cur+1;
+
+	if ( (cur=strchr(pos, ':')) == NULL || cur+1 >= end)
+		goto invalid_format_error;
+	*cur = '\0';
+	td->chain = pos;
+	pos = cur+1;
+
+	if ( (cur=strchr(pos, ':')) == NULL || cur+1 >= end)
+		goto invalid_format_error;
+	*cur = '\0';
+	td->action = pos;
+
+	td->num = cur+1;
+	return 0;
+
+invalid_format_error:
+	return -1;
+}
+
+
+static int parse_attr_cb(const struct nlattr *attr, void *data)
+{
+	const struct nlattr **tb = data;
+	int type = mnl_attr_get_type(attr);
+
+	/* skip unsupported attribute in user-space */
+	if (mnl_attr_type_valid(attr, NFULA_MAX) < 0)
+		return MNL_CB_OK;
+
+	switch(type) {
+	case NFULA_MARK:
+	case NFULA_IFINDEX_INDEV:
+	case NFULA_IFINDEX_OUTDEV:
+	case NFULA_IFINDEX_PHYSINDEV:
+	case NFULA_IFINDEX_PHYSOUTDEV:
+		if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
+			perror("mnl_attr_validate");
+			return MNL_CB_ERROR;
+		}
+		break;
+	case NFULA_TIMESTAMP:
+		if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
+		    sizeof(struct nfulnl_msg_packet_timestamp)) < 0) {
+			perror("mnl_attr_validate2");
+			return MNL_CB_ERROR;
+		}
+		break;
+	case NFULA_HWADDR:
+		if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
+		    sizeof(struct nfulnl_msg_packet_hw)) < 0) {
+			perror("mnl_attr_validate2");
+			return MNL_CB_ERROR;
+		}
+		break;
+	case NFULA_PREFIX:
+		if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) {
+			perror("mnl_attr_validate");
+			return MNL_CB_ERROR;
+		}
+		break;
+	case NFULA_PAYLOAD:
+		break;
+	}
+	tb[type] = attr;
+	return MNL_CB_OK;
+}
+
+struct log_ctx
+{
+	int family;
+};
+
+static int log_cb(const struct nlmsghdr *nlh, void *data)
+{
+	struct log_ctx *ctx = data;
+	struct nlattr *tb[NFULA_MAX+1] = {};
+	struct nfulnl_msg_packet_hdr *ph = NULL;
+	struct prefix td;
+	char prefix[65];
+
+	struct handle h;
+	struct table *table;
+	struct chain *chain;
+	struct rule *rule = NULL;
+	const struct stmt *stmt;
+	int i;
+	uint32_t mark = 0;
+
+	mnl_attr_parse(nlh, sizeof(struct nfgenmsg), parse_attr_cb, tb);
+
+	if (!tb[NFULA_PACKET_HDR])
+		return 0;
+
+	ph = mnl_attr_get_payload(tb[NFULA_PACKET_HDR]);
+
+	if (ntohs(ph->hw_protocol) == ETHERTYPE_IP && (ctx->family != NFPROTO_IPV4 && ctx->family != NFPROTO_INET))
+		return 0;
+	if (ntohs(ph->hw_protocol) == ETHERTYPE_IPV6 && (ctx->family != NFPROTO_IPV6 && ctx->family != NFPROTO_INET))
+		return 0;
+
+
+	if (tb[NFULA_PREFIX])
+		strncpy(prefix, mnl_attr_get_str(tb[NFULA_PREFIX]), sizeof(prefix)-1);
+	else
+		goto invalid_format_error;
+
+	prefix[sizeof(prefix)-1] = '\0';
+
+	if( parse_prefix(prefix, &td) != 0)
+		return 0;
+
+	if (tb[NFULA_MARK])
+		mark = ntohl(mnl_attr_get_u32(tb[NFULA_MARK]));
+
+	h.family = ctx->family;
+	h.table = td.table;
+
+	if ( (table = table_lookup(&h)) == NULL)
+		return 0;
+
+	h.chain = td.chain;
+	if ( (chain = chain_lookup(table, &h)) ==  NULL)
+		return 0;
+
+	if (strcmp(td.action, "rule") == 0) {
+		i = atoi(td.num);
+		list_for_each_entry(rule, &chain->rules, list) {
+			if (--i != 0)
+				continue;
+			break;
+		}
+		if (rule == NULL)
+			return 0;
+		list_for_each_entry(stmt, &rule->stmts, list) {
+			if (stmt->ops->type == STMT_META &&
+				stmt->meta.key == NFT_META_NFTRACE)
+			{
+				nf_log_packet(tb);
+				break;
+			}
+		}
+	}
+
+
+	if (strcmp(td.action, "policy") == 0) {
+		char *policies[NF_MAX_VERDICT] = {
+			[NF_DROP] = "DROP",
+			[NF_ACCEPT] = "ACCEPT",
+			[NF_QUEUE] = "QUEUE",
+		};
+		printf("\t%s %s NFMARK=0x%x\n", td.table, td.chain, mark);
+		printf("\t\t%s\n", policies[chain->policy]);
+	} else
+	if (strcmp(td.action, "rule") == 0) {
+		printf("\t%s %s (#%i) NFMARK=0x%x\n", td.table, td.chain, atoi(td.num), mark);
+		printf("\t\t");
+		rule_print(rule);
+		printf("\n");
+	} else
+	if (strcmp(td.action, "return") == 0) {
+		printf("\t%s %s NFMARK=0x%x\n", td.table, td.chain, mark);
+		printf("\t\t => RETURN\n");
+	}
+
+invalid_format_error:
+	return MNL_CB_OK;
+}
+
+static struct nlmsghdr *
+nflog_build_cfg_pf_request(char *buf, uint8_t command)
+{
+	struct nlmsghdr *nlh;
+	struct nfgenmsg *nfg;
+	struct nfulnl_msg_config_cmd cmd;
+
+	nlh = mnl_nlmsg_put_header(buf);
+	nlh->nlmsg_type	= (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
+	nlh->nlmsg_flags = NLM_F_REQUEST;
+
+	nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+	nfg->nfgen_family = AF_INET;
+	nfg->version = NFNETLINK_V0;
+
+	cmd.command = command,
+
+	mnl_attr_put(nlh, NFULA_CFG_CMD, sizeof(cmd), &cmd);
+
+	return nlh;
+}
+
+static struct nlmsghdr *
+nflog_build_cfg_request(char *buf, uint8_t command, int qnum)
+{
+	struct nlmsghdr *nlh;
+	struct nfgenmsg *nfg;
+	struct nfulnl_msg_config_cmd cmd;
+
+	nlh = mnl_nlmsg_put_header(buf);
+	nlh->nlmsg_type	= (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
+	nlh->nlmsg_flags = NLM_F_REQUEST;
+
+	nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+	nfg->nfgen_family = AF_INET;
+	nfg->version = NFNETLINK_V0;
+	nfg->res_id = htons(qnum);
+
+	cmd.command = command,
+
+	mnl_attr_put(nlh, NFULA_CFG_CMD, sizeof(cmd), &cmd);
+
+	return nlh;
+}
+
+static struct nlmsghdr *
+nflog_build_cfg_params(char *buf, uint8_t mode, int range, int qnum)
+{
+	struct nlmsghdr *nlh;
+	struct nfgenmsg *nfg;
+	struct nfulnl_msg_config_mode params;
+
+	nlh = mnl_nlmsg_put_header(buf);
+	nlh->nlmsg_type	= (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
+	nlh->nlmsg_flags = NLM_F_REQUEST;
+
+	nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+	nfg->nfgen_family = AF_UNSPEC;
+	nfg->version = NFNETLINK_V0;
+	nfg->res_id = htons(qnum);
+
+	params.copy_range = htonl(range);
+	params.copy_mode = mode;
+
+	mnl_attr_put(nlh, NFULA_CFG_MODE, sizeof(params), &params);
+
+	return nlh;
+}
+
+int nft_trace(int qnum, int family)
+{
+	struct mnl_socket *nl;
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+	int ret;
+	int portid;
+	struct log_ctx lctx = { .family = family };
+
+	nl = mnl_socket_open(NETLINK_NETFILTER);
+	if (nl == NULL)
+		return -1;
+
+	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
+		goto failed;
+
+	portid = mnl_socket_get_portid(nl);
+
+	nlh = nflog_build_cfg_pf_request(buf, NFULNL_CFG_CMD_PF_UNBIND);
+
+	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
+		goto failed;
+
+	nlh = nflog_build_cfg_pf_request(buf, NFULNL_CFG_CMD_PF_BIND);
+
+	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
+		goto failed;
+
+	nlh = nflog_build_cfg_request(buf, NFULNL_CFG_CMD_BIND, qnum);
+
+	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
+		goto failed;
+
+	nlh = nflog_build_cfg_params(buf, NFULNL_COPY_PACKET, 0xFFFF, qnum);
+
+	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
+		goto failed;
+
+	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+	if (ret == -1)
+		goto failed;
+
+	while (ret > 0) {
+		ret = mnl_cb_run(buf, ret, 0, portid, log_cb, &lctx);
+		if (ret < 0){
+			perror("mnl_cb_run");
+			exit(EXIT_FAILURE);
+		}
+
+		ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+		if (ret == -1) {
+			perror("mnl_socket_recvfrom");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	mnl_socket_close(nl);
+
+	return 0;
+
+
+failed:
+	mnl_socket_close(nl);
+	return -1;
+}
+
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux