summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2011-05-24 09:33:38 +0200
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2011-05-24 09:33:38 +0200
commiteb77f0db6a95691bc62ce9669c27f7cfa173bee5 (patch)
treef682b6f75397d3fca25da6331c9a64db5c656b75 /lib
parentbacee4529c3fdd43a02ee96e636a04c2e81d4565 (diff)
Protocol-level debugging support added
Diffstat (limited to 'lib')
-rw-r--r--lib/debug.c268
-rw-r--r--lib/mnl.c8
-rw-r--r--lib/session.c16
3 files changed, 286 insertions, 6 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;
+}
diff --git a/lib/mnl.c b/lib/mnl.c
index 75cadb6..d18ec04 100644
--- a/lib/mnl.c
+++ b/lib/mnl.c
@@ -92,12 +92,16 @@ ipset_mnl_query(struct ipset_handle *handle, void *buffer, size_t len)
assert(handle);
assert(buffer);
+#ifdef IPSET_DEBUG
+ ipset_debug_msg("sent", nlh, nlh->nlmsg_len);
+#endif
if (mnl_socket_sendto(handle->h, nlh, nlh->nlmsg_len) < 0)
return -ECOMM;
- D("message sent");
ret = mnl_socket_recvfrom(handle->h, buffer, len);
- D("message received, ret: %d", ret);
+#ifdef IPSET_DEBUG
+ ipset_debug_msg("received", buffer, ret);
+#endif
while (ret > 0) {
ret = mnl_cb_run2(buffer, ret,
handle->seq, handle->portid,
diff --git a/lib/session.c b/lib/session.c
index a9c7c33..bab1846 100644
--- a/lib/session.c
+++ b/lib/session.c
@@ -485,6 +485,10 @@ static const struct ipset_attr_policy ipaddr_attrs[] = {
},
};
+#ifdef IPSET_DEBUG
+static int debug = 1;
+#endif
+
static int
generic_data_attr_cb(const struct nlattr *attr, void *data,
int attr_max, const struct ipset_attr_policy *policy)
@@ -492,14 +496,14 @@ generic_data_attr_cb(const struct nlattr *attr, void *data,
const struct nlattr **tb = data;
int type = mnl_attr_get_type(attr);
- D("attr type: %u, len %u", type, attr->nla_len);
+ IF_D(debug, "attr type: %u, len %u", type, attr->nla_len);
if (mnl_attr_type_valid(attr, attr_max) < 0) {
- D("attr type: %u INVALID", type);
+ IF_D(debug, "attr type: %u INVALID", type);
return MNL_CB_ERROR;
}
if (mnl_attr_validate(attr, policy[type].type) < 0) {
- D("attr type: %u POLICY, attrlen %u", type,
- mnl_attr_get_payload_len(attr));
+ IF_D(debug, "attr type: %u POLICY, attrlen %u", type,
+ mnl_attr_get_payload_len(attr));
return MNL_CB_ERROR;
}
if (policy[type].type == MNL_TYPE_NUL_STRING
@@ -1969,3 +1973,7 @@ ipset_session_fini(struct ipset_session *session)
free(session);
return 0;
}
+
+#ifdef IPSET_DEBUG
+#include "debug.c"
+#endif