This is a partial revert of commit 7462e4aa757dc28e74b4a731b3ee13079b04ef23 ("iptables-compat: Keep xtables-config and xtables-events out from tree") and re-adds xtables-events under a new name, with a few enhancements, this is --trace mode, which replaces printk-based tracing, and an imroved event mode which will now also display pid/name and new generation id at the end of a batch. Example output of xtables-monitor --event --trace PACKET: 10 fa6b77e1 IN=wlan0 MACSRC=51:14:31:51:XX:XX MACDST=1c:b6:b0:ac:XX:XX MACPROTO=86dd SRC=2a00:3a0:2::1 DST=2b00:bf0:c001::1 LEN=1440 TC=18 HOPLIMIT=61 FLOWLBL=1921 SPORT=22 DPORT=13024 ACK PSH TRACE: 10 fa6b77e1 raw:PREROUTING:return: TRACE: 10 fa6b77e1 raw:PREROUTING:policy:DROP TRACE: 10 fa6b77e1 filter:INPUT:return: TRACE: 10 fa6b77e1 filter:INPUT:policy:DROP EVENT: -6 -t mangle -A PREROUTING -j DNPT --src-pfx dead::/64 --dst-pfx 1c3::/64 NEWGEN: GENID=6581 PID=15601 NAME=xtables-multi Signed-off-by: Florian Westphal <fw@xxxxxxxxx> --- Changes since v1: - allow filtering for ip(6)tables, but also allow listing both ipv4/ipv6 events - add fallback for nft-style events for base chains (hook prios etc) - change to -N/-X for user defined chain/add/del iptables/Makefile.am | 3 +- iptables/xtables-compat-multi.c | 1 + iptables/xtables-monitor.c | 647 ++++++++++++++++++++++++++++++++ iptables/xtables-multi.c | 1 - iptables/xtables-multi.h | 2 +- 5 files changed, 651 insertions(+), 3 deletions(-) create mode 100644 iptables/xtables-monitor.c diff --git a/iptables/Makefile.am b/iptables/Makefile.am index 2de142083c81..008d811045d5 100644 --- a/iptables/Makefile.am +++ b/iptables/Makefile.am @@ -41,6 +41,7 @@ xtables_compat_multi_SOURCES += xtables-config-parser.y xtables-config-syntax.l xtables_compat_multi_SOURCES += xtables-save.c xtables-restore.c \ xtables-standalone.c xtables.c nft.c \ nft-shared.c nft-ipv4.c nft-ipv6.c nft-arp.c \ + xtables-monitor.c \ xtables-arp-standalone.c xtables-arp.c \ getethertype.c nft-bridge.c \ xtables-eb-standalone.c xtables-eb.c \ @@ -76,7 +77,7 @@ x_sbin_links = iptables-compat iptables-compat-restore iptables-compat-save \ ip6tables-compat ip6tables-compat-restore ip6tables-compat-save \ iptables-translate ip6tables-translate \ iptables-restore-translate ip6tables-restore-translate \ - arptables-compat ebtables-compat + arptables-compat ebtables-compat xtables-monitor endif iptables-extensions.8: iptables-extensions.8.tmpl ../extensions/matches.man ../extensions/targets.man diff --git a/iptables/xtables-compat-multi.c b/iptables/xtables-compat-multi.c index 0b05eaded617..014e5a4e3c8f 100644 --- a/iptables/xtables-compat-multi.c +++ b/iptables/xtables-compat-multi.c @@ -35,6 +35,7 @@ static const struct subcommand multi_subcommands[] = { {"ebtables-compat", xtables_eb_main}, {"ebtables-translate", xtables_eb_xlate_main}, {"ebtables", xtables_eb_main}, + {"xtables-monitor", xtables_monitor_main}, {NULL}, }; diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c new file mode 100644 index 000000000000..09f9fb2ede34 --- /dev/null +++ b/iptables/xtables-monitor.c @@ -0,0 +1,647 @@ +/* + * (C) 2012-2013 by Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> + * + * 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. + * + * This software has been sponsored by Sophos Astaro <http://www.sophos.com> + */ + +#include <stdlib.h> +#include <time.h> +#include <string.h> +#include <netinet/ether.h> +#include <netinet/in.h> +#include <netinet/ip6.h> +#include <net/if_arp.h> +#include <getopt.h> + +#include <sys/socket.h> +#include <arpa/inet.h> + +#include <linux/netfilter/nfnetlink.h> +#include <linux/netfilter/nf_tables.h> + +#include <libmnl/libmnl.h> +#include <libnftnl/table.h> +#include <libnftnl/trace.h> +#include <libnftnl/chain.h> +#include <libnftnl/rule.h> + +#include <include/xtables.h> +#include "iptables.h" /* for xtables_globals */ +#include "xtables-multi.h" +#include "nft.h" +#include "nft-arp.h" + +struct cb_arg { + uint32_t nfproto; + +}; + +static int table_cb(const struct nlmsghdr *nlh, void *data) +{ + uint32_t type = nlh->nlmsg_type & 0xFF; + const struct cb_arg *arg = data; + struct nftnl_table *t; + char buf[4096]; + + t = nftnl_table_alloc(); + if (t == NULL) + goto err; + + if (nftnl_table_nlmsg_parse(nlh, t) < 0) + goto err_free; + + if (arg->nfproto && arg->nfproto != nftnl_table_get_u32(t, NFTNL_TABLE_FAMILY)) + goto err_free; + nftnl_table_snprintf(buf, sizeof(buf), t, NFTNL_OUTPUT_DEFAULT, 0); + printf(" EVENT: "); + printf("nft: %s table: %s\n", type == NFT_MSG_NEWTABLE ? "NEW" : "DEL", buf); + +err_free: + nftnl_table_free(t); +err: + return MNL_CB_OK; +} + +static bool counters; +static bool trace; +static bool events; + +static int rule_cb(const struct nlmsghdr *nlh, void *data) +{ + struct arptables_command_state cs_arp = {}; + struct iptables_command_state cs = {}; + uint32_t type = nlh->nlmsg_type & 0xFF; + const struct cb_arg *arg = data; + struct nftnl_rule *r; + void *fw = NULL; + uint8_t family; + + r = nftnl_rule_alloc(); + if (r == NULL) + goto err; + + if (nftnl_rule_nlmsg_parse(nlh, r) < 0) + goto err_free; + + family = nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY); + if (arg->nfproto && arg->nfproto != family) + goto err_free; + + printf(" EVENT: "); + switch (family) { + case AF_INET: + case AF_INET6: + printf("-%c ", family == AF_INET ? '4' : '6'); + nft_rule_to_iptables_command_state(r, &cs); + fw = &cs; + break; + case NFPROTO_ARP: + printf("-0 "); + nft_rule_to_arptables_command_state(r, &cs_arp); + fw = &cs_arp; + break; + default: + goto err_free; + } + + printf("-t %s ", nftnl_rule_get_str(r, NFTNL_RULE_TABLE)); + nft_rule_print_save(fw, r, + type == NFT_MSG_NEWRULE ? NFT_RULE_APPEND : + NFT_RULE_DEL, + counters ? 0 : FMT_NOCOUNTS); +err_free: + nftnl_rule_free(r); +err: + return MNL_CB_OK; +} + +static int chain_cb(const struct nlmsghdr *nlh, void *data) +{ + uint32_t type = nlh->nlmsg_type & 0xFF; + const struct cb_arg *arg = data; + struct nftnl_chain *c; + char buf[4096]; + int family; + + c = nftnl_chain_alloc(); + if (c == NULL) + goto err; + + if (nftnl_chain_nlmsg_parse(nlh, c) < 0) + goto err_free; + + family = nftnl_chain_get_u32(c, NFTNL_CHAIN_FAMILY); + if (arg->nfproto && arg->nfproto != family) + goto err_free; + + if (nftnl_chain_is_set(c, NFTNL_CHAIN_PRIO)) + family = -1; + + printf(" EVENT: "); + switch (family) { + case NFPROTO_IPV4: + family = 4; + break; + case NFPROTO_IPV6: + family = 6; + break; + default: + nftnl_chain_snprintf(buf, sizeof(buf), c, NFTNL_OUTPUT_DEFAULT, 0); + printf("# nft: %s\n", buf); + goto err_free; + } + + printf("-%d -t %s -%c %s\n", + family, + nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), + type == NFT_MSG_NEWCHAIN ? 'N' : 'X', + nftnl_chain_get_str(c, NFTNL_CHAIN_NAME)); +err_free: + nftnl_chain_free(c); +err: + return MNL_CB_OK; +} + +static int newgen_cb(const struct nlmsghdr *nlh, void *data) +{ + uint32_t genid = 0, pid = 0; + const struct nlattr *attr; + const char *name = NULL; + + mnl_attr_for_each(attr, nlh, sizeof(struct nfgenmsg)) { + switch (mnl_attr_get_type(attr)) { + case NFTA_GEN_ID: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + break; + genid = ntohl(mnl_attr_get_u32(attr)); + break; + case NFTA_GEN_PROC_NAME: + if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) + break; + name = mnl_attr_get_str(attr); + break; + case NFTA_GEN_PROC_PID: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + break; + pid = ntohl(mnl_attr_get_u32(attr)); + break; + } + } + + if (name) + printf("NEWGEN: GENID=%u PID=%u NAME=%s\n", genid, pid, name); + + return MNL_CB_OK; +} + +static void trace_print_return(const struct nftnl_trace *nlt) +{ + const char *chain = NULL; + + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_JUMP_TARGET)) { + chain = nftnl_trace_get_str(nlt, NFTNL_TRACE_JUMP_TARGET); + printf("%s", chain); + } +} + +static void trace_print_rule(const struct nftnl_trace *nlt, struct cb_arg *args) +{ + uint64_t handle = nftnl_trace_get_u64(nlt, NFTNL_TRACE_RULE_HANDLE); + uint32_t family = nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY); + const char *table = nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE); + const char *chain = nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN); + struct nftnl_rule *r; + struct mnl_socket *nl; + struct nlmsghdr *nlh; + uint32_t portid; + char buf[16536]; + int ret; + + r = nftnl_rule_alloc(); + if (r == NULL) { + perror("OOM"); + exit(EXIT_FAILURE); + } + + nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family, NLM_F_DUMP, 0); + + nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family); + nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain); + nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table); + nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, handle); + nftnl_rule_nlmsg_build_payload(nlh, r); + nftnl_rule_free(r); + + 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); + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_send"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, 0, portid, rule_cb, args); + if (ret <= 0) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) { + perror("error"); + exit(EXIT_FAILURE); + } + mnl_socket_close(nl); +} + +static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *args) +{ + struct list_head stmts = LIST_HEAD_INIT(stmts); + uint32_t nfproto, family; + uint16_t l4proto = 0; + uint32_t mark; + char name[IFNAMSIZ]; + + printf("PACKET: %d %08x ", args->nfproto, nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID)); + + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_IIF)) + printf("IN=%s ", if_indextoname(nftnl_trace_get_u32(nlt, NFTNL_TRACE_IIF), name)); + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_OIF)) + printf("OUT=%s ", if_indextoname(nftnl_trace_get_u32(nlt, NFTNL_TRACE_OIF), name)); + + family = nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY); + nfproto = family; + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_NFPROTO)) { + nfproto = nftnl_trace_get_u32(nlt, NFTNL_TRACE_NFPROTO); + + if (family != nfproto) + printf("NFPROTO=%d ", nfproto); + } + + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_LL_HEADER)) { + const struct ethhdr *eh; + const char *linklayer; + uint32_t i, len; + uint16_t type = nftnl_trace_get_u16(nlt, NFTNL_TRACE_IIFTYPE); + + linklayer = nftnl_trace_get_data(nlt, NFTNL_TRACE_LL_HEADER, &len); + switch (type) { + case ARPHRD_ETHER: + if (len < sizeof(*eh)) + break; + eh = (const void *)linklayer; + printf("MACSRC=%s ", ether_ntoa((const void *)eh->h_source)); + printf("MACDST=%s ", ether_ntoa((const void *)eh->h_dest)); + printf("MACPROTO=%04x ", ntohs(eh->h_proto)); + break; + default: + printf("LL=0x%x ", type); + for (i = 0 ; i < len; i++) + printf("%02x", linklayer[i]); + printf(" "); + break; + } + } + + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_NETWORK_HEADER)) { + const struct ip6_hdr *ip6h; + const struct iphdr *iph; + uint32_t i, len; + const char *nh; + + ip6h = nftnl_trace_get_data(nlt, NFTNL_TRACE_NETWORK_HEADER, &len); + + switch (nfproto) { + case NFPROTO_IPV4: { + char addrbuf[INET_ADDRSTRLEN]; + + if (len < sizeof(*iph)) + break; + iph = (const void *)ip6h; + + + inet_ntop(AF_INET, &iph->saddr, addrbuf, sizeof(addrbuf)); + printf("SRC=%s ", addrbuf); + inet_ntop(AF_INET, &iph->daddr, addrbuf, sizeof(addrbuf)); + printf("DST=%s ", addrbuf); + + printf("LEN=%d TOS=0x%x TTL=%d ID=%d", ntohs(iph->tot_len), iph->tos, iph->ttl, ntohs(iph->id)); + if (iph->frag_off & htons(0x8000)) + printf("CE "); + if (iph->frag_off & htons(IP_DF)) + printf("DF "); + if (iph->frag_off & htons(IP_MF)) + printf("MF "); + + if (ntohs(iph->frag_off) & 0x1fff) + printf("FRAG:%u ", ntohs(iph->frag_off) & 0x1fff); + + // TRACE: raw:OUTPUT:rule:1 IN= OUT=wlp58s0 SRC=217.197.81.41 DST=146.0.238.67 LEN=88 TOS=0x12 PREC=0x00 TTL=64 ID=34694 DF PROTO=TCP SPT=52432 DPT=22 SEQ=2308055971 ACK=3782479795 WINDOW=1444 RES=0x00 ACK PSH URGP=0 OPT (0101080A8D509CFA47870333) UID=1000 GID=1000 + l4proto = iph->protocol; + if (iph->ihl * 4 > sizeof(*iph)) { + unsigned int optsize; + const char *op; + + optsize = iph->ihl * 4 - sizeof(*iph); + op = (const char *)iph; + op += sizeof(*iph); + + printf("OPT ("); + for (i = 0; i < optsize; i++) + printf("%02X", op[i]); + printf(")"); + } + break; + } + case NFPROTO_IPV6: { + uint32_t flowlabel = ntohl(*(uint32_t *)ip6h); + char addrbuf[INET6_ADDRSTRLEN]; + + if (len < sizeof(*ip6h)) + break; + + inet_ntop(AF_INET6, &ip6h->ip6_src, addrbuf, sizeof(addrbuf)); + printf("SRC=%s ", addrbuf); + inet_ntop(AF_INET6, &ip6h->ip6_dst, addrbuf, sizeof(addrbuf)); + printf("DST=%s ", addrbuf); + + printf("LEN=%zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", + ntohs(ip6h->ip6_plen) + sizeof(*iph), + (flowlabel & 0x0ff00000) >> 20, + ip6h->ip6_hops, + flowlabel & 0x000fffff); + + l4proto = ip6h->ip6_nxt; + break; + } + default: + nh = (const char *)ip6h; + printf("NH="); + for (i = 0 ; i < len; i++) + printf("%02x", nh[i]); + printf(" "); + } + } + + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_TRANSPORT_HEADER)) { + const struct tcphdr *tcph; + uint32_t len; + + tcph = nftnl_trace_get_data(nlt, NFTNL_TRACE_TRANSPORT_HEADER, &len); + + switch (l4proto) { + case IPPROTO_DCCP: + case IPPROTO_SCTP: + case IPPROTO_UDPLITE: + case IPPROTO_UDP: + if (len < 4) + break; + printf("SPORT=%d DPORT=%d ", ntohs(tcph->th_sport), ntohs(tcph->th_dport)); + break; + case IPPROTO_TCP: + if (len < sizeof(*tcph)) + break; + printf("SPORT=%d DPORT=%d ", ntohs(tcph->th_sport), ntohs(tcph->th_dport)); + if (tcph->th_flags & (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG)) { + if (tcph->th_flags & TH_SYN) + printf("SYN "); + if (tcph->th_flags & TH_ACK) + printf("ACK "); + if (tcph->th_flags & TH_FIN) + printf("FIN "); + if (tcph->th_flags & TH_RST) + printf("RST "); + if (tcph->th_flags & TH_PUSH) + printf("PSH "); + if (tcph->th_flags & TH_URG) + printf("URG "); + } + break; + default: + break; + } + } + + mark = nftnl_trace_get_u32(nlt, NFTNL_TRACE_MARK); + if (mark) + printf("MARK=0x%x ", mark); +} + +static int trace_cb(const struct nlmsghdr *nlh, struct cb_arg *arg) +{ + struct nftnl_trace *nlt; + + nlt = nftnl_trace_alloc(); + if (nlt == NULL) + goto err; + + if (nftnl_trace_nlmsg_parse(nlh, nlt) < 0) + goto err_free; + + if (arg->nfproto && + arg->nfproto != nftnl_trace_get_u32(nlt, NFTNL_TABLE_FAMILY)) + goto err_free; + + printf(" TRACE: %d %08x %s:%s", nftnl_trace_get_u32(nlt, NFTNL_TABLE_FAMILY), + nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID), + nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE), + nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN)); + + switch (nftnl_trace_get_u32(nlt, NFTNL_TRACE_TYPE)) { + case NFT_TRACETYPE_RULE: + printf(":rule:0x%llx ", (unsigned long long)nftnl_trace_get_u64(nlt, NFTNL_TRACE_RULE_HANDLE)); + + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_RULE_HANDLE)) + trace_print_rule(nlt, arg); + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_LL_HEADER) || + nftnl_trace_is_set(nlt, NFTNL_TRACE_NETWORK_HEADER)) + trace_print_packet(nlt, arg); + break; + case NFT_TRACETYPE_POLICY: { + uint32_t verdict; + + printf(":policy:"); + verdict = nftnl_trace_get_u32(nlt, NFTNL_TRACE_VERDICT); + + switch(verdict) { + case NF_ACCEPT: + printf("ACCEPT"); + break; + break; + case NF_DROP: + printf("DROP"); + break; + default: /* Would be a kernel bug - policy must be ACCEPT or DROP */ + printf("%d", verdict); + break; + } + } + break; + case NFT_TRACETYPE_RETURN: + printf(":return:"); + trace_print_return(nlt); + break; + } + puts(""); +err_free: + nftnl_trace_free(nlt); +err: + return MNL_CB_OK; +} + +static int monitor_cb(const struct nlmsghdr *nlh, void *data) +{ + uint32_t type = nlh->nlmsg_type & 0xFF; + int ret = MNL_CB_OK; + + switch(type) { + case NFT_MSG_NEWTABLE: + case NFT_MSG_DELTABLE: + ret = table_cb(nlh, data); + break; + case NFT_MSG_NEWCHAIN: + case NFT_MSG_DELCHAIN: + ret = chain_cb(nlh, data); + break; + case NFT_MSG_NEWRULE: + case NFT_MSG_DELRULE: + ret = rule_cb(nlh, data); + break; + case NFT_MSG_NEWGEN: + ret = newgen_cb(nlh, data); + break; + case NFT_MSG_TRACE: + ret = trace_cb(nlh, data); + break; + } + + return ret; +} + +static const struct option options[] = { + {.name = "counters", .has_arg = false, .val = 'c'}, + {.name = "trace", .has_arg = false, .val = 't'}, + {.name = "monitor", .has_arg = false, .val = 'm'}, + {.name = "ipv4", .has_arg = false, .val = '4'}, + {.name = "ipv6", .has_arg = false, .val = '6'}, + {NULL}, +}; + +static void print_usage(void) +{ + printf("%s %s\n", xtables_globals.program_name, + xtables_globals.program_version); + printf("Usage: %s [ -t | -e ]\n" + " --trace -t trace ruleset traversal of packets tagged via -j TRACE rule\n" + " --event -e show events taht modify the ruleset\n" + "Optional arguments:\n" + " --ipv4 -4 only monitor ipv4\n" + " --ipv6 -6 only monitor ipv6\n" + " --counters -c show counters in rules\n" + + , xtables_globals.program_name); + exit(EXIT_FAILURE); +} + +int xtables_monitor_main(int argc, char *argv[]) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + uint32_t nfgroup = 0; + struct cb_arg cb_arg; + int ret, c; + + xtables_globals.program_name = "xtables-monitor"; + /* XXX xtables_init_all does several things we don't want */ + c = xtables_init_all(&xtables_globals, NFPROTO_IPV4); + if (c < 0) { + fprintf(stderr, "%s/%s Failed to initialize xtables\n", + xtables_globals.program_name, + xtables_globals.program_version); + exit(1); + } +#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) + init_extensions(); + init_extensions4(); +#endif + + memset(&cb_arg, 0, sizeof(cb_arg)); + opterr = 0; + while ((c = getopt_long(argc, argv, "ceht46", options, NULL)) != -1) { + switch (c) { + case 'c': + counters = true; + break; + case 't': + trace = true; + break; + case 'e': + events = true; + break; + case 'h': + print_usage(); + exit(0); + case '4': + cb_arg.nfproto = NFPROTO_IPV4; + break; + case '6': + cb_arg.nfproto = NFPROTO_IPV6; + break; + default: + fprintf(stderr, "xtables-monitor %s: Bad argument.\n", XTABLES_VERSION); + fprintf(stderr, "Try `xtables-monitor -h' for more information."); + exit(PARAMETER_PROBLEM); + } + } + + if (trace) + nfgroup |= 1 << (NFNLGRP_NFTRACE - 1); + if (events) + nfgroup |= 1 << (NFNLGRP_NFTABLES - 1); + + if (nfgroup == 0) { + print_usage(); + exit(EXIT_FAILURE); + } + + nl = mnl_socket_open(NETLINK_NETFILTER); + if (nl == NULL) { + perror("cannot open nfnetlink socket"); + exit(EXIT_FAILURE); + } + + if (mnl_socket_bind(nl, nfgroup, MNL_SOCKET_AUTOPID) < 0) { + perror("cannot bind to nfnetlink socket"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, 0, 0, monitor_cb, &cb_arg); + if (ret <= 0) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) { + perror("cannot receive from nfnetlink socket"); + exit(EXIT_FAILURE); + } + mnl_socket_close(nl); + + return EXIT_SUCCESS; +} + diff --git a/iptables/xtables-multi.c b/iptables/xtables-multi.c index 30391e7fec7f..e90885ddb0fd 100644 --- a/iptables/xtables-multi.c +++ b/iptables/xtables-multi.c @@ -41,7 +41,6 @@ static const struct subcommand multi_subcommands[] = { {"xtables-save", xtables_save_main}, {"xtables-restore", xtables_restore_main}, {"xtables-config", xtables_config_main}, - {"xtables-events", xtables_events_main}, {"xtables-arp", xtables_arp_main}, {"xtables-ebtables", xtables_eb_main}, #endif diff --git a/iptables/xtables-multi.h b/iptables/xtables-multi.h index f0c14ea42ed4..82ee9c9dbcab 100644 --- a/iptables/xtables-multi.h +++ b/iptables/xtables-multi.h @@ -17,7 +17,7 @@ extern int xtables_ip6_xlate_restore_main(int, char **); extern int xtables_arp_main(int, char **); extern int xtables_eb_main(int, char **); extern int xtables_config_main(int, char **); -extern int xtables_events_main(int, char **); +extern int xtables_monitor_main(int, char **); #endif #endif /* _XTABLES_MULTI_H */ -- 2.17.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