/* * (C) 2006 by Pablo Neira Ayuso * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. */ #include "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 * 1 * * * */ static char *proto2str[IPPROTO_MAX] = { [IPPROTO_TCP] = "tcp", [IPPROTO_UDP] = "udp", [IPPROTO_ICMP] = "icmp", [IPPROTO_SCTP] = "sctp" }; static char *l3proto2str[AF_MAX] = { [AF_INET] = "ipv4", [AF_INET6] = "ipv6" }; enum { __ADDR_SRC = 0, __ADDR_DST, }; static void buffer_size(int ret, unsigned int *size, unsigned int *len) { *size += ret; *len -= ret; } static char *__proto2str(u_int8_t protonum) { return proto2str[protonum] ? proto2str[protonum] : "unknown"; } static 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.in6_u, p, sizeof(struct in6_addr)); if (!inet_ntop(AF_INET6, &addr, tmp, sizeof(tmp))) return -1; return snprintf(buf, len, "%s", tmp); } static int __snprintf_addr_xml(char *buf, unsigned int len, const struct __nfct_tuple *tuple, unsigned int type) { int ret; unsigned int size = 0; switch(type) { case __ADDR_SRC: ret = snprintf(buf, len, ""); if (ret == -1) return -1; buffer_size(ret, &size, &len); break; case __ADDR_DST: ret = snprintf(buf+size, len, ""); if (ret == -1) return -1; buffer_size(ret, &size, &len); break; } switch (tuple->l3protonum) { case AF_INET: ret = __snprintf_ipv4_xml(buf+size, len, tuple, type); if (ret == -1) return -1; buffer_size(ret, &size, &len); break; case AF_INET6: ret = __snprintf_ipv6_xml(buf+size, len, tuple, type); if (ret == -1) return -1; buffer_size(ret, &size, &len); break; } switch(type) { case __ADDR_SRC: ret = snprintf(buf+size, len, ""); if (ret == -1) return -1; buffer_size(ret, &size, &len); break; case __ADDR_DST: ret = snprintf(buf+size, len, ""); if (ret == -1) return -1; buffer_size(ret, &size, &len); break; } return size; } static int __snprintf_proto_xml(char *buf, unsigned int len, const struct __nfct_tuple *tuple, unsigned int type) { int ret = 0; unsigned int size = 0; switch(tuple->protonum) { case IPPROTO_TCP: case IPPROTO_UDP: case IPPROTO_SCTP: if (type == __ADDR_SRC) { ret = snprintf(buf, len, "%u", tuple->l4src.tcp.port); if (ret == -1) return -1; buffer_size(ret, &size, &len); } else { ret = snprintf(buf, len, "%u", tuple->l4dst.tcp.port); if (ret == -1) return -1; buffer_size(ret, &size, &len); } 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; ret = snprintf(buf, len, "%llu", ct->counters[type].packets); if (ret == -1) return -1; buffer_size(ret, &size, &len); ret = snprintf(buf+size, len, "%llu", ct->counters[type].bytes); if (ret == -1) return -1; buffer_size(ret, &size, &len); 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; const struct __nfct_tuple *tuple = &ct->tuple[dir]; ret = snprintf(buf, len, "", dir == __DIR_ORIG ? "original" : "reply"); if (ret == -1) return -1; buffer_size(ret, &size, &len); ret = snprintf(buf+size, len, "", tuple->l3protonum, __l3proto2str(tuple->l3protonum)); if (ret == -1) return -1; buffer_size(ret, &size, &len); ret = __snprintf_addr_xml(buf+size, len, tuple, __DIR_ORIG); if (ret == -1) return -1; buffer_size(ret, &size, &len); ret = __snprintf_addr_xml(buf+size, len, tuple, __DIR_REPL); if (ret == -1) return -1; buffer_size(ret, &size, &len); ret = snprintf(buf+size, len, ""); if (ret == -1) return -1; buffer_size(ret, &size, &len); ret = snprintf(buf+size, len, "", tuple->protonum, __proto2str(tuple->protonum)); if (ret == -1) return -1; buffer_size(ret, &size, &len); ret = __snprintf_proto_xml(buf+size, len, tuple, __DIR_ORIG); if (ret == -1) return -1; buffer_size(ret, &size, &len); ret = __snprintf_proto_xml(buf+size, len, tuple, __DIR_REPL); if (ret == -1) return -1; buffer_size(ret, &size, &len); ret = snprintf(buf+size, len, ""); if (ret == -1) return -1; buffer_size(ret, &size, &len); if (test_bit(ATTR_ORIG_COUNTER_PACKETS, ct->set) && test_bit(ATTR_ORIG_COUNTER_BYTES, ct->set)) { ret = snprintf(buf+size, len, ""); if (ret == -1) return -1; buffer_size(ret, &size, &len); ret = __snprintf_counters_xml(buf+size, len, ct, dir); if (ret == -1) return -1; buffer_size(ret, &size, &len); ret = snprintf(buf+size, len, ""); if (ret == -1) return -1; buffer_size(ret, &size, &len); } ret = snprintf(buf+size, len, ""); if (ret == -1) return -1; buffer_size(ret, &size, &len); 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; switch(msg_type) { case NFCT_T_NEW: ret = snprintf(buf, len, ""); break; case NFCT_T_UPDATE: ret = snprintf(buf, len, ""); break; } if (ret == -1) return -1; buffer_size(ret, &size, &len); ret = __snprintf_tuple_xml(buf+size, len, ct, __DIR_ORIG); if (ret == -1) return -1; buffer_size(ret, &size, &len); ret = __snprintf_tuple_xml(buf+size, len, ct, __DIR_REPL); if (ret == -1) return -1; buffer_size(ret, &size, &len); if (test_bit(ATTR_TIMEOUT, ct->set) || test_bit(ATTR_MARK, ct->set) || test_bit(ATTR_USE, ct->set) || test_bit(ATTR_STATUS, ct->set)) { ret = snprintf(buf+size, len, ""); if (ret == -1) return -1; buffer_size(ret, &size, &len); } if (test_bit(ATTR_TIMEOUT, ct->set)) { ret = snprintf(buf+size, len, "%u", ct->timeout); if (ret == -1) return -1; buffer_size(ret, &size, &len); } if (test_bit(ATTR_MARK, ct->set)) { ret = snprintf(buf+size, len, "%u", ct->mark); if (ret == -1) return -1; buffer_size(ret, &size, &len); } if (test_bit(ATTR_USE, ct->set)) { ret = snprintf(buf+size, len, "%u", ct->use); if (ret == -1) return -1; buffer_size(ret, &size, &len); } if (test_bit(ATTR_STATUS, ct->set) && ct->status & IPS_ASSURED) { ret = snprintf(buf+size, len, ""); if (ret == -1) return -1; buffer_size(ret, &size, &len); } if (test_bit(ATTR_STATUS, ct->set) && !(ct->status & IPS_SEEN_REPLY)) { ret = snprintf(buf+size, len, ""); if (ret == -1) return -1; buffer_size(ret, &size, &len); } if (test_bit(ATTR_TIMEOUT, ct->set) || test_bit(ATTR_MARK, ct->set) || test_bit(ATTR_USE, ct->set) || test_bit(ATTR_STATUS, ct->set)) { ret = snprintf(buf+size, len, ""); if (ret == -1) return -1; buffer_size(ret, &size, &len); } ret = snprintf(buf+size, len, ""); if (ret == -1) return -1; buffer_size(ret, &size, &len); return size; }