| /* |
| * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org> |
| * |
| * 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/in.h> |
| #include <getopt.h> |
| |
| #include <linux/netfilter/nfnetlink.h> |
| #include <linux/netfilter/nf_tables.h> |
| |
| #include <libmnl/libmnl.h> |
| #include <libnftables/table.h> |
| #include <libnftables/chain.h> |
| #include <libnftables/rule.h> |
| |
| #include <include/xtables.h> |
| #include "iptables.h" /* for xtables_globals */ |
| #include "xtables-multi.h" |
| #include "nft.h" |
| |
| static int table_cb(const struct nlmsghdr *nlh, int type) |
| { |
| struct nft_table *t; |
| char buf[4096]; |
| |
| t = nft_table_alloc(); |
| if (t == NULL) { |
| perror("OOM"); |
| goto err; |
| } |
| |
| if (nft_table_nlmsg_parse(nlh, t) < 0) { |
| perror("nft_table_nlmsg_parse"); |
| goto err_free; |
| } |
| |
| nft_table_snprintf(buf, sizeof(buf), t, NFT_TABLE_O_DEFAULT, 0); |
| /* FIXME: define syntax to represent table events */ |
| printf("# [table: %s]\t%s\n", type == NFT_MSG_NEWTABLE ? "NEW" : "DEL", buf); |
| |
| err_free: |
| nft_table_free(t); |
| err: |
| return MNL_CB_OK; |
| } |
| |
| static bool counters; |
| |
| static int rule_cb(const struct nlmsghdr *nlh, int type) |
| { |
| struct iptables_command_state cs = {}; |
| struct nft_rule *r; |
| |
| r = nft_rule_alloc(); |
| if (r == NULL) { |
| perror("OOM"); |
| goto err; |
| } |
| |
| if (nft_rule_nlmsg_parse(nlh, r) < 0) { |
| perror("nft_rule_nlmsg_parse"); |
| goto err_free; |
| } |
| |
| nft_rule_to_iptables_command_state(r, &cs); |
| |
| switch(nft_rule_attr_get_u8(r, NFT_RULE_ATTR_FAMILY)) { |
| case AF_INET: |
| printf("-4 "); |
| break; |
| case AF_INET6: |
| printf("-6 "); |
| break; |
| default: |
| break; |
| } |
| |
| |
| nft_rule_print_save(&cs, r, |
| type == NFT_MSG_NEWRULE ? NFT_RULE_APPEND : |
| NFT_RULE_DEL, |
| counters ? 0 : FMT_NOCOUNTS); |
| err_free: |
| nft_rule_free(r); |
| err: |
| return MNL_CB_OK; |
| } |
| |
| static int chain_cb(const struct nlmsghdr *nlh, int type) |
| { |
| struct nft_chain *t; |
| char buf[4096]; |
| |
| t = nft_chain_alloc(); |
| if (t == NULL) { |
| perror("OOM"); |
| goto err; |
| } |
| |
| if (nft_chain_nlmsg_parse(nlh, t) < 0) { |
| perror("nft_chain_nlmsg_parse"); |
| goto err_free; |
| } |
| |
| nft_chain_snprintf(buf, sizeof(buf), t, NFT_CHAIN_O_DEFAULT, 0); |
| /* FIXME: define syntax to represent chain events */ |
| printf("# [chain: %s]\t%s\n", type == NFT_MSG_NEWCHAIN ? "NEW" : "DEL", buf); |
| |
| err_free: |
| nft_chain_free(t); |
| err: |
| return MNL_CB_OK; |
| } |
| |
| static int events_cb(const struct nlmsghdr *nlh, void *data) |
| { |
| int ret = MNL_CB_OK; |
| int type = nlh->nlmsg_type & 0xFF; |
| |
| switch(type) { |
| case NFT_MSG_NEWTABLE: |
| case NFT_MSG_DELTABLE: |
| ret = table_cb(nlh, type); |
| break; |
| case NFT_MSG_NEWCHAIN: |
| case NFT_MSG_DELCHAIN: |
| ret = chain_cb(nlh, type); |
| break; |
| case NFT_MSG_NEWRULE: |
| case NFT_MSG_DELRULE: |
| ret = rule_cb(nlh, type); |
| break; |
| } |
| |
| return ret; |
| } |
| |
| static const struct option options[] = { |
| {.name = "counters", .has_arg = false, .val = 'c'}, |
| {NULL}, |
| }; |
| |
| static void print_usage(const char *name, const char *version) |
| { |
| fprintf(stderr, "Usage: %s [-c]\n" |
| " [ --counters ]\n", name); |
| exit(EXIT_FAILURE); |
| } |
| |
| int xtables_events_main(int argc, char *argv[]) |
| { |
| struct mnl_socket *nl; |
| char buf[MNL_SOCKET_BUFFER_SIZE]; |
| int ret, c; |
| |
| xtables_globals.program_name = "xtables-events"; |
| /* 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 |
| |
| opterr = 0; |
| while ((c = getopt_long(argc, argv, "c", options, NULL)) != -1) { |
| switch (c) { |
| case 'c': |
| counters = true; |
| break; |
| default: |
| print_usage(argv[0], XTABLES_VERSION); |
| exit(EXIT_FAILURE); |
| } |
| } |
| |
| nl = mnl_socket_open(NETLINK_NETFILTER); |
| if (nl == NULL) { |
| perror("mnl_socket_open"); |
| exit(EXIT_FAILURE); |
| } |
| |
| if (mnl_socket_bind(nl, (1 << (NFNLGRP_NFTABLES-1)), MNL_SOCKET_AUTOPID) < 0) { |
| perror("mnl_socket_bind"); |
| exit(EXIT_FAILURE); |
| } |
| |
| ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); |
| while (ret > 0) { |
| ret = mnl_cb_run(buf, ret, 0, 0, events_cb, NULL); |
| if (ret <= 0) |
| break; |
| ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); |
| } |
| if (ret == -1) { |
| perror("error"); |
| exit(EXIT_FAILURE); |
| } |
| mnl_socket_close(nl); |
| |
| return EXIT_SUCCESS; |
| } |