summaryrefslogtreecommitdiffstats
path: root/lib/debug.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/debug.c')
-rw-r--r--lib/debug.c268
1 files changed, 268 insertions, 0 deletions
diff --git a/lib/debug.c b/lib/debug.c
new file mode 100644
index 0000000..174567d
--- /dev/null
+++ b/lib/debug.c
@@ -0,0 +1,268 @@
+/* Copyright 2011 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <arpa/inet.h> /* inet_ntop */
+#include <libmnl/libmnl.h> /* libmnl backend */
+
+struct ipset_attrname {
+ const char *name;
+};
+
+static const struct ipset_attrname cmdattr2name[] = {
+ [IPSET_ATTR_PROTOCOL] = { .name = "PROTOCOL" },
+ [IPSET_ATTR_SETNAME] = { .name = "SETNAME" },
+ [IPSET_ATTR_TYPENAME] = { .name = "TYPENAME" },
+ [IPSET_ATTR_REVISION] = { .name = "REVISION" },
+ [IPSET_ATTR_FAMILY] = { .name = "FAMILY" },
+ [IPSET_ATTR_FLAGS] = { .name = "FLAGS" },
+ [IPSET_ATTR_DATA] = { .name = "DATA" },
+ [IPSET_ATTR_ADT] = { .name = "ADT" },
+ [IPSET_ATTR_LINENO] = { .name = "LINENO" },
+ [IPSET_ATTR_PROTOCOL_MIN] = { .name = "PROTO_MIN" },
+};
+
+static const struct ipset_attrname createattr2name[] = {
+ [IPSET_ATTR_IP] = { .name = "IP" },
+ [IPSET_ATTR_IP_TO] = { .name = "IP_TO" },
+ [IPSET_ATTR_CIDR] = { .name = "CIDR" },
+ [IPSET_ATTR_PORT] = { .name = "PORT" },
+ [IPSET_ATTR_PORT_TO] = { .name = "PORT_TO" },
+ [IPSET_ATTR_TIMEOUT] = { .name = "TIMEOUT" },
+ [IPSET_ATTR_PROTO] = { .name = "PROTO" },
+ [IPSET_ATTR_CADT_FLAGS] = { .name = "CADT_FLAGS" },
+ [IPSET_ATTR_CADT_LINENO] = { .name = "CADT_LINENO" },
+ [IPSET_ATTR_GC] = { .name = "GC" },
+ [IPSET_ATTR_HASHSIZE] = { .name = "HASHSIZE" },
+ [IPSET_ATTR_MAXELEM] = { .name = "MAXELEM" },
+ [IPSET_ATTR_NETMASK] = { .name = "NETMASK" },
+ [IPSET_ATTR_PROBES] = { .name = "PROBES" },
+ [IPSET_ATTR_RESIZE] = { .name = "RESIZE" },
+ [IPSET_ATTR_SIZE] = { .name = "SIZE" },
+ [IPSET_ATTR_ELEMENTS] = { .name = "ELEMENTS" },
+ [IPSET_ATTR_REFERENCES] = { .name = "REFERENCES" },
+ [IPSET_ATTR_MEMSIZE] = { .name = "MEMSIZE" },
+};
+
+static const struct ipset_attrname adtattr2name[] = {
+ [IPSET_ATTR_IP] = { .name = "IP" },
+ [IPSET_ATTR_IP_TO] = { .name = "IP_TO" },
+ [IPSET_ATTR_CIDR] = { .name = "CIDR" },
+ [IPSET_ATTR_PORT] = { .name = "PORT" },
+ [IPSET_ATTR_PORT_TO] = { .name = "PORT_TO" },
+ [IPSET_ATTR_TIMEOUT] = { .name = "TIMEOUT" },
+ [IPSET_ATTR_PROTO] = { .name = "PROTO" },
+ [IPSET_ATTR_CADT_FLAGS] = { .name = "CADT_FLAGS" },
+ [IPSET_ATTR_CADT_LINENO] = { .name = "CADT_LINENO" },
+ [IPSET_ATTR_ETHER] = { .name = "ETHER" },
+ [IPSET_ATTR_NAME] = { .name = "NAME" },
+ [IPSET_ATTR_NAMEREF] = { .name = "NAMEREF" },
+ [IPSET_ATTR_IP2] = { .name = "IP2" },
+ [IPSET_ATTR_CIDR2] = { .name = "CIDR2" },
+ [IPSET_ATTR_IP2_TO] = { .name = "IP2_TO" },
+};
+
+static void
+debug_cadt_attrs(int max, const struct ipset_attr_policy *policy,
+ const struct ipset_attrname attr2name[],
+ struct nlattr *nla[])
+{
+ uint32_t v;
+ int i;
+
+ fprintf(stderr,"\t\t%s attributes:\n", policy == create_attrs ? "CREATE" : "ADT");
+ for (i = IPSET_ATTR_UNSPEC + 1; i <= max; i++) {
+ if (!nla[i])
+ continue;
+ switch (policy[i].type) {
+ case MNL_TYPE_U8:
+ v = * (uint8_t *) mnl_attr_get_payload(nla[i]);
+ fprintf(stderr, "\t\t%s: %u\n",
+ attr2name[i].name, v);
+ break;
+ case MNL_TYPE_U16:
+ v = * (uint16_t *) mnl_attr_get_payload(nla[i]);
+ fprintf(stderr, "\t\t%s: %u\n",
+ attr2name[i].name, ntohs(v));
+ break;
+ case MNL_TYPE_U32:
+ v = * (uint32_t *) mnl_attr_get_payload(nla[i]);
+ fprintf(stderr, "\t\t%s: %u\n",
+ attr2name[i].name, ntohl(v));
+ break;
+ case MNL_TYPE_NUL_STRING:
+ fprintf(stderr, "\t\t%s: %s\n",
+ attr2name[i].name,
+ (const char *) mnl_attr_get_payload(nla[i]));
+ break;
+ case MNL_TYPE_NESTED: {
+ struct nlattr *ipattr[IPSET_ATTR_IPADDR_MAX+1] = {};
+ char addr[INET6_ADDRSTRLEN];
+ void *d;
+
+ if (mnl_attr_parse_nested(nla[i], ipaddr_attr_cb, ipattr) < 0) {
+ fprintf(stderr, "\t\tIPADDR: cannot validate and parse attributes\n");
+ continue;
+ }
+ if (ipattr[IPSET_ATTR_IPADDR_IPV4]) {
+ d = mnl_attr_get_payload(ipattr[IPSET_ATTR_IPADDR_IPV4]);
+
+ inet_ntop(AF_INET, d, addr, INET6_ADDRSTRLEN);
+ fprintf(stderr, "\t\t%s: %s\n",
+ attr2name[i].name, addr);
+ } else if (ipattr[IPSET_ATTR_IPADDR_IPV6]) {
+ d = mnl_attr_get_payload(ipattr[IPSET_ATTR_IPADDR_IPV6]);
+
+ inet_ntop(AF_INET6, d, addr, INET6_ADDRSTRLEN);
+ fprintf(stderr, "\t\t%s: %s\n",
+ attr2name[i].name, addr);
+ }
+ break;
+ }
+ default:
+ fprintf(stderr, "\t\t%s: unresolved!\n",
+ attr2name[i].name);
+ }
+ }
+}
+
+static void
+debug_cmd_attrs(int cmd, struct nlattr *nla[])
+{
+ struct nlattr *adt[IPSET_ATTR_ADT_MAX+1] = {};
+ struct nlattr *cattr[IPSET_ATTR_CREATE_MAX+1] = {};
+ uint32_t v;
+ int i;
+
+ fprintf(stderr,"\tCommand attributes:\n");
+ for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_CMD_MAX; i++) {
+ if (!nla[i])
+ continue;
+ switch (cmd_attrs[i].type) {
+ case MNL_TYPE_U8:
+ v = * (uint8_t *) mnl_attr_get_payload(nla[i]);
+ fprintf(stderr, "\t%s: %u\n",
+ cmdattr2name[i].name, v);
+ break;
+ case MNL_TYPE_U16:
+ v = * (uint16_t *) mnl_attr_get_payload(nla[i]);
+ fprintf(stderr, "\t%s: %u\n",
+ cmdattr2name[i].name, ntohs(v));
+ break;
+ case MNL_TYPE_U32:
+ v = * (uint32_t *) mnl_attr_get_payload(nla[i]);
+ fprintf(stderr, "\t%s: %u\n",
+ cmdattr2name[i].name, ntohl(v));
+ break;
+ case MNL_TYPE_NUL_STRING:
+ fprintf(stderr, "\t%s: %s\n",
+ cmdattr2name[i].name,
+ (const char *) mnl_attr_get_payload(nla[i]));
+ break;
+ case MNL_TYPE_NESTED:
+ if (i == IPSET_ATTR_DATA) {
+ switch (cmd) {
+ case IPSET_CMD_ADD:
+ case IPSET_CMD_DEL:
+ case IPSET_CMD_TEST:
+ if (mnl_attr_parse_nested(nla[i], adt_attr_cb, adt) < 0) {
+ fprintf(stderr, "\tADT: cannot validate and parse attributes\n");
+ continue;
+ }
+ debug_cadt_attrs(IPSET_ATTR_ADT_MAX,
+ adt_attrs,
+ adtattr2name,
+ adt);
+ break;
+ default:
+ if (mnl_attr_parse_nested(nla[i], create_attr_cb, cattr) < 0) {
+ fprintf(stderr, "\tCREATE: cannot validate and parse attributes\n");
+ continue;
+ }
+ debug_cadt_attrs(IPSET_ATTR_CREATE_MAX,
+ create_attrs,
+ createattr2name,
+ cattr);
+ }
+ } else {
+ struct nlattr *tb;
+ mnl_attr_for_each_nested(tb, nla[i]) {
+ memset(adt, 0, sizeof(adt));
+ if (mnl_attr_parse_nested(tb, adt_attr_cb, adt) < 0) {
+ fprintf(stderr, "\tADT: cannot validate and parse attributes\n");
+ continue;
+ }
+ debug_cadt_attrs(IPSET_ATTR_ADT_MAX,
+ adt_attrs,
+ adtattr2name,
+ adt);
+ }
+ }
+ break;
+ default:
+ fprintf(stderr, "\t%s: unresolved!\n",
+ cmdattr2name[i].name);
+ }
+ }
+}
+
+void
+ipset_debug_msg(const char *dir, void *buffer, int len)
+{
+ const struct nlmsghdr *nlh = buffer;
+ struct nlattr *nla[IPSET_ATTR_CMD_MAX+1] = {};
+ int cmd, nfmsglen = MNL_ALIGN(sizeof(struct nfgenmsg));
+
+ debug = 0;
+ while (mnl_nlmsg_ok(nlh, len)) {
+ switch (nlh->nlmsg_type) {
+ case NLMSG_NOOP:
+ case NLMSG_DONE:
+ case NLMSG_OVERRUN:
+ fprintf(stderr, "Message header: %s msg %s\n"
+ "\tlen %d\n"
+ "\tseq %u\n",
+ dir,
+ nlh->nlmsg_type == NLMSG_NOOP ? "NOOP" :
+ nlh->nlmsg_type == NLMSG_DONE ? "DONE" : "OVERRUN",
+ len, nlh->nlmsg_seq);
+ goto next_msg;
+ case NLMSG_ERROR: {
+ const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
+ fprintf(stderr, "Message header: %s msg ERROR\n"
+ "\tlen %d\n"
+ "\terrcode %d\n"
+ "\tseq %u\n",
+ dir, len, err->error, nlh->nlmsg_seq);
+ goto next_msg;
+ }
+ default:
+ ;
+ }
+ cmd = ipset_get_nlmsg_type(nlh);
+ fprintf(stderr, "Message header: %s cmd %s (%d)\n"
+ "\tlen %d\n"
+ "\tflag %s\n"
+ "\tseq %u\n",
+ dir,
+ cmd <= IPSET_CMD_NONE ? "NONE!" :
+ cmd >= IPSET_CMD_MAX ? "MAX!" : cmd2name[cmd], cmd,
+ len,
+ !(nlh->nlmsg_flags & NLM_F_EXCL) ? "EXIST" : "none",
+ nlh->nlmsg_seq);
+ if (cmd <= IPSET_CMD_NONE || cmd >= IPSET_CMD_MAX)
+ goto next_msg;
+ memset(nla, 0, sizeof(nla));
+ if (mnl_attr_parse(nlh, nfmsglen, cmd_attr_cb, nla) < MNL_CB_STOP) {
+ fprintf(stderr, "\tcannot validate and parse attributes\n");
+ goto next_msg;
+ }
+ debug_cmd_attrs(cmd, nla);
+next_msg:
+ nlh = mnl_nlmsg_next(nlh, &len);
+ }
+ debug = 1;
+}