From f9dc4d2ed9f724057ed107839aa8ca6122f7b46c Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=pablo/emailAddress=pablo@netfilter.org" Date: Sun, 16 Oct 2005 19:44:46 +0000 Subject: Major changes, this library isn't libnfnetlink_conntrack anymore. We provide an high level interface that abstracts from the netlink sockets. Now users don't need to know anything about them. --- src/libnetfilter_conntrack.c | 994 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 994 insertions(+) create mode 100644 src/libnetfilter_conntrack.c (limited to 'src/libnetfilter_conntrack.c') diff --git a/src/libnetfilter_conntrack.c b/src/libnetfilter_conntrack.c new file mode 100644 index 0000000..3b130da --- /dev/null +++ b/src/libnetfilter_conntrack.c @@ -0,0 +1,994 @@ +/* + * (C) 2005 by Pablo Neira Ayuso + * Harald Welte + * + * 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 +#include +#include +#include +#include +#include +#include +#include "linux_list.h" +#include +#include + +#define NFCT_BUFSIZE 4096 + +#define NIPQUAD(addr) \ + ((unsigned char *)&addr)[0], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[3] + +char *lib_dir = LIBNETFILTER_CONNTRACK_DIR; +struct list_head proto_list; +char *proto2str[IPPROTO_MAX] = { + [IPPROTO_TCP] = "tcp", + [IPPROTO_UDP] = "udp", + [IPPROTO_ICMP] = "icmp", + [IPPROTO_SCTP] = "sctp" +}; + +/* 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 type = NFNL_MSG_TYPE(n->nlmsg_type); + struct nfct_msg_handler *hdlr = cth->handler[type]; + 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 (!hdlr) + return 0; + + if (!hdlr->handler) + return 0; + + ret = hdlr->handler(nladdr, n, arg); + + return ret; +} + +struct nfct_handle *nfct_open(u_int8_t subsys_id, unsigned subscriptions) +{ + int err; + u_int8_t cb_count; + struct nfct_handle *cth; + + switch(subsys_id) { + case NFNL_SUBSYS_CTNETLINK: + cb_count = IPCTNL_MSG_MAX; + break; + case NFNL_SUBSYS_CTNETLINK_EXP: + cb_count = IPCTNL_MSG_EXP_MAX; + break; + default: + return NULL; + break; + } + cth = (struct nfct_handle *) + malloc(sizeof(struct nfct_handle)); + if (!cth) + return NULL; + + memset(cth, 0, sizeof(*cth)); + + err = nfnl_open(&cth->nfnlh, subsys_id, cb_count, subscriptions); + if (err < 0) + return NULL; + + return cth; +} + +int nfct_close(struct nfct_handle *cth) +{ + int err; + + err = nfnl_close(&cth->nfnlh); + free(cth); + + return err; +} + +void nfct_set_callback(struct nfct_handle *cth, + nfct_callback callback) +{ + cth->callback = callback; +} + +static int nfct_register_handler(struct nfct_handle *cth, + struct nfct_msg_handler *hndlr) +{ + if (hndlr->type >= IPCTNL_MSG_MAX) + return -EINVAL; + + cth->handler[hndlr->type] = hndlr; + + return 0; +} + +static void nfct_build_tuple_ip(struct nfnlhdr *req, int size, + struct nfct_tuple *t) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_TUPLE_IP); + + nfnl_addattr_l(&req->nlh, size, CTA_IP_V4_SRC, &t->src.v4, + sizeof(u_int32_t)); + + nfnl_addattr_l(&req->nlh, size, CTA_IP_V4_DST, &t->dst.v4, + sizeof(u_int32_t)); + + nfnl_nest_end(&req->nlh, nest); +} + +static void nfct_build_tuple_proto(struct nfnlhdr *req, int size, + struct nfct_tuple *t) +{ + 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_int16_t)); + + switch(t->protonum) { + case IPPROTO_TCP: + case IPPROTO_UDP: + case IPPROTO_SCTP: + nfnl_addattr_l(&req->nlh, size, CTA_PROTO_SRC_PORT, + &t->l4src.tcp.port, sizeof(u_int16_t)); + nfnl_addattr_l(&req->nlh, size, CTA_PROTO_DST_PORT, + &t->l4dst.tcp.port, sizeof(u_int16_t)); + break; + case IPPROTO_ICMP: + nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_CODE, + &t->l4dst.icmp.code, sizeof(u_int8_t)); + nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_TYPE, + &t->l4dst.icmp.type, sizeof(u_int8_t)); + /* This is an ICMP echo */ + if (t->l4dst.icmp.type == 8) + nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_ID, + &t->l4src.icmp.id, sizeof(u_int16_t)); + break; + } + nfnl_nest_end(&req->nlh, nest); +} + +static 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; + + nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO); + + switch (ct->tuple[NFCT_DIR_ORIGINAL].protonum) { + case IPPROTO_TCP: { + struct nfattr *nest_proto; + nest_proto = nfnl_nest(&req->nlh, size, CTA_PROTOINFO_TCP); + nfnl_addattr_l(&req->nlh, size, CTA_PROTOINFO_TCP_STATE, + &ct->protoinfo.tcp.state, sizeof(u_int8_t)); + nfnl_nest_end(&req->nlh, nest_proto); + break; + } + default: + break; + } + + 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); +} + +static void nfct_build_conntrack(struct nfnlhdr *req, int size, + struct nfct_conntrack *ct) +{ + nfct_build_tuple(req, size, &ct->tuple[NFCT_DIR_ORIGINAL], + CTA_TUPLE_ORIG); + nfct_build_tuple(req, size, &ct->tuple[NFCT_DIR_REPLY], + CTA_TUPLE_REPLY); + + nfnl_addattr_l(&req->nlh, size, CTA_STATUS, &ct->status, + sizeof(unsigned int)); + nfnl_addattr_l(&req->nlh, size, CTA_TIMEOUT, &ct->timeout, + sizeof(unsigned long)); + + nfct_build_protoinfo(req, size, ct); + if (ct->nat.min_ip != 0) + nfct_build_nat(req, size, ct); +} + +void nfct_dump_tuple(struct nfct_tuple *tp) +{ + fprintf(stdout, "tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", + tp, tp->protonum, + NIPQUAD(tp->src.v4), ntohs(tp->l4src.all), + NIPQUAD(tp->dst.v4), 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("libnetfilter_conntrack_.so") + + strlen(name) + strlen(lib_dir)]; + sprintf(path, "%s/libnetfilter_conntrack_%s.so", lib_dir, name); + if (dlopen(path, RTLD_NOW)) + handler = findproto(name); + else + fprintf(stderr, "%s\n", dlerror()); + } + + return handler; +} + +static int print_status(char *buf, unsigned int status) +{ + int size = 0; + + if (status & IPS_ASSURED) + size = sprintf(buf, "[ASSURED] "); + if (!(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]; + + nfnl_parse_nested(tb, CTA_IP_MAX, attr); + if (tb[CTA_IP_V4_SRC-1]) + tuple->src.v4 = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]); + + if (tb[CTA_IP_V4_DST-1]) + tuple->dst.v4 = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]); +} + +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_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 + = htonl(*(u_int32_t *) + NFA_DATA(tb[CTA_COUNTERS32_PACKETS-1])); + if (tb[CTA_COUNTERS32_BYTES-1]) + ct->counters[dir].bytes + = htonl(*(u_int32_t *) + NFA_DATA(tb[CTA_COUNTERS32_BYTES-1])); +} + +static int nfct_conntrack_netlink_handler(struct sockaddr_nl *sock, + struct nlmsghdr *nlh, void *arg) +{ + struct nfgenmsg *nfmsg; + int min_len = sizeof(struct nfgenmsg);; + struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); + int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); + struct nfct_conntrack ct; + unsigned int flags = 0; + struct nfct_handle *cth = arg; + + memset(&ct, 0, sizeof(struct nfct_conntrack)); + + nfmsg = NLMSG_DATA(nlh); + + if (nlh->nlmsg_len < min_len) + return -EINVAL; + + while (NFA_OK(attr, attrlen)) { + switch(NFA_TYPE(attr)) { + case CTA_TUPLE_ORIG: + parse_tuple(attr, &ct.tuple[NFCT_DIR_ORIGINAL]); + break; + case CTA_TUPLE_REPLY: + parse_tuple(attr, &ct.tuple[NFCT_DIR_REPLY]); + break; + case CTA_STATUS: + ct.status = ntohl(*(u_int32_t *)NFA_DATA(attr)); + flags |= NFCT_STATUS; + break; + case CTA_PROTOINFO: + parse_protoinfo(attr, &ct); + flags |= NFCT_PROTOINFO; + break; + case CTA_TIMEOUT: + ct.timeout = ntohl(*(u_int32_t *)NFA_DATA(attr)); + flags |= NFCT_TIMEOUT; + break; + case CTA_MARK: + ct.mark = ntohl(*(u_int32_t *)NFA_DATA(attr)); + flags |= NFCT_MARK; + break; + case CTA_COUNTERS_ORIG: + case CTA_COUNTERS_REPLY: + nfct_parse_counters(attr, &ct, + NFA_TYPE(attr)-1); + flags |= NFCT_COUNTERS; + break; + case CTA_USE: + ct.use = ntohl(*(u_int32_t *)NFA_DATA(attr)); + flags |= NFCT_USE; + break; + case CTA_ID: + ct.id = ntohl(*(u_int32_t *)NFA_DATA(attr)); + flags |= NFCT_ID; + break; + default: + fprintf(stderr, "Unknown Attribute\n"); + break; + } + attr = NFA_NEXT(attr, attrlen); + } + if (cth->callback) + cth->callback((void *) &ct, flags); + + return 0; +} + +void nfct_default_conntrack_display(void *arg, unsigned int flags) +{ + struct nfct_conntrack *ct = arg; + struct nfct_proto *h = NULL; + char buf[512]; + int size = 0; + + size += 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); + + if (flags & NFCT_TIMEOUT) + size += sprintf(buf+size, "%lu ", ct->timeout); + + h = findproto(proto2str[ct->tuple[NFCT_DIR_ORIGINAL].protonum]); + if ((flags & NFCT_PROTOINFO) && h && h->print_protoinfo) + size += h->print_protoinfo(buf+size, &ct->protoinfo); + + size += sprintf(buf+size, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(ct->tuple[NFCT_DIR_ORIGINAL].src.v4), + NIPQUAD(ct->tuple[NFCT_DIR_ORIGINAL].dst.v4)); + + if (h && h->print_proto) + size += h->print_proto(buf+size, &ct->tuple[NFCT_DIR_ORIGINAL]); + + if (flags & NFCT_COUNTERS) + size += printf(buf+size, "packets=%llu bytes=%llu ", + ct->counters[NFCT_DIR_ORIGINAL].packets, + ct->counters[NFCT_DIR_ORIGINAL].bytes); + + size += sprintf(buf+size, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(ct->tuple[NFCT_DIR_REPLY].src.v4), + NIPQUAD(ct->tuple[NFCT_DIR_REPLY].dst.v4)); + + h = findproto(proto2str[ct->tuple[NFCT_DIR_ORIGINAL].protonum]); + if (h && h->print_proto) + size += h->print_proto(buf+size, &ct->tuple[NFCT_DIR_REPLY]); + + if (flags & NFCT_COUNTERS) + size += sprintf(buf+size, "packets=%llu bytes=%llu ", + ct->counters[NFCT_DIR_REPLY].packets, + ct->counters[NFCT_DIR_REPLY].bytes); + + if (flags & NFCT_STATUS) + size += print_status(buf+size, ct->status); + + if (flags & NFCT_MARK) + size += sprintf(buf+size, "mark=%lu ", ct->mark); + if (flags & NFCT_USE) + size += sprintf(buf+size, "use=%u ", ct->use); + if (flags & NFCT_ID) + size += sprintf(buf+size, "id=%u ", ct->id); + + sprintf(buf+size, "\n"); + fprintf(stdout, buf); +} + +void nfct_default_expect_display(void *arg, unsigned int flags) +{ + struct nfct_expect *exp = arg; + char buf[256]; + int size = 0; + + size += sprintf(buf, "%ld proto=%d ", exp->timeout, exp->tuple.protonum); + size += sprintf(buf+size, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(exp->tuple.src.v4), + NIPQUAD(exp->tuple.dst.v4)); + size += sprintf(buf+size, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(exp->mask.src.v4), + NIPQUAD(exp->mask.dst.v4)); + size += sprintf(buf+size, "id=%u ", exp->id); + size += sprintf(buf, "\n"); + fprintf(stdout, buf); +} + +static char *typemsg2str(type, flags) +{ + char *ret = "[UNKNOWN]"; + + if (type == IPCTNL_MSG_CT_NEW) { + if (flags & NLM_F_CREATE) + ret = "[NEW]"; + else + ret = "[UPDATE]"; + } else if (type == IPCTNL_MSG_CT_DELETE) + ret = "[DESTROY]"; + + return ret; +} + +static int nfct_event_handler(struct sockaddr_nl *sock, + struct nlmsghdr *nlh, + void *arg) +{ + int type = NFNL_MSG_TYPE(nlh->nlmsg_type); + fprintf(stdout, "%9s ", typemsg2str(type, nlh->nlmsg_flags)); + return nfct_conntrack_netlink_handler(sock, nlh, arg); +} + +static int nfct_expect_netlink_handler(struct sockaddr_nl *sock, + struct nlmsghdr *nlh, void *arg) +{ + struct nfgenmsg *nfmsg; + struct nfct_handle *cth = arg; + int min_len = sizeof(struct nfgenmsg); + struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); + int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); + struct nfct_expect exp; + + memset(&exp, 0, sizeof(struct nfct_expect)); + + nfmsg = NLMSG_DATA(nlh); + + if (nlh->nlmsg_len < min_len) + return -EINVAL; + + while (NFA_OK(attr, attrlen)) { + switch(NFA_TYPE(attr)) { + + case CTA_EXPECT_TUPLE: + parse_tuple(attr, &exp.tuple); + break; + case CTA_EXPECT_MASK: + parse_tuple(attr, &exp.mask); + break; + case CTA_EXPECT_TIMEOUT: + exp.timeout = htonl(*(unsigned long *) + NFA_DATA(attr)); + break; + case CTA_EXPECT_ID: + exp.id = htonl(*(u_int32_t *)NFA_DATA(attr)); + break; + } + attr = NFA_NEXT(attr, attrlen); + } + if (cth->callback) + cth->callback((void *)&exp, 0); + + return 0; +} + +static +int __nfct_create_conntrack(struct nfct_handle *cth, + struct nfct_tuple *orig, + struct nfct_tuple *reply, + unsigned long timeout, + union nfct_protoinfo *proto, + unsigned int status, + struct nfct_nat *range) +{ + struct nfnlhdr *req; + char buf[NFCT_BUFSIZE]; + struct nfct_conntrack ct; + int ret; + + req = (void *) buf; + + memset(buf, 0, sizeof(buf)); + memset(&ct, 0, sizeof(struct nfct_conntrack)); + + ct.tuple[NFCT_DIR_ORIGINAL] = *orig; + ct.tuple[NFCT_DIR_REPLY] = *reply; + ct.timeout = htonl(timeout); + ct.status = htonl(status); + ct.protoinfo = *proto; + if (range) + ct.nat = *range; + + nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, AF_INET, 0, IPCTNL_MSG_CT_NEW, + NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK|NLM_F_EXCL); + + nfct_build_conntrack(req, sizeof(buf), &ct); + + if (nfnl_send(&cth->nfnlh, &req->nlh) < 0 ) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +int nfct_create_conntrack(struct nfct_handle *cth, + struct nfct_tuple *orig, + struct nfct_tuple *reply, + unsigned long timeout, + union nfct_protoinfo *proto, + unsigned int status) +{ + return(__nfct_create_conntrack(cth, orig, reply, timeout, + proto, status, NULL)); +} + +int nfct_create_conntrack_nat(struct nfct_handle *cth, + struct nfct_tuple *orig, + struct nfct_tuple *reply, + unsigned long timeout, + union nfct_protoinfo *proto, + unsigned int status, + struct nfct_nat *nat) +{ + return(__nfct_create_conntrack(cth, orig, reply, timeout, + proto, status, nat)); +} + +int nfct_update_conntrack(struct nfct_handle *cth, + struct nfct_tuple *orig, + struct nfct_tuple *reply, + unsigned long timeout, + union nfct_protoinfo *proto, + unsigned int status) +{ + struct nfnlhdr *req; + char buf[NFCT_BUFSIZE]; + struct nfct_conntrack ct; + int ret; + + req = (void *) &buf; + memset(&buf, 0, sizeof(buf)); + memset(&ct, 0, sizeof(struct nfct_conntrack)); + + ct.tuple[NFCT_DIR_ORIGINAL] = *orig; + ct.tuple[NFCT_DIR_REPLY] = *reply; + ct.timeout = htonl(timeout); + ct.status = htonl(status); + ct.protoinfo = *proto; + + nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, AF_INET, 0, IPCTNL_MSG_CT_NEW, + NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK); + + nfct_build_conntrack(req, sizeof(buf), &ct); + + if (nfnl_send(&cth->nfnlh, &req->nlh) < 0) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +int nfct_delete_conntrack(struct nfct_handle *cth,struct nfct_tuple *tuple, int dir) +{ + int ret; + struct nfnlhdr *req; + char buf[NFCT_BUFSIZE]; + int type = dir ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG; + + memset(&buf, 0, sizeof(buf)); + req = (void *) &buf; + + nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, + AF_INET, 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 (nfnl_send(&cth->nfnlh, &req->nlh) < 0) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +/* get_conntrack_handler */ +int nfct_get_conntrack(struct nfct_handle *cth,struct nfct_tuple *tuple, int dir) +{ + int ret; + struct nfnlhdr *req; + struct nfct_msg_handler h = { + .type = 0, + .handler = nfct_conntrack_netlink_handler + }; + char buf[NFCT_BUFSIZE]; + + memset(&buf, 0, sizeof(buf)); + req = (void *) &buf; + + nfct_build_tuple(req, sizeof(buf), tuple, dir); + + nfct_register_handler(cth, &h); + nfct_build_tuple(req, sizeof(buf), tuple, dir); + + if (nfnl_send(&cth->nfnlh, &req->nlh) < 0) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +static int __nfct_dump_conntrack_table(struct nfct_handle *cth,int zero) +{ + int ret, msg; + struct nfct_msg_handler h = { + .type = IPCTNL_MSG_CT_NEW, /* Hm... really? */ + .handler = nfct_conntrack_netlink_handler + }; + struct nfnlhdr req; + + nfct_register_handler(cth, &h); + + if (zero) + msg = IPCTNL_MSG_CT_GET_CTRZERO; + else + msg = IPCTNL_MSG_CT_GET; + + nfnl_fill_hdr(&cth->nfnlh, &req.nlh, 0, AF_INET, 0, + msg, NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST); + + if (nfnl_send(&cth->nfnlh, &req.nlh) < 0) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +int nfct_dump_conntrack_table(struct nfct_handle *cth) +{ + return(__nfct_dump_conntrack_table(cth, 0)); +} + +int nfct_dump_conntrack_table_zero(struct nfct_handle *cth) +{ + return(__nfct_dump_conntrack_table(cth, 1)); +} + +int nfct_event_conntrack(struct nfct_handle *cth) +{ + struct nfct_msg_handler hnew = { + .type = IPCTNL_MSG_CT_NEW, + .handler = nfct_event_handler + }; + struct nfct_msg_handler hdestroy = { + .type = IPCTNL_MSG_CT_DELETE, + .handler = nfct_event_handler + }; + int ret; + + nfct_register_handler(cth, &hnew); + nfct_register_handler(cth, &hdestroy); + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return 0; +} + +void nfct_register_proto(struct nfct_proto *h) +{ + if (strcmp(h->version, LIBNETFILTER_CONNTRACK_VERSION) != 0) { + fprintf(stderr, "plugin `%s': version %s (I'm %s)\n", + h->name, h->version, LIBNETFILTER_CONNTRACK_VERSION); + exit(1); + } + list_add(&h->head, &proto_list); +} + +void nfct_unregister_proto(struct nfct_proto *h) +{ + list_del(&h->head); +} + +int nfct_dump_expect_list(struct nfct_handle *cth) +{ + struct nfct_msg_handler h = { + .type = IPCTNL_MSG_EXP_NEW, + .handler = nfct_expect_netlink_handler + }; + int ret; + struct nfnlhdr req; + + nfct_register_handler(cth, &h); + + nfnl_fill_hdr(&cth->nfnlh, &req.nlh, 0, AF_INET, 0, + IPCTNL_MSG_EXP_GET, NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST); + + if (nfnl_send(&cth->nfnlh, &req.nlh) < 0) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +int nfct_flush_conntrack_table(struct nfct_handle *cth) +{ + int ret; + struct nfnlhdr *req; + char buf[sizeof(*req)]; + + memset(&buf, 0, sizeof(buf)); + req = (void *) &buf; + + nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf, + 0, AF_INET, 0, IPCTNL_MSG_CT_DELETE, + NLM_F_REQUEST|NLM_F_ACK); + + if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0 ) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +int nfct_get_expectation(struct nfct_handle *cth,struct nfct_tuple *tuple) +{ + struct nfct_msg_handler h = { + .type = IPCTNL_MSG_EXP_NEW, + .handler = nfct_expect_netlink_handler + }; + int ret; + struct nfnlhdr *req; + char buf[NFCT_BUFSIZE]; + + memset(&buf, 0, sizeof(buf)); + req = (void *) &buf; + + nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, AF_INET, 0, IPCTNL_MSG_EXP_GET, + NLM_F_REQUEST|NLM_F_ACK); + + nfct_register_handler(cth, &h); + nfct_build_tuple(req, sizeof(buf), tuple, CTA_EXPECT_MASTER); + + if (nfnl_send(&cth->nfnlh, &req->nlh) < 0) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +int nfct_create_expectation(struct nfct_handle *cth,struct nfct_tuple *master, + struct nfct_tuple *tuple, + struct nfct_tuple *mask, + unsigned long timeout) +{ + int ret; + struct nfnlhdr *req; + char buf[NFCT_BUFSIZE]; + req = (void *) &buf; + + memset(&buf, 0, sizeof(buf)); + + nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, AF_INET, 0, IPCTNL_MSG_EXP_NEW, + NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK); + + nfct_build_tuple(req, sizeof(buf), master, CTA_EXPECT_MASTER); + nfct_build_tuple(req, sizeof(buf), tuple, CTA_EXPECT_TUPLE); + nfct_build_tuple(req, sizeof(buf), mask, CTA_EXPECT_MASK); + + if (nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_EXPECT_TIMEOUT, &timeout, + sizeof(timeout)) < 0) + return -1; + + if (nfnl_send(&cth->nfnlh, &req->nlh) < 0 ) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +int nfct_delete_expectation(struct nfct_handle *cth,struct nfct_tuple *tuple) +{ + int ret; + struct nfnlhdr *req; + char buf[NFCT_BUFSIZE]; + + memset(&buf, 0, sizeof(buf)); + req = (void *) &buf; + + nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, AF_INET, + 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 (nfnl_send(&cth->nfnlh, &req->nlh) < 0) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +int nfct_event_expectation(struct nfct_handle *cth) +{ + struct nfct_msg_handler hnew = { + .type = IPCTNL_MSG_EXP_NEW, + .handler = nfct_expect_netlink_handler + }; + struct nfct_msg_handler hdestroy = { + .type = IPCTNL_MSG_EXP_DELETE, + .handler = nfct_expect_netlink_handler + }; + int ret; + + nfct_register_handler(cth, &hnew); + nfct_register_handler(cth, &hdestroy); + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +int nfct_flush_expectation_table(struct nfct_handle *cth) +{ + int ret; + struct nfnlhdr *req; + char buf[sizeof(*req)]; + + memset(&buf, 0, sizeof(buf)); + req = (void *) &buf; + + nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf, + 0, AF_INET, 0, IPCTNL_MSG_EXP_DELETE, + NLM_F_REQUEST|NLM_F_ACK); + + if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0 ) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} -- cgit v1.2.3