diff mbox

[lnf-log,RFC,2/2] utils: take a example from libmnl and use nflog_nlmsg_parse

Message ID 20150810081752.GD25169@gmail.com
State RFC
Delegated to: Pablo Neira
Headers show

Commit Message

Ken-ichirou MATSUZAWA Aug. 10, 2015, 8:17 a.m. UTC
Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
 utils/Makefile.am |   6 +-
 utils/nf-log.c    | 178 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 183 insertions(+), 1 deletion(-)
 create mode 100644 utils/nf-log.c

Comments

Pablo Neira Ayuso Aug. 18, 2015, 6:04 a.m. UTC | #1
This code can be generalized a bit so you can place it in
src/nlmsg.c, see below.

On Mon, Aug 10, 2015 at 05:17:53PM +0900, Ken-ichirou MATSUZAWA wrote:
[...]
> +static struct nlmsghdr *
> +nflog_build_cfg_pf_request(char *buf, uint8_t command)
> +{
> +	struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
> +	nlh->nlmsg_type	= (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
> +	nlh->nlmsg_flags = NLM_F_REQUEST;
> +
> +	struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
> +	nfg->nfgen_family = AF_INET;
> +	nfg->version = NFNETLINK_V0;
> +
> +	struct nfulnl_msg_config_cmd cmd = {
> +		.command = command,
> +	};
> +	mnl_attr_put(nlh, NFULA_CFG_CMD, sizeof(cmd), &cmd);
> +
> +	return nlh;
> +}

I suggest you use and implement the following new helper functions for
libnetfilter_log:

struct nlmsghdr *
nfnl_nlmsg_put_header(char *buf, uint8_t type, uint8_t cmd, uint16_t qnum);

int nfnl_attr_put_cfg_mode(struct nlmsghdr *nlh, struct nfulnl_msg_config_mode *mode);
int nfnl_attr_put_cfg_cmd(struct nlmsghdr *nlh, struct nfulnl_msg_config_cmd *cmd);

You can reuse code in the functions here below to make it. Thanks.

> +static struct nlmsghdr *
> +nflog_build_cfg_request(char *buf, uint8_t command, int qnum)
> +{
> +	struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
> +	nlh->nlmsg_type	= (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
> +	nlh->nlmsg_flags = NLM_F_REQUEST;
> +
> +	struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
> +	nfg->nfgen_family = AF_INET;
> +	nfg->version = NFNETLINK_V0;
> +	nfg->res_id = htons(qnum);
> +
> +	struct nfulnl_msg_config_cmd 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 = mnl_nlmsg_put_header(buf);
> +	nlh->nlmsg_type	= (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
> +	nlh->nlmsg_flags = NLM_F_REQUEST;
> +
> +	struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
> +	nfg->nfgen_family = AF_UNSPEC;
> +	nfg->version = NFNETLINK_V0;
> +	nfg->res_id = htons(qnum);
> +
> +	struct nfulnl_msg_config_mode params = {
> +		.copy_range = htonl(range),
> +		.copy_mode = mode,
> +	};
> +	mnl_attr_put(nlh, NFULA_CFG_MODE, sizeof(params), &params);
> +
> +	return nlh;
> +}
> +
[...]
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ken-ichirou MATSUZAWA Aug. 19, 2015, 7:11 a.m. UTC | #2
Thank you for comment.

On Tue, Aug 18, 2015 at 08:04:22AM +0200, Pablo Neira Ayuso wrote:
> I suggest you use and implement the following new helper functions for
> libnetfilter_log:
> 
> struct nlmsghdr *
> nfnl_nlmsg_put_header(char *buf, uint8_t type, uint8_t cmd, uint16_t qnum);
> 
> int nfnl_attr_put_cfg_mode(struct nlmsghdr *nlh, struct nfulnl_msg_config_mode *mode);
> int nfnl_attr_put_cfg_cmd(struct nlmsghdr *nlh, struct nfulnl_msg_config_cmd *cmd);

Would you confirm the functions for nlmsg building which you suggested
to add because it's a little different from you suggested. I am worried
about it's in accodance with your intention.

In addition, I added NFLOG_DATA_SIZE as is, the size of struct
nflog_data. This enables to preallocate buffer, and I added
functions which initialize a buffer based on this.

Would you see it again?

Changes from previous:
  * introduce nlmsg three build functions:
    struct nlmsghdr *
      nfnl_nlmsg_put_header(char *buf, uint8_t type, uint8_t family, uint16_t qnum);
    int nfnl_attr_put_cfg_mode(struct nlmsghdr *nlh, struct nfulnl_msg_config_mode *mode);
    int nfnl_attr_put_cfg_cmd(struct nlmsghdr *nlh, struct nfulnl_msg_config_cmd *cmd);
    
  * introduce NFLOG_DATA_SIZE macro and use it at allocate functions.
  * update utils/nf-log to fit with the above.
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Pablo Neira Ayuso Aug. 19, 2015, 10:04 p.m. UTC | #3
On Wed, Aug 19, 2015 at 04:11:03PM +0900, Ken-ichirou MATSUZAWA wrote:
[...]
> Would you confirm the functions for nlmsg building which you suggested
> to add because it's a little different from you suggested. I am worried
> about it's in accodance with your intention.

I suggest you remove the nflog_data_init(), nflog_data_alloc(),
nflog_data_free() and nflog_nlmsg_parse().

Those are part of the old API, we should focus on API that we can
combine with libmnl.

More comments below:

> In addition, I added NFLOG_DATA_SIZE as is, the size of struct
> nflog_data. This enables to preallocate buffer, and I added
> functions which initialize a buffer based on this.
> 
> Would you see it again?
> 
> Changes from previous:
>   * introduce nlmsg three build functions:
>     struct nlmsghdr *
>       nfnl_nlmsg_put_header(char *buf, uint8_t type, uint8_t family, uint16_t qnum);
>     int nfnl_attr_put_cfg_mode(struct nlmsghdr *nlh, struct nfulnl_msg_config_mode *mode);
>     int nfnl_attr_put_cfg_cmd(struct nlmsghdr *nlh, struct nfulnl_msg_config_cmd *cmd);

One small change more, please change this interface from:

+       nfcmd.command = NFULNL_CFG_CMD_PF_UNBIND;
+       if (nfnl_attr_put_cfg_cmd(nlh, &nfcmd) < 0) {

to:

        if (nfnl_attr_put_cfg_cmd(nlh, NFULNL_CFG_CMD_PF_UNBIND) < 0) {

Same thing with nfnl_attr_put_cfg_mode(), replace this:

+       nfmode.copy_mode = NFULNL_COPY_PACKET;
+       nfmode.copy_range = 0xFFFF;
+       if (nfnl_attr_put_cfg_mode(nlh, &nfmode) < 0) {

to:
        if (nfnl_attr_put_cfg_mode(nlh, NFULNL_COPY_PACKET, 0xffff)

>   * introduce NFLOG_DATA_SIZE macro and use it at allocate functions.

You can remove NFLOG_DATA_SIZE, this is only needed by the old API,
not for libmnl.

>   * update utils/nf-log to fit with the above.

Thanks a lot!
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ken-ichirou MATSUZAWA Aug. 20, 2015, 7:26 a.m. UTC | #4
Thank you for the reply.

On Thu, Aug 20, 2015 at 12:04:03AM +0200, Pablo Neira Ayuso wrote:
> I suggest you remove the nflog_data_init(), nflog_data_alloc(),
> nflog_data_free() and nflog_nlmsg_parse().
> 
> Those are part of the old API, we should focus on API that we can
> combine with libmnl.

I think I can follow your suggestion, is it correct?

Please let me ask two more things.
With these functions, nflog attrs can be acquired by
mnl_attr_get_payload, but can not show as XML in one shot. To do it,
may I post another patch:

    struct nflog_data *nfnl_attrs2data(struct nlattr **attr)
    {
        struct nflog_data *nfad = calloc(1, sizeof(struct nflog_data));
        if (nfad == NULL)
            return NULL;
        nfad->nfa = (struct nfattr **)&attr[1];
        return nfad;
    }

Is it acceptable?

It's just my curiosity, would you tell me what does nfnl_ prefix
stand for?

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

Patch

diff --git a/utils/Makefile.am b/utils/Makefile.am
index f961b6c..dfe5f34 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -1,11 +1,15 @@ 
 include ${top_srcdir}/Make_global.am
 
-check_PROGRAMS = nfulnl_test
+check_PROGRAMS = nfulnl_test nf-log
 
 nfulnl_test_SOURCES = nfulnl_test.c
 nfulnl_test_LDADD = ../src/libnetfilter_log.la
 nfulnl_test_LDFLAGS = -dynamic
 
+nf_log_SOURCES = nf-log.c
+nf_log_LDADD = ../src/libnetfilter_log.la
+nf_log_LDFLAGS = -dynamic -lmnl
+
 if BUILD_IPULOG
 check_PROGRAMS += ulog_test
 
diff --git a/utils/nf-log.c b/utils/nf-log.c
new file mode 100644
index 0000000..ab9ac70
--- /dev/null
+++ b/utils/nf-log.c
@@ -0,0 +1,178 @@ 
+/* This example is placed in the public domain. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <arpa/inet.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_log.h>
+
+#include <libmnl/libmnl.h>
+#include <libnetfilter_log/libnetfilter_log.h>
+
+static int log_cb(const struct nlmsghdr *nlh, void *data)
+{
+	struct nflog_data *nfad;
+	struct nfulnl_msg_packet_hdr *ph = NULL;
+	const char *prefix = NULL;
+	uint32_t mark = 0;
+	int ret;
+
+	nfad = nflog_data_alloc();
+	if (nfad == NULL)
+		return MNL_CB_ERROR;
+	ret = nflog_nlmsg_parse(nlh, nfad);
+	if (ret != MNL_CB_OK)
+		return ret;
+
+	ph = nflog_get_msg_packet_hdr(nfad);
+	prefix = nflog_get_prefix(nfad);
+	mark = nflog_get_nfmark(nfad);
+
+	printf("log received (prefix=\"%s\" hw=0x%04x hook=%u mark=%u)\n",
+		prefix ? prefix : "", ntohs(ph->hw_protocol), ph->hook,
+		mark);
+
+	return MNL_CB_OK;
+}
+
+static struct nlmsghdr *
+nflog_build_cfg_pf_request(char *buf, uint8_t command)
+{
+	struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
+	nlh->nlmsg_type	= (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
+	nlh->nlmsg_flags = NLM_F_REQUEST;
+
+	struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+	nfg->nfgen_family = AF_INET;
+	nfg->version = NFNETLINK_V0;
+
+	struct nfulnl_msg_config_cmd 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 = mnl_nlmsg_put_header(buf);
+	nlh->nlmsg_type	= (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
+	nlh->nlmsg_flags = NLM_F_REQUEST;
+
+	struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+	nfg->nfgen_family = AF_INET;
+	nfg->version = NFNETLINK_V0;
+	nfg->res_id = htons(qnum);
+
+	struct nfulnl_msg_config_cmd 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 = mnl_nlmsg_put_header(buf);
+	nlh->nlmsg_type	= (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
+	nlh->nlmsg_flags = NLM_F_REQUEST;
+
+	struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+	nfg->nfgen_family = AF_UNSPEC;
+	nfg->version = NFNETLINK_V0;
+	nfg->res_id = htons(qnum);
+
+	struct nfulnl_msg_config_mode params = {
+		.copy_range = htonl(range),
+		.copy_mode = mode,
+	};
+	mnl_attr_put(nlh, NFULA_CFG_MODE, sizeof(params), &params);
+
+	return nlh;
+}
+
+int main(int argc, char *argv[])
+{
+	struct mnl_socket *nl;
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+	int ret;
+	unsigned int portid, qnum;
+
+	if (argc != 2) {
+		printf("Usage: %s [queue_num]\n", argv[0]);
+		exit(EXIT_FAILURE);
+	}
+	qnum = atoi(argv[1]);
+
+	nl = mnl_socket_open(NETLINK_NETFILTER);
+	if (nl == NULL) {
+		perror("mnl_socket_open");
+		exit(EXIT_FAILURE);
+	}
+
+	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
+		perror("mnl_socket_bind");
+		exit(EXIT_FAILURE);
+	}
+	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) {
+		perror("mnl_socket_sendto");
+		exit(EXIT_FAILURE);
+	}
+
+	nlh = nflog_build_cfg_pf_request(buf, NFULNL_CFG_CMD_PF_BIND);
+
+	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+		perror("mnl_socket_sendto");
+		exit(EXIT_FAILURE);
+	}
+
+	nlh = nflog_build_cfg_request(buf, NFULNL_CFG_CMD_BIND, qnum);
+
+	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+		perror("mnl_socket_sendto");
+		exit(EXIT_FAILURE);
+	}
+
+	nlh = nflog_build_cfg_params(buf, NFULNL_COPY_PACKET, 0xFFFF, qnum);
+
+	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+		perror("mnl_socket_sendto");
+		exit(EXIT_FAILURE);
+	}
+
+	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+	if (ret == -1) {
+		perror("mnl_socket_recvfrom");
+		exit(EXIT_FAILURE);
+	}
+	while (ret > 0) {
+		ret = mnl_cb_run(buf, ret, 0, portid, log_cb, NULL);
+		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;
+}