/* * (C) 2005-2011 by Pablo Neira Ayuso * * 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. */ #include "internal/internal.h" /* * XML output sample: * * * * * 192.168.0.1 * 192.168.0.2 * * * 80 * 56665 * * * 10 * 1 * * * * * 192.168.0.2 * 192.168.0.1 * * * 80 * 56665 * * * 5029 * 12 * * * * ESTABLISHED * 100 * 1 * 0 * 453281439 * 1 * * * */ const char *__proto2str(u_int8_t protonum) { return proto2str[protonum] ? proto2str[protonum] : "unknown"; } const char *__l3proto2str(u_int8_t protonum) { return l3proto2str[protonum] ? l3proto2str[protonum] : "unknown"; } static int __snprintf_ipv4_xml(char *buf, unsigned int len, const struct __nfct_tuple *tuple, unsigned int type) { struct in_addr addr = { .s_addr = (type == __ADDR_SRC) ? tuple->src.v4 : tuple->dst.v4, }; return snprintf(buf, len, "%s", inet_ntoa(addr)); } static int __snprintf_ipv6_xml(char *buf, unsigned int len, const struct __nfct_tuple *tuple, unsigned int type) { struct in6_addr addr; static char tmp[INET6_ADDRSTRLEN]; const void *p = (type == __ADDR_SRC) ? &tuple->src.v6 : &tuple->dst.v6; memcpy(&addr, p, sizeof(struct in6_addr)); if (!inet_ntop(AF_INET6, &addr, tmp, sizeof(tmp))) return -1; return snprintf(buf, len, "%s", tmp); } int __snprintf_addr_xml(char *buf, unsigned int len, const struct __nfct_tuple *tuple, enum __nfct_addr type) { int ret; unsigned int size = 0, offset = 0; const char *tag = (type == __ADDR_SRC) ? "src" : "dst"; ret = snprintf(buf, len, "<%s>", tag); BUFFER_SIZE(ret, size, len, offset); switch (tuple->l3protonum) { case AF_INET: ret = __snprintf_ipv4_xml(buf+offset, len, tuple, type); BUFFER_SIZE(ret, size, len, offset); break; case AF_INET6: ret = __snprintf_ipv6_xml(buf+offset, len, tuple, type); BUFFER_SIZE(ret, size, len, offset); break; } ret = snprintf(buf+offset, len, "", tag); BUFFER_SIZE(ret, size, len, offset); return size; } int __snprintf_proto_xml(char *buf, unsigned int len, const struct __nfct_tuple *tuple, enum __nfct_addr type) { int ret = 0; unsigned int size = 0, offset = 0; switch(tuple->protonum) { case IPPROTO_TCP: case IPPROTO_UDP: case IPPROTO_UDPLITE: case IPPROTO_SCTP: case IPPROTO_DCCP: if (type == __ADDR_SRC) { ret = snprintf(buf, len, "%u", ntohs(tuple->l4src.tcp.port)); BUFFER_SIZE(ret, size, len, offset); } else { ret = snprintf(buf, len, "%u", ntohs(tuple->l4dst.tcp.port)); BUFFER_SIZE(ret, size, len, offset); } break; case IPPROTO_GRE: if (type == __ADDR_SRC) { ret = snprintf(buf, len, "0x%x", ntohs(tuple->l4src.all)); BUFFER_SIZE(ret, size, len, offset); } else { ret = snprintf(buf, len, "0x%x", ntohs(tuple->l4dst.all)); BUFFER_SIZE(ret, size, len, offset); } break; } return ret; } static int __snprintf_counters_xml(char *buf, unsigned int len, const struct nf_conntrack *ct, unsigned int type) { int ret; unsigned int size = 0, offset = 0; ret = snprintf(buf, len, "%llu", (unsigned long long)ct->counters[type].packets); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, "%llu", (unsigned long long)ct->counters[type].bytes); BUFFER_SIZE(ret, size, len, offset); return size; } static int __snprintf_timestamp_start(char *buf, unsigned int len, const struct nf_conntrack *ct) { int ret; unsigned int size = 0, offset = 0; ret = snprintf(buf, len, "%llu", (unsigned long long)ct->timestamp.start); BUFFER_SIZE(ret, size, len, offset); return size; } static int __snprintf_timestamp_stop(char *buf, unsigned int len, const struct nf_conntrack *ct) { int ret; unsigned int size = 0, offset = 0; ret = snprintf(buf, len, "%llu", (unsigned long long)ct->timestamp.stop); BUFFER_SIZE(ret, size, len, offset); return size; } static int __snprintf_deltatime_now(char *buf, unsigned int len, const struct nf_conntrack *ct) { int ret; unsigned int size = 0, offset = 0; time_t now, delta_time; time(&now); delta_time = now - (time_t)(ct->timestamp.start / NSEC_PER_SEC); ret = snprintf(buf+offset, len, "%llu", (unsigned long long)delta_time); BUFFER_SIZE(ret, size, len, offset); return size; } static int __snprintf_deltatime(char *buf, unsigned int len, const struct nf_conntrack *ct) { int ret; unsigned int size = 0, offset = 0; time_t delta_time = (time_t)((ct->timestamp.stop - ct->timestamp.start) / NSEC_PER_SEC); ret = snprintf(buf+offset, len, "%llu", (unsigned long long)delta_time); BUFFER_SIZE(ret, size, len, offset); return size; } static int __snprintf_helper_name(char *buf, unsigned int len, const struct nf_conntrack *ct) { int ret; unsigned int size = 0, offset = 0; ret = snprintf(buf+offset, len, "%s", ct->helper_name); BUFFER_SIZE(ret, size, len, offset); return size; } int __snprintf_localtime_xml(char *buf, unsigned int len, const struct tm *tm) { int ret = 0; unsigned int size = 0, offset = 0; ret = snprintf(buf+offset, len, "%d", tm->tm_hour); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, "%02d", tm->tm_min); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, "%02d", tm->tm_sec); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, "%d", tm->tm_wday + 1); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, "%d", tm->tm_mday); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, "%d", tm->tm_mon + 1); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, "%d", 1900 + tm->tm_year); BUFFER_SIZE(ret, size, len, offset); return size; } static int __snprintf_tuple_xml(char *buf, unsigned int len, const struct nf_conntrack *ct, unsigned int dir) { int ret; unsigned int size = 0, offset = 0; const struct __nfct_tuple *tuple = NULL; switch(dir) { case __DIR_ORIG: tuple = &ct->head.orig; break; case __DIR_REPL: tuple = &ct->repl; break; } ret = snprintf(buf, len, "", dir == __DIR_ORIG ? "original" : "reply"); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, "", tuple->l3protonum, __l3proto2str(tuple->l3protonum)); BUFFER_SIZE(ret, size, len, offset); ret = __snprintf_addr_xml(buf+offset, len, tuple, __ADDR_SRC); BUFFER_SIZE(ret, size, len, offset); ret = __snprintf_addr_xml(buf+offset, len, tuple, __ADDR_DST); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, ""); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, "", tuple->protonum, __proto2str(tuple->protonum)); BUFFER_SIZE(ret, size, len, offset); ret = __snprintf_proto_xml(buf+offset, len, tuple, __DIR_ORIG); BUFFER_SIZE(ret, size, len, offset); ret = __snprintf_proto_xml(buf+offset, len, tuple, __DIR_REPL); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, ""); BUFFER_SIZE(ret, size, len, offset); if (test_bit(ATTR_ORIG_COUNTER_PACKETS, ct->head.set) && test_bit(ATTR_ORIG_COUNTER_BYTES, ct->head.set)) { ret = snprintf(buf+offset, len, ""); BUFFER_SIZE(ret, size, len, offset); ret = __snprintf_counters_xml(buf+offset, len, ct, dir); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, ""); BUFFER_SIZE(ret, size, len, offset); } ret = snprintf(buf+offset, len, ""); BUFFER_SIZE(ret, size, len, offset); return size; } int __snprintf_conntrack_xml(char *buf, unsigned int len, const struct nf_conntrack *ct, const unsigned int msg_type, const unsigned int flags) { int ret = 0; unsigned int size = 0, offset = 0; switch(msg_type) { case NFCT_T_NEW: ret = snprintf(buf, len, ""); break; case NFCT_T_UPDATE: ret = snprintf(buf, len, ""); break; case NFCT_T_DESTROY: ret = snprintf(buf, len, ""); break; default: ret = snprintf(buf, len, ""); break; } BUFFER_SIZE(ret, size, len, offset); ret = __snprintf_tuple_xml(buf+offset, len, ct, __DIR_ORIG); BUFFER_SIZE(ret, size, len, offset); ret = __snprintf_tuple_xml(buf+offset, len, ct, __DIR_REPL); BUFFER_SIZE(ret, size, len, offset); if (test_bit(ATTR_TCP_STATE, ct->head.set) || test_bit(ATTR_SCTP_STATE, ct->head.set) || test_bit(ATTR_DCCP_STATE, ct->head.set) || test_bit(ATTR_TIMEOUT, ct->head.set) || test_bit(ATTR_MARK, ct->head.set) || test_bit(ATTR_SECMARK, ct->head.set) || test_bit(ATTR_ZONE, ct->head.set) || test_bit(ATTR_USE, ct->head.set) || test_bit(ATTR_STATUS, ct->head.set) || test_bit(ATTR_ID, ct->head.set) || test_bit(ATTR_TIMESTAMP_START, ct->head.set) || test_bit(ATTR_TIMESTAMP_STOP, ct->head.set)) { ret = snprintf(buf+offset, len, ""); BUFFER_SIZE(ret, size, len, offset); } if (test_bit(ATTR_TCP_STATE, ct->head.set)) { ret = snprintf(buf+offset, len, "%s", ct->protoinfo.tcp.state < TCP_CONNTRACK_MAX ? states[ct->protoinfo.tcp.state] : states[TCP_CONNTRACK_NONE]); BUFFER_SIZE(ret, size, len, offset); } if (test_bit(ATTR_SCTP_STATE, ct->head.set)) { ret = snprintf(buf+offset, len, "%s", ct->protoinfo.sctp.state < SCTP_CONNTRACK_MAX ? states[ct->protoinfo.sctp.state] : states[SCTP_CONNTRACK_NONE]); BUFFER_SIZE(ret, size, len, offset); } if (test_bit(ATTR_DCCP_STATE, ct->head.set)) { ret = snprintf(buf+offset, len, "%s", ct->protoinfo.sctp.state < DCCP_CONNTRACK_MAX ? states[ct->protoinfo.dccp.state] : states[DCCP_CONNTRACK_NONE]); BUFFER_SIZE(ret, size, len, offset); } if (test_bit(ATTR_TIMEOUT, ct->head.set)) { ret = snprintf(buf+offset, len, "%u", ct->timeout); BUFFER_SIZE(ret, size, len, offset); } if (test_bit(ATTR_MARK, ct->head.set)) { ret = snprintf(buf+offset, len, "%u", ct->mark); BUFFER_SIZE(ret, size, len, offset); } if (test_bit(ATTR_SECMARK, ct->head.set)) { ret = snprintf(buf+offset, len, "%u", ct->secmark); BUFFER_SIZE(ret, size, len, offset); } if (test_bit(ATTR_SECCTX, ct->head.set)) { ret = snprintf(buf+offset, len, "%s", ct->secctx); BUFFER_SIZE(ret, size, len, offset); } if (test_bit(ATTR_ZONE, ct->head.set)) { ret = snprintf(buf+offset, len, "%u", ct->zone); BUFFER_SIZE(ret, size, len, offset); } if (test_bit(ATTR_USE, ct->head.set)) { ret = snprintf(buf+offset, len, "%u", ct->use); BUFFER_SIZE(ret, size, len, offset); } if (test_bit(ATTR_ID, ct->head.set)) { ret = snprintf(buf+offset, len, "%u", ct->id); BUFFER_SIZE(ret, size, len, offset); } if (test_bit(ATTR_STATUS, ct->head.set) && ct->status & IPS_ASSURED) { ret = snprintf(buf+offset, len, ""); BUFFER_SIZE(ret, size, len, offset); } if (test_bit(ATTR_STATUS, ct->head.set) && !(ct->status & IPS_SEEN_REPLY)) { ret = snprintf(buf+offset, len, ""); BUFFER_SIZE(ret, size, len, offset); } if (flags & NFCT_OF_TIMESTAMP) { if (test_bit(ATTR_TIMESTAMP_START, ct->head.set) || test_bit(ATTR_TIMESTAMP_STOP, ct->head.set)) { ret = snprintf(buf+offset, len, ""); BUFFER_SIZE(ret, size, len, offset); } if (test_bit(ATTR_TIMESTAMP_START, ct->head.set)) { ret = __snprintf_timestamp_start(buf+offset, len, ct); BUFFER_SIZE(ret, size, len, offset); } if (test_bit(ATTR_TIMESTAMP_STOP, ct->head.set)) { ret = __snprintf_timestamp_stop(buf+offset, len, ct); BUFFER_SIZE(ret, size, len, offset); } if (test_bit(ATTR_TIMESTAMP_START, ct->head.set) || test_bit(ATTR_TIMESTAMP_STOP, ct->head.set)) { ret = snprintf(buf+offset, len, ""); BUFFER_SIZE(ret, size, len, offset); } } if (test_bit(ATTR_TIMESTAMP_START, ct->head.set) && test_bit(ATTR_TIMESTAMP_STOP, ct->head.set)) { ret = __snprintf_deltatime(buf+offset, len, ct); BUFFER_SIZE(ret, size, len, offset); } else if (test_bit(ATTR_TIMESTAMP_START, ct->head.set)) { ret = __snprintf_deltatime_now(buf+offset, len, ct); BUFFER_SIZE(ret, size, len, offset); } if (test_bit(ATTR_TCP_STATE, ct->head.set) || test_bit(ATTR_SCTP_STATE, ct->head.set) || test_bit(ATTR_DCCP_STATE, ct->head.set) || test_bit(ATTR_TIMEOUT, ct->head.set) || test_bit(ATTR_MARK, ct->head.set) || test_bit(ATTR_SECMARK, ct->head.set) || test_bit(ATTR_ZONE, ct->head.set) || test_bit(ATTR_USE, ct->head.set) || test_bit(ATTR_STATUS, ct->head.set) || test_bit(ATTR_ID, ct->head.set) || test_bit(ATTR_TIMESTAMP_START, ct->head.set) || test_bit(ATTR_TIMESTAMP_STOP, ct->head.set)) { ret = snprintf(buf+offset, len, ""); BUFFER_SIZE(ret, size, len, offset); } if (flags & NFCT_OF_TIME) { time_t t; struct tm tm; t = time(NULL); if (localtime_r(&t, &tm) == NULL) goto err_out; ret = snprintf(buf+offset, len, ""); BUFFER_SIZE(ret, size, len, offset); ret = __snprintf_localtime_xml(buf+offset, len, &tm); BUFFER_SIZE(ret, size, len, offset); ret = snprintf(buf+offset, len, ""); BUFFER_SIZE(ret, size, len, offset); } if (test_bit(ATTR_HELPER_NAME, ct->head.set)) { ret = __snprintf_helper_name(buf+offset, len, ct); BUFFER_SIZE(ret, size, len, offset); } err_out: ret = snprintf(buf+offset, len, ""); BUFFER_SIZE(ret, size, len, offset); return size; }