From eb77f0db6a95691bc62ce9669c27f7cfa173bee5 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Tue, 24 May 2011 09:33:38 +0200 Subject: Protocol-level debugging support added --- lib/debug.c | 268 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/mnl.c | 8 +- lib/session.c | 16 +++- 3 files changed, 286 insertions(+), 6 deletions(-) create mode 100644 lib/debug.c (limited to 'lib') 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 /* inet_ntop */ +#include /* 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 -- cgit v1.2.3