diff options
author | /C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org </C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org> | 2007-12-08 20:43:28 +0000 |
---|---|---|
committer | /C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org </C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org> | 2007-12-08 20:43:28 +0000 |
commit | 803daa7e837148307258a8e2a152165d65236724 (patch) | |
tree | 984eb36e615ae7ffa35f5e84c35eced90420082e /src/deprecated.c | |
parent | d167a7b1f5307c73a39b5a209e0f9bc54cd2d989 (diff) |
- move old API implementation to deprecated.c
- rename libnetfilter_conntrack.c to main.c
Diffstat (limited to 'src/deprecated.c')
-rw-r--r-- | src/deprecated.c | 1216 |
1 files changed, 1216 insertions, 0 deletions
diff --git a/src/deprecated.c b/src/deprecated.c new file mode 100644 index 0000000..6555062 --- /dev/null +++ b/src/deprecated.c @@ -0,0 +1,1216 @@ +/* + * (C) 2005-2006 by Pablo Neira Ayuso <pablo@netfilter.org> + * Harald Welte <laforge@netfilter.org> + * + * 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. + * + * Warning: This file contains the old API that is deprecated! + */ +#include <stdio.h> +#include <unistd.h> +#include <dlfcn.h> +#include <stdlib.h> +#include <signal.h> +#include <errno.h> +#include <string.h> +#include <arpa/inet.h> +#include "linux_list.h" +#include <libnfnetlink/libnfnetlink.h> +#include <libnetfilter_conntrack/libnetfilter_conntrack.h> +#include <libnetfilter_conntrack/libnetfilter_conntrack_l3extensions.h> +#include <libnetfilter_conntrack/libnetfilter_conntrack_extensions.h> + +#include "internal.h" + +#define NFCT_BUFSIZE 4096 + +static char *lib_dir = LIBNETFILTER_CONNTRACK_DIR; +static LIST_HEAD(proto_list); +static LIST_HEAD(l3proto_list); +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" +}; +static struct nfct_proto *findproto(char *name); +static struct nfct_l3proto *findl3proto(char *name); + +/* handler used for nfnl_listen */ +static int callback_handler(struct sockaddr_nl *nladdr, + struct nlmsghdr *n, void *arg) +{ + struct nfct_handle *cth = (struct nfct_handle *) arg; + int ret; + + if (NFNL_SUBSYS_ID(n->nlmsg_type) != NFNL_SUBSYS_CTNETLINK && + NFNL_SUBSYS_ID(n->nlmsg_type) != NFNL_SUBSYS_CTNETLINK_EXP) { + nfnl_dump_packet(n, n->nlmsg_len, "callback_handler"); + return 0; + } + + if (!cth) + return -ENODEV; + + if (!cth->handler) + return -ENODEV; + + ret = cth->handler(cth, n, NULL); + + return ret; +} + +void nfct_register_callback(struct nfct_handle *cth, nfct_callback callback, + void *data) +{ + cth->callback = callback; + cth->callback_data = data; +} + +void nfct_unregister_callback(struct nfct_handle *cth) +{ + cth->callback = NULL; + cth->callback_data = NULL; +} + +static void nfct_build_tuple_ip(struct nfnlhdr *req, int size, + struct nfct_tuple *t) +{ + struct nfattr *nest; + struct nfct_l3proto *h; + + nest = nfnl_nest(&req->nlh, size, CTA_TUPLE_IP); + + h = findl3proto(l3proto2str[t->l3protonum]); + if (h && h->build_tuple_proto) + h->build_tuple_proto(req, size, t); + + nfnl_nest_end(&req->nlh, nest); +} + +static void nfct_build_tuple_proto(struct nfnlhdr *req, int size, + struct nfct_tuple *t) +{ + struct nfct_proto *h; + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_TUPLE_PROTO); + + nfnl_addattr_l(&req->nlh, size, CTA_PROTO_NUM, &t->protonum, + sizeof(u_int8_t)); + + h = findproto(proto2str[t->protonum]); + + if (h && h->build_tuple_proto) + h->build_tuple_proto(req, size, t); + + nfnl_nest_end(&req->nlh, nest); +} + +void nfct_build_tuple(struct nfnlhdr *req, int size, + struct nfct_tuple *t, int type) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, type); + + nfct_build_tuple_ip(req, size, t); + nfct_build_tuple_proto(req, size, t); + + nfnl_nest_end(&req->nlh, nest); +} + +static void nfct_build_protoinfo(struct nfnlhdr *req, int size, + struct nfct_conntrack *ct) +{ + struct nfattr *nest; + struct nfct_proto *h; + + h = findproto(proto2str[ct->tuple[NFCT_DIR_ORIGINAL].protonum]); + if (h && h->build_protoinfo) { + nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO); + h->build_protoinfo(req, size, ct); + nfnl_nest_end(&req->nlh, nest); + } +} + +static void nfct_build_protonat(struct nfnlhdr *req, int size, + struct nfct_conntrack *ct) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_NAT_PROTO); + + switch (ct->tuple[NFCT_DIR_ORIGINAL].protonum) { +#if 0 + case IPPROTO_TCP: + nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_TCP_MIN, + &ct->nat.l4min.tcp.port, sizeof(u_int16_t)); + nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_TCP_MAX, + &ct->nat.l4max.tcp.port, sizeof(u_int16_t)); + break; + case IPPROTO_UDP: + nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_UDP_MIN, + &ct->nat.l4min.udp.port, sizeof(u_int16_t)); + nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_UDP_MAX, + &ct->nat.l4max.udp.port, sizeof(u_int16_t)); + break; +#endif + } + nfnl_nest_end(&req->nlh, nest); +} + +static void nfct_build_nat(struct nfnlhdr *req, int size, + struct nfct_conntrack *ct) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_NAT); + + nfnl_addattr_l(&req->nlh, size, CTA_NAT_MINIP, + &ct->nat.min_ip, sizeof(u_int32_t)); + + if (ct->nat.min_ip != ct->nat.max_ip) + nfnl_addattr_l(&req->nlh, size, CTA_NAT_MAXIP, + &ct->nat.max_ip, sizeof(u_int32_t)); + + if (ct->nat.l4min.all != ct->nat.l4max.all) + nfct_build_protonat(req, size, ct); + + nfnl_nest_end(&req->nlh, nest); +} + +void nfct_dump_tuple(struct nfct_tuple *tp) +{ + struct in_addr src = { .s_addr = tp->src.v4 }; + struct in_addr dst = { .s_addr = tp->dst.v4 }; + + fprintf(stdout, "tuple %p: %u %s:%hu -> ", tp, tp->protonum, + inet_ntoa(src), + ntohs(tp->l4src.all)); + + fprintf(stdout, "%s:%hu\n", inet_ntoa(dst), ntohs(tp->l4dst.all)); +} + +static struct nfct_proto *findproto(char *name) +{ + struct list_head *i; + struct nfct_proto *cur = NULL, *handler = NULL; + + if (!name) + return handler; + + lib_dir = getenv("LIBNETFILTER_CONNTRACK_DIR"); + if (!lib_dir) + lib_dir = LIBNETFILTER_CONNTRACK_DIR; + + list_for_each(i, &proto_list) { + cur = (struct nfct_proto *) i; + if (strcmp(cur->name, name) == 0) { + handler = cur; + break; + } + } + + if (!handler) { + char path[sizeof("nfct_proto_.so") + strlen(VERSION) + + strlen(name) + strlen(lib_dir)]; + sprintf(path, "%s/nfct_proto_%s-%s.so", lib_dir, name, VERSION); + if (dlopen(path, RTLD_NOW)) + handler = findproto(name); + else + fprintf(stderr, "%s\n", dlerror()); + } + + return handler; +} + +static struct nfct_l3proto *findl3proto(char *name) +{ + struct list_head *i; + struct nfct_l3proto *cur = NULL, *handler = NULL; + + if (!name) + return handler; + + lib_dir = getenv("LIBNETFILTER_CONNTRACK_DIR"); + if (!lib_dir) + lib_dir = LIBNETFILTER_CONNTRACK_DIR; + + list_for_each(i, &l3proto_list) { + cur = (struct nfct_l3proto *) i; + if (strcmp(cur->name, name) == 0) { + handler = cur; + break; + } + } + + if (!handler) { + char path[sizeof("nfct_l3proto_.so") + strlen(VERSION) + + strlen(name) + strlen(lib_dir)]; + sprintf(path, "%s/nfct_l3proto_%s-%s.so",lib_dir,name,VERSION); + if (dlopen(path, RTLD_NOW)) + handler = findl3proto(name); + else + fprintf(stderr, "%s\n", dlerror()); + } + + return handler; +} + +int nfct_sprintf_status_assured(char *buf, struct nfct_conntrack *ct) +{ + int size = 0; + + if (ct->status & IPS_ASSURED) + size = sprintf(buf, "[ASSURED] "); + + return size; +} + +int nfct_sprintf_status_seen_reply(char *buf, struct nfct_conntrack *ct) +{ + int size = 0; + + if (!(ct->status & IPS_SEEN_REPLY)) + size = sprintf(buf, "[UNREPLIED] "); + + return size; +} + +static void parse_ip(struct nfattr *attr, struct nfct_tuple *tuple) +{ + struct nfattr *tb[CTA_IP_MAX]; + struct nfct_l3proto *h; + + nfnl_parse_nested(tb, CTA_IP_MAX, attr); + h = findl3proto(l3proto2str[tuple->l3protonum]); + if (h && h->parse_proto) + h->parse_proto(tb, tuple); +} + +static void parse_proto(struct nfattr *attr, struct nfct_tuple *tuple) +{ + struct nfattr *tb[CTA_PROTO_MAX]; + struct nfct_proto *h; + + nfnl_parse_nested(tb, CTA_PROTO_MAX, attr); + if (tb[CTA_PROTO_NUM-1]) + tuple->protonum = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]); + + h = findproto(proto2str[tuple->protonum]); + if (h && h->parse_proto) + h->parse_proto(tb, tuple); +} + +static void parse_tuple(struct nfattr *attr, struct nfct_tuple *tuple) +{ + struct nfattr *tb[CTA_TUPLE_MAX]; + + nfnl_parse_nested(tb, CTA_TUPLE_MAX, attr); + + if (tb[CTA_TUPLE_IP-1]) + parse_ip(tb[CTA_TUPLE_IP-1], tuple); + if (tb[CTA_TUPLE_PROTO-1]) + parse_proto(tb[CTA_TUPLE_PROTO-1], tuple); +} + +static void parse_mask(struct nfattr *attr, struct nfct_tuple *tuple, + u_int8_t l3protonum, u_int16_t protonum) +{ + struct nfattr *cda[CTA_TUPLE_MAX]; + + nfnl_parse_nested(cda, CTA_TUPLE_MAX, attr); + + if (cda[CTA_TUPLE_IP-1]) { + struct nfattr *tb[CTA_IP_MAX]; + struct nfct_l3proto *h; + + nfnl_parse_nested(tb, CTA_IP_MAX, cda[CTA_TUPLE_IP-1]); + h = findl3proto(l3proto2str[l3protonum]); + if (h && h->parse_proto) + h->parse_proto(tb, tuple); + } + if (cda[CTA_TUPLE_PROTO-1]) { + struct nfattr *tb[CTA_PROTO_MAX]; + struct nfct_proto *h; + + nfnl_parse_nested(tb, CTA_PROTO_MAX, cda[CTA_TUPLE_PROTO-1]); + if (tb[CTA_PROTO_NUM-1]) + tuple->protonum = + *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]); + + h = findproto(proto2str[protonum]); + if (h && h->parse_proto) + h->parse_proto(tb, tuple); + } +} + +static void parse_protoinfo(struct nfattr *attr, struct nfct_conntrack *ct) +{ + struct nfattr *tb[CTA_PROTOINFO_MAX]; + struct nfct_proto *h; + + nfnl_parse_nested(tb,CTA_PROTOINFO_MAX, attr); + + h = findproto(proto2str[ct->tuple[NFCT_DIR_ORIGINAL].protonum]); + if (h && h->parse_protoinfo) + h->parse_protoinfo(tb, ct); +} + +static void nfct_parse_counters(struct nfattr *attr, + struct nfct_conntrack *ct, + enum ctattr_type parent) +{ + struct nfattr *tb[CTA_COUNTERS_MAX]; + int dir = (parent == CTA_COUNTERS_ORIG ? NFCT_DIR_REPLY + : NFCT_DIR_ORIGINAL); + + nfnl_parse_nested(tb, CTA_COUNTERS_MAX, attr); + if (tb[CTA_COUNTERS_PACKETS-1]) + ct->counters[dir].packets + = __be64_to_cpu(*(u_int64_t *) + NFA_DATA(tb[CTA_COUNTERS_PACKETS-1])); + if (tb[CTA_COUNTERS_BYTES-1]) + ct->counters[dir].bytes + = __be64_to_cpu(*(u_int64_t *) + NFA_DATA(tb[CTA_COUNTERS_BYTES-1])); + if (tb[CTA_COUNTERS32_PACKETS-1]) + ct->counters[dir].packets + = ntohl(*(u_int32_t *) + NFA_DATA(tb[CTA_COUNTERS32_PACKETS-1])); + if (tb[CTA_COUNTERS32_BYTES-1]) + ct->counters[dir].bytes + = ntohl(*(u_int32_t *) + NFA_DATA(tb[CTA_COUNTERS32_BYTES-1])); +} + +static char *msgtype[] = {"[UNKNOWN]", "[NEW]", "[UPDATE]", "[DESTROY]"}; + +static int typemsg2enum(u_int16_t type, u_int16_t flags) +{ + int ret = NFCT_MSG_UNKNOWN; + + if (type == IPCTNL_MSG_CT_NEW) { + if (flags & (NLM_F_CREATE|NLM_F_EXCL)) + ret = NFCT_MSG_NEW; + else + ret = NFCT_MSG_UPDATE; + } else if (type == IPCTNL_MSG_CT_DELETE) + ret = NFCT_MSG_DESTROY; + + return ret; +} + +static int nfct_conntrack_netlink_handler(struct nfct_handle *cth, + struct nlmsghdr *nlh, void *arg) +{ + struct nfct_conntrack ct; + unsigned int flags = 0; + struct nfgenmsg *nfhdr = NLMSG_DATA(nlh); + int type = NFNL_MSG_TYPE(nlh->nlmsg_type), ret = 0; + int len = nlh->nlmsg_len; + struct nfattr *cda[CTA_MAX]; + + len -= NLMSG_LENGTH(sizeof(struct nfgenmsg)); + if (len < 0) + return -EINVAL; + + memset(&ct, 0, sizeof(struct nfct_conntrack)); + + ct.tuple[NFCT_DIR_ORIGINAL].l3protonum = nfhdr->nfgen_family; + ct.tuple[NFCT_DIR_REPLY].l3protonum = nfhdr->nfgen_family; + + nfnl_parse_attr(cda, CTA_MAX, NFA_DATA(nfhdr), len); + + if (cda[CTA_TUPLE_ORIG-1]) + parse_tuple(cda[CTA_TUPLE_ORIG-1], + &ct.tuple[NFCT_DIR_ORIGINAL]); + + if (cda[CTA_TUPLE_REPLY-1]) + parse_tuple(cda[CTA_TUPLE_REPLY-1], + &ct.tuple[NFCT_DIR_REPLY]); + + if (cda[CTA_STATUS-1]) { + ct.status = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1])); + flags |= NFCT_STATUS; + } + + if (cda[CTA_PROTOINFO-1]) { + parse_protoinfo(cda[CTA_PROTOINFO-1], &ct); + flags |= NFCT_PROTOINFO; + } + + if (cda[CTA_TIMEOUT-1]) { + ct.timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1])); + flags |= NFCT_TIMEOUT; + } + + if (cda[CTA_MARK-1]) { + ct.mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); + flags |= NFCT_MARK; + } + + if (cda[CTA_COUNTERS_ORIG-1]) { + nfct_parse_counters(cda[CTA_COUNTERS_ORIG-1], &ct, + NFA_TYPE(cda[CTA_COUNTERS_ORIG-1])-1); + flags |= NFCT_COUNTERS_ORIG; + } + + if (cda[CTA_COUNTERS_REPLY-1]) { + nfct_parse_counters(cda[CTA_COUNTERS_REPLY-1], &ct, + NFA_TYPE(cda[CTA_COUNTERS_REPLY-1])-1); + flags |= NFCT_COUNTERS_RPLY; + } + + if (cda[CTA_USE-1]) { + ct.use = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_USE-1])); + flags |= NFCT_USE; + } + + if (cda[CTA_ID-1]) { + ct.id = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_ID-1])); + flags |= NFCT_ID; + } + + if (cth->callback) + ret = cth->callback((void *) &ct, flags, + typemsg2enum(type, nlh->nlmsg_flags), + cth->callback_data); + + return ret; +} + +int nfct_sprintf_protocol(char *buf, struct nfct_conntrack *ct) +{ + return (sprintf(buf, "%-8s %u ", + proto2str[ct->tuple[NFCT_DIR_ORIGINAL].protonum] == NULL ? + "unknown" : proto2str[ct->tuple[NFCT_DIR_ORIGINAL].protonum], + ct->tuple[NFCT_DIR_ORIGINAL].protonum)); +} + +int nfct_sprintf_timeout(char *buf, struct nfct_conntrack *ct) +{ + return sprintf(buf, "%u ", ct->timeout); +} + +int nfct_sprintf_protoinfo(char *buf, struct nfct_conntrack *ct) +{ + int size = 0; + struct nfct_proto *h = NULL; + + h = findproto(proto2str[ct->tuple[NFCT_DIR_ORIGINAL].protonum]); + if (h && h->print_protoinfo) + size += h->print_protoinfo(buf+size, &ct->protoinfo); + + return size; +} + +int nfct_sprintf_address(char *buf, struct nfct_tuple *t) +{ + int size = 0; + struct nfct_l3proto *h; + + h = findl3proto(l3proto2str[t->l3protonum]); + if (h && h->print_proto) + size += h->print_proto(buf, t); + + return size; +} + +int nfct_sprintf_proto(char *buf, struct nfct_tuple *t) +{ + int size = 0; + struct nfct_proto *h = NULL; + + h = findproto(proto2str[t->protonum]); + if (h && h->print_proto) + size += h->print_proto(buf, t); + + return size; +} + +int nfct_sprintf_counters(char *buf, struct nfct_conntrack *ct, int dir) +{ + return (sprintf(buf, "packets=%llu bytes=%llu ", + (unsigned long long) ct->counters[dir].packets, + (unsigned long long) ct->counters[dir].bytes)); +} + +int nfct_sprintf_mark(char *buf, struct nfct_conntrack *ct) +{ + return (sprintf(buf, "mark=%u ", ct->mark)); +} + +int nfct_sprintf_use(char *buf, struct nfct_conntrack *ct) +{ + return (sprintf(buf, "use=%u ", ct->use)); +} + +int nfct_sprintf_id(char *buf, u_int32_t id) +{ + return (sprintf(buf, "id=%u ", id)); +} + +int nfct_sprintf_conntrack(char *buf, struct nfct_conntrack *ct, + unsigned int flags) +{ + int size = 0; + + size += nfct_sprintf_protocol(buf, ct); + + if (flags & NFCT_TIMEOUT) + size += nfct_sprintf_timeout(buf+size, ct); + + if (flags & NFCT_PROTOINFO) + size += nfct_sprintf_protoinfo(buf+size, ct); + + size += nfct_sprintf_address(buf+size, &ct->tuple[NFCT_DIR_ORIGINAL]); + size += nfct_sprintf_proto(buf+size, &ct->tuple[NFCT_DIR_ORIGINAL]); + + if (flags & NFCT_COUNTERS_ORIG) + size += nfct_sprintf_counters(buf+size, ct, NFCT_DIR_ORIGINAL); + + if (flags & NFCT_STATUS) + size += nfct_sprintf_status_seen_reply(buf+size, ct); + + size += nfct_sprintf_address(buf+size, &ct->tuple[NFCT_DIR_REPLY]); + size += nfct_sprintf_proto(buf+size, &ct->tuple[NFCT_DIR_REPLY]); + + if (flags & NFCT_COUNTERS_RPLY) + size += nfct_sprintf_counters(buf+size, ct, NFCT_DIR_REPLY); + + if (flags & NFCT_STATUS) + size += nfct_sprintf_status_assured(buf+size, ct); + + if (flags & NFCT_MARK) + size += nfct_sprintf_mark(buf+size, ct); + + if (flags & NFCT_USE) + size += nfct_sprintf_use(buf+size, ct); + + /* Delete the last blank space */ + size--; + + return size; +} + +int nfct_sprintf_conntrack_id(char *buf, struct nfct_conntrack *ct, + unsigned int flags) +{ + int size; + + /* add a blank space, that's why the add 1 to the size */ + size = nfct_sprintf_conntrack(buf, ct, flags) + 1; + if (flags & NFCT_ID) + size += nfct_sprintf_id(buf+size, ct->id); + + /* Delete the last blank space */ + return --size; +} + +int nfct_default_conntrack_display(void *arg, unsigned int flags, int type, + void *data) +{ + char buf[512]; + int size; + struct nfct_conntrack_compare *cmp = data; + + if (cmp && !nfct_conntrack_compare(cmp->ct, arg, cmp)) + return 0; + + memset(buf, 0, sizeof(buf)); + size = nfct_sprintf_conntrack(buf, arg, flags); + sprintf(buf+size, "\n"); + fprintf(stdout, buf); + + return 0; +} + +int nfct_default_conntrack_display_id(void *arg, unsigned int flags, int type, + void *data) +{ + char buf[512]; + int size; + struct nfct_conntrack_compare *cmp = data; + + if (cmp && !nfct_conntrack_compare(cmp->ct, arg, cmp)) + return 0; + + memset(buf, 0, sizeof(buf)); + size = nfct_sprintf_conntrack_id(buf, arg, flags); + sprintf(buf+size, "\n"); + fprintf(stdout, buf); + + return 0; +} + +int nfct_default_conntrack_event_display(void *arg, unsigned int flags, + int type, void *data) +{ + char buf[512]; + int size; + struct nfct_conntrack_compare *cmp = data; + + if (cmp && !nfct_conntrack_compare(cmp->ct, arg, cmp)) + return 0; + + memset(buf, 0, sizeof(buf)); + size = sprintf(buf, "%9s ", msgtype[type]); + size += nfct_sprintf_conntrack_id(buf + size, arg, flags); + sprintf(buf+size, "\n"); + fprintf(stdout, buf); + fflush(stdout); + + return 0; +} + +int nfct_sprintf_expect_proto(char *buf, struct nfct_expect *exp) +{ + return(sprintf(buf, "%u proto=%d ", exp->timeout, + exp->tuple.protonum)); +} + +int nfct_sprintf_expect(char *buf, struct nfct_expect *exp) +{ + int size = 0; + + size = nfct_sprintf_expect_proto(buf, exp); + size += nfct_sprintf_address(buf+size, &exp->tuple); + size += nfct_sprintf_proto(buf+size, &exp->tuple); + + /* remove last blank space */ + return --size; +} + +int nfct_sprintf_expect_id(char *buf, struct nfct_expect *exp) +{ + int size = 0; + + /* add a blank space, that's why the add 1 to the size */ + size = nfct_sprintf_expect(buf, exp) + 1; + size += nfct_sprintf_id(buf+size, exp->id); + + /* remove last blank space */ + return --size; +} + +int nfct_default_expect_display(void *arg, unsigned int flags, int type, + void *data) +{ + char buf[256]; + int size = 0; + + memset(buf, 0, sizeof(buf)); + size = nfct_sprintf_expect(buf, arg); + sprintf(buf+size, "\n"); + fprintf(stdout, buf); + + return 0; +} + +int nfct_default_expect_display_id(void *arg, unsigned int flags, int type, + void *data) +{ + char buf[256]; + int size = 0; + + size = nfct_sprintf_expect_id(buf, arg); + sprintf(buf+size, "\n"); + fprintf(stdout, buf); + + return 0; +} + +static int nfct_expect_netlink_handler(struct nfct_handle *cth, + struct nlmsghdr *nlh, void *arg) +{ + struct nfgenmsg *nfhdr = NLMSG_DATA(nlh); + struct nfct_expect exp; + int type = NFNL_MSG_TYPE(nlh->nlmsg_type), ret = 0; + int len = nlh->nlmsg_len; + struct nfattr *cda[CTA_EXPECT_MAX]; + + len -= NLMSG_LENGTH(sizeof(struct nfgenmsg)); + if (len < 0) + return -EINVAL; + + memset(&exp, 0, sizeof(struct nfct_expect)); + + exp.tuple.l3protonum = nfhdr->nfgen_family; + + nfnl_parse_attr(cda, CTA_EXPECT_MAX, NFA_DATA(nfhdr), len); + + if (cda[CTA_EXPECT_TUPLE-1]) + parse_tuple(cda[CTA_EXPECT_TUPLE-1], &exp.tuple); + + if (cda[CTA_EXPECT_MASK-1]) + parse_mask(cda[CTA_EXPECT_MASK-1], &exp.mask, + exp.tuple.l3protonum, exp.tuple.protonum); + + if (cda[CTA_EXPECT_TIMEOUT-1]) + exp.timeout = ntohl(*(u_int32_t *) + NFA_DATA(cda[CTA_EXPECT_TIMEOUT-1])); + + if (cda[CTA_EXPECT_ID-1]) + exp.id = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1])); + + if (cth->callback) + ret = cth->callback((void *)&exp, 0, + typemsg2enum(type, nlh->nlmsg_flags), + cth->callback_data); + + return 0; +} + +struct nfct_conntrack * +nfct_conntrack_alloc(struct nfct_tuple *orig, struct nfct_tuple *reply, + u_int32_t timeout, union nfct_protoinfo *proto, + u_int32_t status, u_int32_t mark, + u_int32_t id, struct nfct_nat *range) +{ + struct nfct_conntrack *ct; + + ct = malloc(sizeof(struct nfct_conntrack)); + if (!ct) + return NULL; + memset(ct, 0, sizeof(struct nfct_conntrack)); + + ct->tuple[NFCT_DIR_ORIGINAL] = *orig; + ct->tuple[NFCT_DIR_REPLY] = *reply; + ct->timeout = timeout; + ct->status = status; + ct->protoinfo = *proto; + ct->mark = mark; + if (id != NFCT_ANY_ID) + ct->id = id; + if (range) + ct->nat = *range; + + return ct; +} + +void nfct_conntrack_free(struct nfct_conntrack *ct) +{ + free(ct); +} + +#define L3PROTONUM(ct) ct->tuple[NFCT_DIR_ORIGINAL].l3protonum +#define L4PROTONUM(ct) ct->tuple[NFCT_DIR_ORIGINAL].protonum + +int nfct_conntrack_compare(struct nfct_conntrack *ct1, + struct nfct_conntrack *ct2, + struct nfct_conntrack_compare *cmp) +{ + struct nfct_l3proto *l3proto; + struct nfct_proto *proto; + unsigned int l3flags = cmp->l3flags; + unsigned int l4flags = cmp->l4flags; + unsigned int flags = cmp->flags; + + if ((flags & NFCT_MARK) && (ct1->mark != ct2->mark)) + return 0; + + if (l3flags) { + if (ct1->tuple[NFCT_DIR_ORIGINAL].l3protonum != AF_UNSPEC && + ct2->tuple[NFCT_DIR_ORIGINAL].l3protonum != AF_UNSPEC && + ct1->tuple[NFCT_DIR_ORIGINAL].l3protonum != + ct2->tuple[NFCT_DIR_ORIGINAL].l3protonum) + return 0; + if (ct1->tuple[NFCT_DIR_REPLY].l3protonum != AF_UNSPEC && + ct2->tuple[NFCT_DIR_REPLY].l3protonum != AF_UNSPEC && + ct1->tuple[NFCT_DIR_REPLY].l3protonum != + ct2->tuple[NFCT_DIR_REPLY].l3protonum) + return 0; + l3proto = findl3proto(l3proto2str[L3PROTONUM(ct1)]); + if (l3proto && !l3proto->compare(ct1, ct2, l3flags)) + return 0; + } + + if (l4flags) { + if (ct1->tuple[NFCT_DIR_ORIGINAL].protonum != 0 && + ct2->tuple[NFCT_DIR_ORIGINAL].protonum != 0 && + ct1->tuple[NFCT_DIR_ORIGINAL].protonum != + ct2->tuple[NFCT_DIR_ORIGINAL].protonum) + return 0; + if (ct1->tuple[NFCT_DIR_REPLY].protonum != 0 && + ct2->tuple[NFCT_DIR_REPLY].protonum != 0 && + ct1->tuple[NFCT_DIR_REPLY].protonum != + ct2->tuple[NFCT_DIR_REPLY].protonum) + return 0; + proto = findproto(proto2str[L4PROTONUM(ct1)]); + if (proto && !proto->compare(ct1, ct2, l4flags)) + return 0; + } + + return 1; +} + +int nfct_create_conntrack(struct nfct_handle *cth, struct nfct_conntrack *ct) +{ + struct nfnlhdr *req; + char buf[NFCT_BUFSIZE]; + u_int32_t status = htonl(ct->status | IPS_CONFIRMED); + u_int32_t timeout = htonl(ct->timeout); + u_int32_t mark = htonl(ct->mark); + u_int8_t l3num = ct->tuple[NFCT_DIR_ORIGINAL].l3protonum; + + req = (void *) buf; + + memset(buf, 0, sizeof(buf)); + + nfnl_fill_hdr(cth->nfnlssh_ct, &req->nlh, 0, l3num, 0, + IPCTNL_MSG_CT_NEW, + NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK|NLM_F_EXCL); + + nfct_build_tuple(req, sizeof(buf), &ct->tuple[NFCT_DIR_ORIGINAL], + CTA_TUPLE_ORIG); + nfct_build_tuple(req, sizeof(buf), &ct->tuple[NFCT_DIR_REPLY], + CTA_TUPLE_REPLY); + + nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_STATUS, &status, + sizeof(u_int32_t)); + + nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_TIMEOUT, &timeout, + sizeof(u_int32_t)); + + if (ct->mark != 0) + nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_MARK, &mark, + sizeof(u_int32_t)); + + nfct_build_protoinfo(req, sizeof(buf), ct); + if (ct->nat.min_ip != 0) + nfct_build_nat(req, sizeof(buf), ct); + + return nfnl_talk(cth->nfnlh, &req->nlh, 0, 0, NULL, NULL, NULL); +} + +int nfct_update_conntrack(struct nfct_handle *cth, struct nfct_conntrack *ct) +{ + struct nfnlhdr *req; + char buf[NFCT_BUFSIZE]; + u_int32_t status = htonl(ct->status | IPS_CONFIRMED); + u_int32_t timeout = htonl(ct->timeout); + u_int32_t id = htonl(ct->id); + u_int32_t mark = htonl(ct->mark); + u_int8_t l3num = ct->tuple[NFCT_DIR_ORIGINAL].l3protonum; + + req = (void *) &buf; + memset(&buf, 0, sizeof(buf)); + + nfnl_fill_hdr(cth->nfnlssh_ct, &req->nlh, 0, l3num, 0, + IPCTNL_MSG_CT_NEW, NLM_F_REQUEST|NLM_F_ACK); + + nfct_build_tuple(req, sizeof(buf), &ct->tuple[NFCT_DIR_ORIGINAL], + CTA_TUPLE_ORIG); + nfct_build_tuple(req, sizeof(buf), &ct->tuple[NFCT_DIR_REPLY], + CTA_TUPLE_REPLY); + + if (ct->status != 0) + nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_STATUS, &status, + sizeof(u_int32_t)); + + if (ct->timeout != 0) + nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_TIMEOUT, &timeout, + sizeof(u_int32_t)); + + if (ct->mark != 0) + nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_MARK, &mark, + sizeof(u_int32_t)); + + if (ct->id != NFCT_ANY_ID) + nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_ID, &id, + sizeof(u_int32_t)); + + nfct_build_protoinfo(req, sizeof(buf), ct); + + return nfnl_talk(cth->nfnlh, &req->nlh, 0, 0, NULL, NULL, NULL); +} + +int nfct_delete_conntrack(struct nfct_handle *cth, struct nfct_tuple *tuple, + int dir, u_int32_t id) +{ + struct nfnlhdr *req; + char buf[NFCT_BUFSIZE]; + int type = dir ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG; + u_int8_t l3num = tuple->l3protonum; + + req = (void *) &buf; + memset(&buf, 0, sizeof(buf)); + + nfnl_fill_hdr(cth->nfnlssh_ct, &req->nlh, 0, + l3num, 0, IPCTNL_MSG_CT_DELETE, + NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST|NLM_F_ACK); + + nfct_build_tuple(req, sizeof(buf), tuple, type); + + if (id != NFCT_ANY_ID) { + id = htonl(id); /* to network byte order */ + nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_ID, &id, + sizeof(u_int32_t)); + } + + return nfnl_talk(cth->nfnlh, &req->nlh, 0, 0, NULL, NULL, NULL); +} + +int nfct_get_conntrack(struct nfct_handle *cth, struct nfct_tuple *tuple, + int dir, u_int32_t id) +{ + int err; + struct nfnlhdr *req; + char buf[NFCT_BUFSIZE]; + int type = dir ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG; + u_int8_t l3num = tuple->l3protonum; + + cth->handler = nfct_conntrack_netlink_handler; + + memset(&buf, 0, sizeof(buf)); + req = (void *) &buf; + + nfnl_fill_hdr(cth->nfnlssh_ct, &req->nlh, 0, + l3num, 0, IPCTNL_MSG_CT_GET, + NLM_F_REQUEST|NLM_F_ACK); + + nfct_build_tuple(req, sizeof(buf), tuple, type); + + if (id != NFCT_ANY_ID) { + id = htonl(id); /* to network byte order */ + nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_ID, &id, + sizeof(u_int32_t)); + } + + err = nfnl_send(cth->nfnlh, &req->nlh); + if (err < 0) + return err; + + return nfnl_listen(cth->nfnlh, &callback_handler, cth); +} + +static int __nfct_dump_conntrack_table(struct nfct_handle *cth, int zero, + int family) +{ + int err, msg; + struct nfnlhdr req; + + memset(&req, 0, sizeof(req)); + cth->handler = nfct_conntrack_netlink_handler; + + if (zero) + msg = IPCTNL_MSG_CT_GET_CTRZERO; + else + msg = IPCTNL_MSG_CT_GET; + + nfnl_fill_hdr(cth->nfnlssh_ct, &req.nlh, 0, family, 0, + msg, NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST|NLM_F_DUMP); + + err = nfnl_send(cth->nfnlh, &req.nlh); + if (err < 0) + return err; + + return nfnl_listen(cth->nfnlh, &callback_handler, cth); +} + +int nfct_dump_conntrack_table(struct nfct_handle *cth, int family) +{ + return(__nfct_dump_conntrack_table(cth, 0, family)); +} + +int nfct_dump_conntrack_table_reset_counters(struct nfct_handle *cth, + int family) +{ + return(__nfct_dump_conntrack_table(cth, 1, family)); +} + +int nfct_event_conntrack(struct nfct_handle *cth) +{ + cth->handler = nfct_conntrack_netlink_handler; + return nfnl_listen(cth->nfnlh, &callback_handler, cth); +} + +void nfct_register_proto(struct nfct_proto *h) +{ + if (strcmp(h->version, VERSION) != 0) { + fprintf(stderr, "plugin `%s': version %s (I'm %s)\n", + h->name, h->version, VERSION); + exit(1); + } + list_add(&h->head, &proto_list); +} + +void nfct_register_l3proto(struct nfct_l3proto *h) +{ + if (strcmp(h->version, VERSION) != 0) { + fprintf(stderr, "plugin `%s': version %s (I'm %s)\n", + h->name, h->version, VERSION); + exit(1); + } + list_add(&h->head, &l3proto_list); +} + +int nfct_dump_expect_list(struct nfct_handle *cth, int family) +{ + int err; + struct nfnlhdr req; + + memset(&req, 0, sizeof(req)); + + cth->handler = nfct_expect_netlink_handler; + nfnl_fill_hdr(cth->nfnlssh_exp, &req.nlh, 0, family, 0, + IPCTNL_MSG_EXP_GET, NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST); + + err = nfnl_send(cth->nfnlh, &req.nlh); + if (err < 0) + return err; + + return nfnl_listen(cth->nfnlh, &callback_handler, cth); +} + +int nfct_flush_conntrack_table(struct nfct_handle *cth, int family) +{ + struct nfnlhdr req; + + memset(&req, 0, sizeof(req)); + + nfnl_fill_hdr(cth->nfnlssh_ct, (struct nlmsghdr *) &req, + 0, family, 0, IPCTNL_MSG_CT_DELETE, + NLM_F_REQUEST|NLM_F_ACK); + + return nfnl_talk(cth->nfnlh, &req.nlh, 0, 0, NULL, NULL, NULL); +} + +int nfct_get_expectation(struct nfct_handle *cth, struct nfct_tuple *tuple, + u_int32_t id) +{ + int err; + struct nfnlhdr *req; + char buf[NFCT_BUFSIZE]; + u_int8_t l3num = tuple->l3protonum; + + memset(&buf, 0, sizeof(buf)); + req = (void *) &buf; + + nfnl_fill_hdr(cth->nfnlssh_exp, &req->nlh, 0, l3num, 0, + IPCTNL_MSG_EXP_GET, + NLM_F_REQUEST|NLM_F_ACK); + + cth->handler = nfct_expect_netlink_handler; + nfct_build_tuple(req, sizeof(buf), tuple, CTA_EXPECT_MASTER); + + if (id != NFCT_ANY_ID) + nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_EXPECT_ID, &id, + sizeof(u_int32_t)); + + err = nfnl_send(cth->nfnlh, &req->nlh); + if (err < 0) + return err; + + return nfnl_listen(cth->nfnlh, &callback_handler, cth); +} + +struct nfct_expect * +nfct_expect_alloc(struct nfct_tuple *master, struct nfct_tuple *tuple, + struct nfct_tuple *mask, u_int32_t timeout, + u_int32_t id) +{ + struct nfct_expect *exp; + + exp = malloc(sizeof(struct nfct_expect)); + if (!exp) + return NULL; + memset(exp, 0, sizeof(struct nfct_expect)); + + exp->master = *master; + exp->tuple = *tuple; + exp->mask = *mask; + exp->timeout = timeout; + if (id != NFCT_ANY_ID) + exp->id = htonl(id); + + return exp; +} + +void nfct_expect_free(struct nfct_expect *exp) +{ + free(exp); +} + +int nfct_create_expectation(struct nfct_handle *cth, struct nfct_expect *exp) +{ + struct nfnlhdr *req; + char buf[NFCT_BUFSIZE]; + req = (void *) &buf; + u_int8_t l3num = exp->tuple.l3protonum; + u_int32_t timeout; + u_int16_t queuenr; + + memset(&buf, 0, sizeof(buf)); + + nfnl_fill_hdr(cth->nfnlssh_exp, &req->nlh, 0, l3num, 0, + IPCTNL_MSG_EXP_NEW, + NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK); + + nfct_build_tuple(req, sizeof(buf), &exp->master, CTA_EXPECT_MASTER); + nfct_build_tuple(req, sizeof(buf), &exp->tuple, CTA_EXPECT_TUPLE); + nfct_build_tuple(req, sizeof(buf), &exp->mask, CTA_EXPECT_MASK); + + timeout = htonl(exp->timeout); + nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_EXPECT_TIMEOUT, + &timeout, sizeof(u_int32_t)); + + queuenr = htons(exp->expectfn_queue_id); + if (queuenr) + nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_EXPECT_QUEUENR, + &queuenr, sizeof(u_int16_t)); + + return nfnl_talk(cth->nfnlh, &req->nlh, 0, 0, NULL, NULL, NULL); +} + +int nfct_delete_expectation(struct nfct_handle *cth, struct nfct_tuple *tuple, + u_int32_t id) +{ + struct nfnlhdr *req; + char buf[NFCT_BUFSIZE]; + u_int8_t l3num = tuple->l3protonum; + + memset(&buf, 0, sizeof(buf)); + req = (void *) &buf; + + nfnl_fill_hdr(cth->nfnlssh_exp, &req->nlh, 0, l3num, + 0, IPCTNL_MSG_EXP_DELETE, + NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST|NLM_F_ACK); + + nfct_build_tuple(req, sizeof(buf), tuple, CTA_EXPECT_MASTER); + + if (id != NFCT_ANY_ID) + nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_EXPECT_ID, &id, + sizeof(u_int32_t)); + + return nfnl_talk(cth->nfnlh, &req->nlh, 0, 0, NULL, NULL, NULL); +} + +int nfct_event_expectation(struct nfct_handle *cth) +{ + cth->handler = nfct_expect_netlink_handler; + return nfnl_listen(cth->nfnlh, &callback_handler, cth); +} + +int nfct_flush_expectation_table(struct nfct_handle *cth, int family) +{ + struct nfnlhdr req; + + memset(&req, 0, sizeof(req)); + + nfnl_fill_hdr(cth->nfnlssh_exp, (struct nlmsghdr *) &req, + 0, family, 0, IPCTNL_MSG_EXP_DELETE, + NLM_F_REQUEST|NLM_F_ACK); + + return nfnl_talk(cth->nfnlh, &req.nlh, 0, 0, NULL, NULL, NULL); +} + |