@@ -27,5 +27,5 @@ regular_CFLAGS="-Wall -Waggregate-return -Wmissing-declarations \
-Wformat=2 -pipe"
AC_SUBST([regular_CPPFLAGS])
AC_SUBST([regular_CFLAGS])
-AC_CONFIG_FILES([Makefile src/Makefile include/Makefile include/libmnl/Makefile include/linux/Makefile include/linux/netfilter/Makefile examples/Makefile examples/genl/Makefile examples/kobject/Makefile examples/netfilter/Makefile examples/rtnl/Makefile examples/mmap/Makefile examples/mmap/min/Makefile examples/mmap/nonmin1/Makefile libmnl.pc doxygen.cfg])
+AC_CONFIG_FILES([Makefile src/Makefile include/Makefile include/libmnl/Makefile include/linux/Makefile include/linux/netfilter/Makefile examples/Makefile examples/genl/Makefile examples/kobject/Makefile examples/netfilter/Makefile examples/rtnl/Makefile examples/mmap/Makefile examples/mmap/min/Makefile examples/mmap/nonmin1/Makefile examples/mmap/nonmin2/Makefile libmnl.pc doxygen.cfg])
AC_OUTPUT
@@ -1 +1 @@
-SUBDIRS = min nonmin1
+SUBDIRS = min nonmin1 nonmin2
new file mode 100644
@@ -0,0 +1,19 @@
+include $(top_srcdir)/Make_global.am
+
+check_PROGRAMS = nf-log \
+ nfct-dump \
+ rtnl-addr-dump \
+ rtnl-route-dump
+
+nf_log_SOURCES = nf-log.c
+nf_log_LDADD = ../../../src/libmnl.la
+
+nfct_dump_SOURCES = nfct-dump.c
+nfct_dump_LDADD = ../../../src/libmnl.la
+
+rtnl_addr_dump_SOURCES = rtnl-addr-dump.c
+rtnl_addr_dump_LDADD = ../../../src/libmnl.la
+
+rtnl_route_dump_SOURCES = rtnl-route-dump.c
+rtnl_route_dump_LDADD = ../../../src/libmnl.la
+
new file mode 100644
@@ -0,0 +1,269 @@
+/* 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 <errno.h>
+#include <poll.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>
+
+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;
+}
+
+static int log_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct nlattr *tb[NFULA_MAX+1] = {};
+ struct nfulnl_msg_packet_hdr *ph = NULL;
+ const char *prefix = NULL;
+ uint32_t mark = 0;
+
+ mnl_attr_parse(nlh, sizeof(struct nfgenmsg), parse_attr_cb, tb);
+ if (tb[NFULA_PACKET_HDR])
+ ph = mnl_attr_get_payload(tb[NFULA_PACKET_HDR]);
+ if (tb[NFULA_PREFIX])
+ prefix = mnl_attr_get_str(tb[NFULA_PREFIX]);
+ if (tb[NFULA_MARK])
+ mark = ntohl(mnl_attr_get_u32(tb[NFULA_MARK]));
+
+ 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 int nflog_build_cfg_pf_request(void *buf, void *data)
+{
+ uint8_t command = *(uint8_t *)data;
+
+ 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->nlmsg_len;
+}
+
+struct cfg_request {
+ uint8_t command;
+ int qnum;
+};
+
+static int nflog_build_cfg_request(void *buf, void *data)
+{
+ uint8_t command = ((struct cfg_request *)data)->command;
+ int qnum = ((struct cfg_request *)data)->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->nlmsg_len;
+}
+
+struct cfg_params {
+ uint8_t mode;
+ int range;
+ int qnum;
+};
+
+static int nflog_build_cfg_params(void *buf, void *data)
+{
+ uint8_t mode = ((struct cfg_params *)data)->mode;
+ int range = ((struct cfg_params *)data)->range;
+ int qnum = ((struct cfg_params *)data)->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), ¶ms);
+
+ return nlh->nlmsg_len;
+}
+
+int main(int argc, char *argv[])
+{
+ struct mnl_socket *nl;
+ struct mnl_ring_socket *nlm;
+ struct nl_mmap_req nlmr = MNL_MMAP_DEFAULT_REQ;
+ int ret;
+ unsigned int portid, qnum;
+ uint8_t pf_cmd;
+ struct cfg_request cfg_request;
+ struct cfg_params cfg_params;
+
+ 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);
+ }
+
+ nlm = mnl_ring_map(nl, &nlmr, &nlmr);
+ if (nlm == NULL) {
+ perror("mnl_ring_map");
+ 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);
+
+ pf_cmd = NFULNL_CFG_CMD_PF_UNBIND;
+ if (mnl_ring_build_frame(nlm, nflog_build_cfg_pf_request, &pf_cmd) <= 0) {
+ perror("mnl_ring_build_frame");
+ exit(EXIT_FAILURE);
+ }
+ /*
+ * nframes++;
+ * assert(nframes < nlmr.nm_frame_nr);
+ */
+ if (mnl_ring_send(nlm) < 0) {
+ perror("mnl_ring_send");
+ exit(EXIT_FAILURE);
+ }
+ mnl_ring_advance(nlm, MNL_RING_TX);
+
+ pf_cmd = NFULNL_CFG_CMD_PF_BIND;
+ if (mnl_ring_build_frame(nlm, nflog_build_cfg_pf_request, &pf_cmd) < 0) {
+ perror("mnl_ring_build_frame");
+ exit(EXIT_FAILURE);
+ }
+ if (mnl_ring_send(nlm) < 0) {
+ perror("mnl_ring_send");
+ exit(EXIT_FAILURE);
+ }
+ mnl_ring_advance(nlm, MNL_RING_TX);
+
+ cfg_request = (struct cfg_request){
+ .command = NFULNL_CFG_CMD_BIND,
+ .qnum = qnum
+ };
+ if (mnl_ring_build_frame(nlm, nflog_build_cfg_request, &cfg_request) < 0) {
+ perror("mnl_ring_build_frame");
+ exit(EXIT_FAILURE);
+ }
+ if (mnl_ring_send(nlm) < 0) {
+ perror("mnl_ring_send");
+ exit(EXIT_FAILURE);
+ }
+ mnl_ring_advance(nlm, MNL_RING_TX);
+
+ cfg_params = (struct cfg_params){
+ .mode = NFULNL_COPY_PACKET,
+ .range = 0xFFFF,
+ .qnum = qnum
+ };
+ if (mnl_ring_build_frame(nlm, nflog_build_cfg_params, &cfg_params) <= 0) {
+ perror("mnl_ring_build_frame");
+ exit(EXIT_FAILURE);
+ }
+ if (mnl_ring_send(nlm) < 0) {
+ perror("mnl_ring_send");
+ exit(EXIT_FAILURE);
+ }
+ mnl_ring_advance(nlm, MNL_RING_TX);
+
+ while ((ret = mnl_ring_parse_frame(nlm, 0, portid, log_cb, NULL)) >= 0)
+ ;
+
+ if (ret == -1) {
+ perror("error");
+ exit(EXIT_FAILURE);
+ }
+
+ mnl_ring_unmap(nlm);
+ mnl_socket_close(nl);
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,333 @@
+/* This example is placed in the public domain. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <arpa/inet.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <poll.h>
+
+#include <libmnl/libmnl.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_conntrack.h>
+
+static int parse_counters_cb(const struct nlattr *attr, void *data)
+{
+ const struct nlattr **tb = data;
+ int type = mnl_attr_get_type(attr);
+
+ if (mnl_attr_type_valid(attr, CTA_COUNTERS_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case CTA_COUNTERS_PACKETS:
+ case CTA_COUNTERS_BYTES:
+ if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
+ }
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static void print_counters(const struct nlattr *nest)
+{
+ struct nlattr *tb[CTA_COUNTERS_MAX+1] = {};
+
+ mnl_attr_parse_nested(nest, parse_counters_cb, tb);
+ if (tb[CTA_COUNTERS_PACKETS]) {
+ printf("packets=%"PRIu64" ",
+ be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_PACKETS])));
+ }
+ if (tb[CTA_COUNTERS_BYTES]) {
+ printf("bytes=%"PRIu64" ",
+ be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_BYTES])));
+ }
+}
+
+static int parse_ip_cb(const struct nlattr *attr, void *data)
+{
+ const struct nlattr **tb = data;
+ int type = mnl_attr_get_type(attr);
+
+ if (mnl_attr_type_valid(attr, CTA_IP_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case CTA_IP_V4_SRC:
+ case CTA_IP_V4_DST:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
+ case CTA_IP_V6_SRC:
+ case CTA_IP_V6_DST:
+ if (mnl_attr_validate2(attr, MNL_TYPE_BINARY,
+ sizeof(struct in6_addr)) < 0) {
+ perror("mnl_attr_validate2");
+ return MNL_CB_ERROR;
+ }
+ break;
+ }
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static void print_ip(const struct nlattr *nest)
+{
+ struct nlattr *tb[CTA_IP_MAX+1] = {};
+
+ mnl_attr_parse_nested(nest, parse_ip_cb, tb);
+ if (tb[CTA_IP_V4_SRC]) {
+ struct in_addr *in = mnl_attr_get_payload(tb[CTA_IP_V4_SRC]);
+ printf("src=%s ", inet_ntoa(*in));
+ }
+ if (tb[CTA_IP_V4_DST]) {
+ struct in_addr *in = mnl_attr_get_payload(tb[CTA_IP_V4_DST]);
+ printf("dst=%s ", inet_ntoa(*in));
+ }
+ if (tb[CTA_IP_V6_SRC]) {
+ struct in6_addr *in = mnl_attr_get_payload(tb[CTA_IP_V6_SRC]);
+ char out[INET6_ADDRSTRLEN];
+
+ if (!inet_ntop(AF_INET6, in, out, sizeof(out)))
+ printf("src=%s ", out);
+ }
+ if (tb[CTA_IP_V6_DST]) {
+ struct in6_addr *in = mnl_attr_get_payload(tb[CTA_IP_V6_DST]);
+ char out[INET6_ADDRSTRLEN];
+
+ if (!inet_ntop(AF_INET6, in, out, sizeof(out)))
+ printf("dst=%s ", out);
+ }
+}
+
+static int parse_proto_cb(const struct nlattr *attr, void *data)
+{
+ const struct nlattr **tb = data;
+ int type = mnl_attr_get_type(attr);
+
+ if (mnl_attr_type_valid(attr, CTA_PROTO_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case CTA_PROTO_NUM:
+ case CTA_PROTO_ICMP_TYPE:
+ case CTA_PROTO_ICMP_CODE:
+ if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
+ case CTA_PROTO_SRC_PORT:
+ case CTA_PROTO_DST_PORT:
+ case CTA_PROTO_ICMP_ID:
+ if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
+ }
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static void print_proto(const struct nlattr *nest)
+{
+ struct nlattr *tb[CTA_PROTO_MAX+1] = {};
+
+ mnl_attr_parse_nested(nest, parse_proto_cb, tb);
+ if (tb[CTA_PROTO_NUM]) {
+ printf("proto=%u ", mnl_attr_get_u8(tb[CTA_PROTO_NUM]));
+ }
+ if (tb[CTA_PROTO_SRC_PORT]) {
+ printf("sport=%u ",
+ ntohs(mnl_attr_get_u16(tb[CTA_PROTO_SRC_PORT])));
+ }
+ if (tb[CTA_PROTO_DST_PORT]) {
+ printf("dport=%u ",
+ ntohs(mnl_attr_get_u16(tb[CTA_PROTO_DST_PORT])));
+ }
+ if (tb[CTA_PROTO_ICMP_ID]) {
+ printf("id=%u ",
+ ntohs(mnl_attr_get_u16(tb[CTA_PROTO_ICMP_ID])));
+ }
+ if (tb[CTA_PROTO_ICMP_TYPE]) {
+ printf("type=%u ", mnl_attr_get_u8(tb[CTA_PROTO_ICMP_TYPE]));
+ }
+ if (tb[CTA_PROTO_ICMP_CODE]) {
+ printf("code=%u ", mnl_attr_get_u8(tb[CTA_PROTO_ICMP_CODE]));
+ }
+}
+
+static int parse_tuple_cb(const struct nlattr *attr, void *data)
+{
+ const struct nlattr **tb = data;
+ int type = mnl_attr_get_type(attr);
+
+ if (mnl_attr_type_valid(attr, CTA_TUPLE_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case CTA_TUPLE_IP:
+ if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
+ case CTA_TUPLE_PROTO:
+ if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
+ }
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static void print_tuple(const struct nlattr *nest)
+{
+ struct nlattr *tb[CTA_TUPLE_MAX+1] = {};
+
+ mnl_attr_parse_nested(nest, parse_tuple_cb, tb);
+ if (tb[CTA_TUPLE_IP]) {
+ print_ip(tb[CTA_TUPLE_IP]);
+ }
+ if (tb[CTA_TUPLE_PROTO]) {
+ print_proto(tb[CTA_TUPLE_PROTO]);
+ }
+}
+
+static int data_attr_cb(const struct nlattr *attr, void *data)
+{
+ const struct nlattr **tb = data;
+ int type = mnl_attr_get_type(attr);
+
+ if (mnl_attr_type_valid(attr, CTA_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case CTA_TUPLE_ORIG:
+ case CTA_COUNTERS_ORIG:
+ case CTA_COUNTERS_REPLY:
+ if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
+ case CTA_TIMEOUT:
+ case CTA_MARK:
+ case CTA_SECMARK:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
+ }
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int data_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct nlattr *tb[CTA_MAX+1] = {};
+ struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
+
+ mnl_attr_parse(nlh, sizeof(*nfg), data_attr_cb, tb);
+ if (tb[CTA_TUPLE_ORIG])
+ print_tuple(tb[CTA_TUPLE_ORIG]);
+
+ if (tb[CTA_MARK])
+ printf("mark=%u ", ntohl(mnl_attr_get_u32(tb[CTA_MARK])));
+
+ if (tb[CTA_SECMARK])
+ printf("secmark=%u ", ntohl(mnl_attr_get_u32(tb[CTA_SECMARK])));
+
+ if (tb[CTA_COUNTERS_ORIG]) {
+ printf("original ");
+ print_counters(tb[CTA_COUNTERS_ORIG]);
+ }
+
+ if (tb[CTA_COUNTERS_REPLY]) {
+ printf("reply ");
+ print_counters(tb[CTA_COUNTERS_REPLY]);
+ }
+
+ printf("\n");
+ return MNL_CB_OK;
+}
+
+static int build_cb(void *buf, void *data)
+{
+ struct nlmsghdr *nlh;
+ struct nfgenmsg *nfh;
+ unsigned int seq = *(unsigned int *)data;
+
+ nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET;
+ nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
+ nlh->nlmsg_seq = seq = time(NULL);
+
+ nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
+ nfh->nfgen_family = AF_INET;
+ nfh->version = NFNETLINK_V0;
+ nfh->res_id = 0;
+
+ return nlh->nlmsg_len;
+}
+
+int main(void)
+{
+ struct mnl_socket *nl;
+ struct mnl_ring_socket *nlm;
+ struct nl_mmap_req nlmr = MNL_MMAP_DEFAULT_REQ;
+ int ret;
+ uint32_t seq, portid;
+
+ nl = mnl_socket_open(NETLINK_NETFILTER);
+ if (nl == NULL) {
+ perror("mnl_socket_open");
+ exit(EXIT_FAILURE);
+ }
+
+ nlm = mnl_ring_map(nl, &nlmr, &nlmr);
+ if (nlm == NULL) {
+ perror("mnl_ring_map");
+ 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);
+
+ if (mnl_ring_build_frame(nlm, build_cb, &seq) <= 0) {
+ perror("mnl_ring_build_frame");
+ exit(EXIT_FAILURE);
+ }
+
+ if (mnl_ring_send(nlm) < 0) {
+ perror("mnl_socket_send");
+ exit(EXIT_FAILURE);
+ }
+ mnl_ring_advance(nlm, MNL_RING_TX);
+
+ while ((ret = mnl_ring_parse_frame(nlm, seq, portid, data_cb, NULL)) > 0)
+ ;
+
+ if (ret == -1) {
+ perror("error");
+ exit(EXIT_FAILURE);
+ }
+
+ mnl_ring_unmap(nlm);
+ mnl_socket_close(nl);
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,158 @@
+/* This example is placed in the public domain. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <arpa/inet.h>
+
+#include <libmnl/libmnl.h>
+#include <linux/if.h>
+#include <linux/if_link.h>
+#include <linux/rtnetlink.h>
+
+static int data_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, IFA_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case IFA_ADDRESS:
+ if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
+ }
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int data_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct nlattr *tb[IFLA_MAX+1] = {};
+ struct ifaddrmsg *ifa = mnl_nlmsg_get_payload(nlh);
+
+ printf("index=%d family=%d ", ifa->ifa_index, ifa->ifa_family);
+
+ mnl_attr_parse(nlh, sizeof(*ifa), data_attr_cb, tb);
+ printf("addr=");
+ if (tb[IFA_ADDRESS]) {
+ void *addr = mnl_attr_get_payload(tb[IFA_ADDRESS]);
+ char out[INET6_ADDRSTRLEN];
+
+ if (inet_ntop(ifa->ifa_family, addr, out, sizeof(out)))
+ printf("%s ", out);
+ }
+ printf("scope=");
+ switch(ifa->ifa_scope) {
+ case 0:
+ printf("global ");
+ break;
+ case 200:
+ printf("site ");
+ break;
+ case 253:
+ printf("link ");
+ break;
+ case 254:
+ printf("host ");
+ break;
+ case 255:
+ printf("nowhere ");
+ break;
+ default:
+ printf("%d ", ifa->ifa_scope);
+ break;
+ }
+
+ printf("\n");
+ return MNL_CB_OK;
+}
+
+struct seq_family {
+ unsigned char family;
+ unsigned int seq;
+};
+
+static int build_cb(void *buf, void *data)
+{
+ struct nlmsghdr *nlh;
+ struct rtgenmsg *rt;
+ struct seq_family *sf = (struct seq_family *)data;
+
+ nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = RTM_GETADDR;
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ nlh->nlmsg_seq = sf->seq;
+ rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg));
+ rt->rtgen_family = sf->family;
+
+ return nlh->nlmsg_len;
+}
+
+int main(int argc, char *argv[])
+{
+ struct mnl_socket *nl;
+ struct mnl_ring_socket *nlm;
+ struct nl_mmap_req nlmr = MNL_MMAP_DEFAULT_REQ;
+ int ret;
+ unsigned int portid;
+ struct seq_family sf;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <inet|inet6>\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ if (strcmp(argv[1], "inet") == 0)
+ sf.family = AF_INET;
+ else if (strcmp(argv[1], "inet6") == 0)
+ sf.family = AF_INET6;
+
+ nl = mnl_socket_open(NETLINK_ROUTE);
+ if (nl == NULL) {
+ perror("mnl_socket_open");
+ exit(EXIT_FAILURE);
+ }
+
+ nlm = mnl_ring_map(nl, &nlmr, &nlmr);
+ if (nlm == NULL) {
+ perror("mnl_ring_map");
+ 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);
+
+ sf.seq = time(NULL);
+ if (mnl_ring_build_frame(nlm, build_cb, &sf) <= 0) {
+ perror("mnl_ring_build_frame");
+ exit(EXIT_FAILURE);
+ }
+
+ if (mnl_ring_send(nlm) < 0) {
+ perror("mnl_ring_send");
+ exit(EXIT_FAILURE);
+ }
+ mnl_ring_advance(nlm, MNL_RING_TX);
+
+ while ((ret = mnl_ring_parse_frame(nlm, sf.seq, portid, data_cb, NULL)) > 0)
+ ;
+
+ if (ret == -1) {
+ perror("error");
+ exit(EXIT_FAILURE);
+ }
+
+ mnl_ring_unmap(nlm);
+ mnl_socket_close(nl);
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,381 @@
+/* This example is placed in the public domain. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include <libmnl/libmnl.h>
+#include <linux/if.h>
+#include <linux/if_link.h>
+#include <linux/rtnetlink.h>
+
+static int data_attr_cb2(const struct nlattr *attr, void *data)
+{
+ const struct nlattr **tb = data;
+
+ /* skip unsupported attribute in user-space */
+ if (mnl_attr_type_valid(attr, RTAX_MAX) < 0)
+ return MNL_CB_OK;
+
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+
+ tb[mnl_attr_get_type(attr)] = attr;
+ return MNL_CB_OK;
+}
+
+static void attributes_show_ipv4(struct nlattr *tb[])
+{
+ if (tb[RTA_TABLE]) {
+ printf("table=%u ", mnl_attr_get_u32(tb[RTA_TABLE]));
+ }
+ if (tb[RTA_DST]) {
+ struct in_addr *addr = mnl_attr_get_payload(tb[RTA_DST]);
+ printf("dst=%s ", inet_ntoa(*addr));
+ }
+ if (tb[RTA_SRC]) {
+ struct in_addr *addr = mnl_attr_get_payload(tb[RTA_SRC]);
+ printf("src=%s ", inet_ntoa(*addr));
+ }
+ if (tb[RTA_OIF]) {
+ printf("oif=%u ", mnl_attr_get_u32(tb[RTA_OIF]));
+ }
+ if (tb[RTA_FLOW]) {
+ printf("flow=%u ", mnl_attr_get_u32(tb[RTA_FLOW]));
+ }
+ if (tb[RTA_PREFSRC]) {
+ struct in_addr *addr = mnl_attr_get_payload(tb[RTA_PREFSRC]);
+ printf("prefsrc=%s ", inet_ntoa(*addr));
+ }
+ if (tb[RTA_GATEWAY]) {
+ struct in_addr *addr = mnl_attr_get_payload(tb[RTA_GATEWAY]);
+ printf("gw=%s ", inet_ntoa(*addr));
+ }
+ if (tb[RTA_PRIORITY]) {
+ printf("prio=%u ", mnl_attr_get_u32(tb[RTA_PRIORITY]));
+ }
+ if (tb[RTA_METRICS]) {
+ int i;
+ struct nlattr *tbx[RTAX_MAX+1] = {};
+
+ mnl_attr_parse_nested(tb[RTA_METRICS], data_attr_cb2, tbx);
+
+ for (i=0; i<RTAX_MAX; i++) {
+ if (tbx[i]) {
+ printf("metrics[%d]=%u ",
+ i, mnl_attr_get_u32(tbx[i]));
+ }
+ }
+ }
+}
+
+/* like inet_ntoa(), not reentrant */
+static const char *inet6_ntoa(struct in6_addr in6)
+{
+ static char buf[INET6_ADDRSTRLEN];
+
+ return inet_ntop(AF_INET6, &in6.s6_addr, buf, sizeof(buf));
+}
+
+static void attributes_show_ipv6(struct nlattr *tb[])
+{
+ if (tb[RTA_TABLE]) {
+ printf("table=%u ", mnl_attr_get_u32(tb[RTA_TABLE]));
+ }
+ if (tb[RTA_DST]) {
+ struct in6_addr *addr = mnl_attr_get_payload(tb[RTA_DST]);
+ printf("dst=%s ", inet6_ntoa(*addr));
+ }
+ if (tb[RTA_SRC]) {
+ struct in6_addr *addr = mnl_attr_get_payload(tb[RTA_SRC]);
+ printf("src=%s ", inet6_ntoa(*addr));
+ }
+ if (tb[RTA_OIF]) {
+ printf("oif=%u ", mnl_attr_get_u32(tb[RTA_OIF]));
+ }
+ if (tb[RTA_FLOW]) {
+ printf("flow=%u ", mnl_attr_get_u32(tb[RTA_FLOW]));
+ }
+ if (tb[RTA_PREFSRC]) {
+ struct in6_addr *addr = mnl_attr_get_payload(tb[RTA_PREFSRC]);
+ printf("prefsrc=%s ", inet6_ntoa(*addr));
+ }
+ if (tb[RTA_GATEWAY]) {
+ struct in6_addr *addr = mnl_attr_get_payload(tb[RTA_GATEWAY]);
+ printf("gw=%s ", inet6_ntoa(*addr));
+ }
+ if (tb[RTA_PRIORITY]) {
+ printf("prio=%u ", mnl_attr_get_u32(tb[RTA_PRIORITY]));
+ }
+ if (tb[RTA_METRICS]) {
+ int i;
+ struct nlattr *tbx[RTAX_MAX+1] = {};
+
+ mnl_attr_parse_nested(tb[RTA_METRICS], data_attr_cb2, tbx);
+
+ for (i=0; i<RTAX_MAX; i++) {
+ if (tbx[i]) {
+ printf("metrics[%d]=%u ",
+ i, mnl_attr_get_u32(tbx[i]));
+ }
+ }
+ }
+}
+
+static int data_ipv4_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, RTA_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case RTA_TABLE:
+ case RTA_DST:
+ case RTA_SRC:
+ case RTA_OIF:
+ case RTA_FLOW:
+ case RTA_PREFSRC:
+ case RTA_GATEWAY:
+ case RTA_PRIORITY:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
+ case RTA_METRICS:
+ if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
+ }
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int data_ipv6_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, RTA_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case RTA_TABLE:
+ case RTA_OIF:
+ case RTA_FLOW:
+ case RTA_PRIORITY:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
+ case RTA_DST:
+ case RTA_SRC:
+ case RTA_PREFSRC:
+ case RTA_GATEWAY:
+ if (mnl_attr_validate2(attr, MNL_TYPE_BINARY,
+ sizeof(struct in6_addr)) < 0) {
+ perror("mnl_attr_validate2");
+ return MNL_CB_ERROR;
+ }
+ break;
+ case RTA_METRICS:
+ if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
+ }
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int data_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct nlattr *tb[RTA_MAX+1] = {};
+ struct rtmsg *rm = mnl_nlmsg_get_payload(nlh);
+
+ /* protocol family = AF_INET | AF_INET6 */
+ printf("family=%u ", rm->rtm_family);
+
+ /* destination CIDR, eg. 24 or 32 for IPv4 */
+ printf("dst_len=%u ", rm->rtm_dst_len);
+
+ /* source CIDR */
+ printf("src_len=%u ", rm->rtm_src_len);
+
+ /* type of service (TOS), eg. 0 */
+ printf("tos=%u ", rm->rtm_tos);
+
+ /* table id:
+ * RT_TABLE_UNSPEC = 0
+ *
+ * ... user defined values ...
+ *
+ * RT_TABLE_COMPAT = 252
+ * RT_TABLE_DEFAULT = 253
+ * RT_TABLE_MAIN = 254
+ * RT_TABLE_LOCAL = 255
+ * RT_TABLE_MAX = 0xFFFFFFFF
+ *
+ * Synonimous attribute: RTA_TABLE.
+ */
+ printf("table=%u ", rm->rtm_table);
+
+ /* type:
+ * RTN_UNSPEC = 0
+ * RTN_UNICAST = 1
+ * RTN_LOCAL = 2
+ * RTN_BROADCAST = 3
+ * RTN_ANYCAST = 4
+ * RTN_MULTICAST = 5
+ * RTN_BLACKHOLE = 6
+ * RTN_UNREACHABLE = 7
+ * RTN_PROHIBIT = 8
+ * RTN_THROW = 9
+ * RTN_NAT = 10
+ * RTN_XRESOLVE = 11
+ * __RTN_MAX = 12
+ */
+ printf("type=%u ", rm->rtm_type);
+
+ /* scope:
+ * RT_SCOPE_UNIVERSE = 0 : everywhere in the universe
+ *
+ * ... user defined values ...
+ *
+ * RT_SCOPE_SITE = 200
+ * RT_SCOPE_LINK = 253 : destination attached to link
+ * RT_SCOPE_HOST = 254 : local address
+ * RT_SCOPE_NOWHERE = 255 : not existing destination
+ */
+ printf("scope=%u ", rm->rtm_scope);
+
+ /* protocol:
+ * RTPROT_UNSPEC = 0
+ * RTPROT_REDIRECT = 1
+ * RTPROT_KERNEL = 2 : route installed by kernel
+ * RTPROT_BOOT = 3 : route installed during boot
+ * RTPROT_STATIC = 4 : route installed by administrator
+ *
+ * Values >= RTPROT_STATIC are not interpreted by kernel, they are
+ * just user-defined.
+ */
+ printf("proto=%u ", rm->rtm_protocol);
+
+ /* flags:
+ * RTM_F_NOTIFY = 0x100: notify user of route change
+ * RTM_F_CLONED = 0x200: this route is cloned
+ * RTM_F_EQUALIZE = 0x400: Multipath equalizer: NI
+ * RTM_F_PREFIX = 0x800: Prefix addresses
+ */
+ printf("flags=%x ", rm->rtm_flags);
+
+ switch(rm->rtm_family) {
+ case AF_INET:
+ mnl_attr_parse(nlh, sizeof(*rm), data_ipv4_attr_cb, tb);
+ attributes_show_ipv4(tb);
+ break;
+ case AF_INET6:
+ mnl_attr_parse(nlh, sizeof(*rm), data_ipv6_attr_cb, tb);
+ attributes_show_ipv6(tb);
+ break;
+ }
+
+ printf("\n");
+ return MNL_CB_OK;
+}
+
+struct seq_family {
+ unsigned char family;
+ unsigned int seq;
+};
+
+static int build_cb(void *buf, void *data)
+{
+ struct nlmsghdr *nlh;
+ struct rtmsg *rtm;
+ struct seq_family *sf = (struct seq_family *)data;
+
+ nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = RTM_GETROUTE;
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ nlh->nlmsg_seq = sf->seq;
+ rtm = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtmsg));
+ rtm->rtm_family = sf->family;
+
+ return nlh->nlmsg_len;
+}
+
+int main(int argc, char *argv[])
+{
+ struct mnl_socket *nl;
+ struct mnl_ring_socket *nlm;
+ struct nl_mmap_req nlmr = MNL_MMAP_DEFAULT_REQ;
+ int ret;
+ unsigned int portid;
+ struct seq_family sf;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <inet|inet6>\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (strcmp(argv[1], "inet") == 0)
+ sf.family = AF_INET;
+ else if (strcmp(argv[1], "inet6") == 0)
+ sf.family = AF_INET6;
+
+ nl = mnl_socket_open(NETLINK_ROUTE);
+ if (nl == NULL) {
+ perror("mnl_socket_open");
+ exit(EXIT_FAILURE);
+ }
+
+ nlm = mnl_ring_map(nl, &nlmr, &nlmr);
+ if (nlm == NULL) {
+ perror("mnl_ring_map");
+ 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);
+
+ if (mnl_ring_build_frame(nlm, build_cb, &sf) <= 0) {
+ perror("mnl_ring_build_frame");
+ exit(EXIT_FAILURE);
+ }
+
+ if (mnl_ring_send(nlm) < 0) {
+ perror("mnl_ring_send");
+ exit(EXIT_FAILURE);
+ }
+ mnl_ring_advance(nlm, MNL_RING_TX);
+
+ while ((ret = mnl_ring_parse_frame(nlm, sf.seq, portid, data_cb, NULL)) > 0)
+ ;
+
+ if (ret == -1) {
+ perror("error");
+ exit(EXIT_FAILURE);
+ }
+
+ mnl_ring_unmap(nlm);
+ mnl_socket_close(nl);
+
+ return 0;
+}
Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp> --- configure.ac | 2 +- examples/mmap/Makefile.am | 2 +- examples/mmap/nonmin2/Makefile.am | 19 ++ examples/mmap/nonmin2/nf-log.c | 269 ++++++++++++++++++++++ examples/mmap/nonmin2/nfct-dump.c | 333 ++++++++++++++++++++++++++++ examples/mmap/nonmin2/rtnl-addr-dump.c | 158 +++++++++++++ examples/mmap/nonmin2/rtnl-route-dump.c | 381 ++++++++++++++++++++++++++++++++ 7 files changed, 1162 insertions(+), 2 deletions(-) create mode 100644 examples/mmap/nonmin2/Makefile.am create mode 100644 examples/mmap/nonmin2/nf-log.c create mode 100644 examples/mmap/nonmin2/nfct-dump.c create mode 100644 examples/mmap/nonmin2/rtnl-addr-dump.c create mode 100644 examples/mmap/nonmin2/rtnl-route-dump.c